Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / openpam / misc / gendoc.pl
blob683d431ce7bd4e47c3472d6607c031845624363d
1 #!/usr/bin/perl -w
2 #-
3 # Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4 # Copyright (c) 2004-2007 Dag-Erling Smørgrav
5 # All rights reserved.
7 # This software was developed for the FreeBSD Project by ThinkSec AS and
8 # Network Associates Laboratories, the Security Research Division of
9 # Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
10 # ("CBOSS"), as part of the DARPA CHATS research program.
12 # Redistribution and use in source and binary forms, with or without
13 # modification, are permitted provided that the following conditions
14 # are met:
15 # 1. Redistributions of source code must retain the above copyright
16 # notice, this list of conditions and the following disclaimer.
17 # 2. Redistributions in binary form must reproduce the above copyright
18 # notice, this list of conditions and the following disclaimer in the
19 # documentation and/or other materials provided with the distribution.
20 # 3. The name of the author may not be used to endorse or promote
21 # products derived from this software without specific prior written
22 # permission.
24 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 # SUCH DAMAGE.
36 # $Id: gendoc.pl,v 1.5 2008/01/27 01:23:01 christos Exp $
39 use strict;
40 use locale;
41 use Fcntl;
42 use Getopt::Std;
43 use POSIX qw(locale_h strftime);
44 use vars qw($COPYRIGHT $TODAY %FUNCTIONS %PAMERR);
46 $COPYRIGHT = ".\\\"-
47 .\\\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
48 .\\\" Copyright (c) 2004-2007 Dag-Erling Smørgrav
49 .\\\" All rights reserved.
50 .\\\"
51 .\\\" This software was developed for the FreeBSD Project by ThinkSec AS and
52 .\\\" Network Associates Laboratories, the Security Research Division of
53 .\\\" Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
54 .\\\" (\"CBOSS\"), as part of the DARPA CHATS research program.
55 .\\\"
56 .\\\" Redistribution and use in source and binary forms, with or without
57 .\\\" modification, are permitted provided that the following conditions
58 .\\\" are met:
59 .\\\" 1. Redistributions of source code must retain the above copyright
60 .\\\" notice, this list of conditions and the following disclaimer.
61 .\\\" 2. Redistributions in binary form must reproduce the above copyright
62 .\\\" notice, this list of conditions and the following disclaimer in the
63 .\\\" documentation and/or other materials provided with the distribution.
64 .\\\" 3. The name of the author may not be used to endorse or promote
65 .\\\" products derived from this software without specific prior written
66 .\\\" permission.
67 .\\\"
68 .\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
69 .\\\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70 .\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71 .\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
72 .\\\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73 .\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74 .\\\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75 .\\\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76 .\\\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77 .\\\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78 .\\\" SUCH DAMAGE.
79 .\\\"
80 .\\\" \$" . "P4" . "\$
81 .\\\"";
83 %PAMERR = (
84 PAM_SUCCESS => "Success",
85 PAM_OPEN_ERR => "Failed to load module",
86 PAM_SYMBOL_ERR => "Invalid symbol",
87 PAM_SERVICE_ERR => "Error in service module",
88 PAM_SYSTEM_ERR => "System error",
89 PAM_BUF_ERR => "Memory buffer error",
90 PAM_CONV_ERR => "Conversation failure",
91 PAM_PERM_DENIED => "Permission denied",
92 PAM_MAXTRIES => "Maximum number of tries exceeded",
93 PAM_AUTH_ERR => "Authentication error",
94 PAM_NEW_AUTHTOK_REQD => "New authentication token required",
95 PAM_CRED_INSUFFICIENT => "Insufficient credentials",
96 PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable",
97 PAM_USER_UNKNOWN => "Unknown user",
98 PAM_CRED_UNAVAIL => "Failed to retrieve user credentials",
99 PAM_CRED_EXPIRED => "User credentials have expired",
100 PAM_CRED_ERR => "Failed to set user credentials",
101 PAM_ACCT_EXPIRED => "User account has expired",
102 PAM_AUTHTOK_EXPIRED => "Password has expired",
103 PAM_SESSION_ERR => "Session failure",
104 PAM_AUTHTOK_ERR => "Authentication token failure",
105 PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token",
106 PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy",
107 PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled",
108 PAM_NO_MODULE_DATA => "Module data not found",
109 PAM_IGNORE => "Ignore this module",
110 PAM_ABORT => "General failure",
111 PAM_TRY_AGAIN => "Try again",
112 PAM_MODULE_UNKNOWN => "Unknown module type",
113 PAM_DOMAIN_UNKNOWN => "Unknown authentication domain",
116 sub parse_source($) {
117 my $fn = shift;
119 local *FILE;
120 my $source;
121 my $func;
122 my $descr;
123 my $type;
124 my $args;
125 my $argnames;
126 my $man;
127 my $inlist;
128 my $inliteral;
129 my %xref;
130 my @errors;
132 if ($fn !~ m,\.c$,) {
133 warn("$fn: not C source, ignoring\n");
134 return undef;
137 sysopen(FILE, $fn, O_RDONLY)
138 or die("$fn: open(): $!\n");
139 $source = join('', <FILE>);
140 close(FILE);
142 return undef
143 if ($source =~ m/^ \* NOPARSE\s*$/m);
145 $func = $fn;
146 $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
147 if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
148 warn("$fn: can't find $func\n");
149 return undef;
151 ($descr, $type, $args) = ($1, $2, $3);
152 $descr =~ s,^([A-Z][a-z]),lc($1),e;
153 $descr =~ s,[\.\s]*$,,;
154 while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
155 # nothing
157 $args =~ s/,\s+/, /gs;
158 $args = "\"$args\"";
160 %xref = (
161 3 => { 'pam' => 1 },
164 if ($type eq "int") {
165 foreach (split("\n", $source)) {
166 next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
167 push(@errors, $1);
169 ++$xref{3}->{'pam_strerror'};
172 $argnames = $args;
173 # extract names of regular arguments
174 $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
175 # extract names of function pointer arguments
176 $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
177 # escape metacharacters (there shouldn't be any, but...)
178 $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
179 # separate argument names with |
180 $argnames =~ s/\" \"/|/g;
181 # and surround with ()
182 $argnames =~ s/^\"(.*)\"$/($1)/;
183 # $argnames is now a regexp that matches argument names
184 $inliteral = $inlist = 0;
185 foreach (split("\n", $source)) {
186 s/\s*$//;
187 if (!defined($man)) {
188 if (m/^\/\*\*$/) {
189 $man = "";
191 next;
193 last if (m/^ \*\/$/);
194 s/^ \* ?//;
195 s/\\(.)/$1/gs;
196 if (m/^$/) {
197 if ($man ne "" && $man !~ m/\.Pp\n$/s) {
198 if ($inliteral) {
199 $man .= "\0\n";
200 } elsif ($inlist) {
201 $man .= ".El\n.Pp\n";
202 $inlist = 0;
203 } else {
204 $man .= ".Pp\n";
207 next;
209 if (m/^>(\w+)(\s+\d)?$/) {
210 my ($page, $sect) = ($1, $2 ? int($2) : 3);
211 ++$xref{$sect}->{$page};
212 next;
214 if (s/^\s+(=?\w+):\s*/.It $1/) {
215 if ($inliteral) {
216 $man .= ".Ed\n";
217 $inliteral = 0;
219 if (!$inlist) {
220 $man =~ s/\.Pp\n$//s;
221 $man .= ".Bl -tag -width 18n\n";
222 $inlist = 1;
224 s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
225 $man .= "$_\n";
226 next;
227 } elsif ($inlist && m/^\S/) {
228 $man .= ".El\n.Pp\n";
229 $inlist = 0;
230 } elsif ($inliteral && m/^\S/) {
231 $man .= ".Ed\n";
232 $inliteral = 0;
233 } elsif ($inliteral) {
234 $man .= "$_\n";
235 next;
236 } elsif ($inlist) {
237 s/^\s+//;
238 } elsif (m/^\s+/) {
239 $man .= ".Bd -literal\n";
240 $inliteral = 1;
241 $man .= "$_\n";
242 next;
244 s/\s*=$func\b\s*/\n.Nm\n/gs;
245 s/\s*=$argnames\b\s*/\n.Fa $1\n/gs;
246 s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
247 s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
248 s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
249 s/\s*=cleanup\s*/\n.Ar cleanup\n/gs;
250 while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
251 ++$xref{3}->{$1};
253 s/\s*\"(?=\w)/\n.Do\n/gs;
254 s/\"(?!\w)\s*/\n.Dc\n/gs;
255 s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
256 s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
257 s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
258 $man .= "$_\n";
260 if (defined($man)) {
261 if ($inlist) {
262 $man .= ".El\n";
264 if ($inliteral) {
265 $man .= ".Ed\n";
267 $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([\.,:;-]\S*)\s*/$1 $2\n/gs;
268 $man =~ s/\s*$/\n/gm;
269 $man =~ s/\n+/\n/gs;
270 $man =~ s/\0//gs;
271 $man =~ s/\n\n\./\n\./gs;
272 chomp($man);
273 } else {
274 $man = "No description available.";
277 $FUNCTIONS{$func} = {
278 'source' => $fn,
279 'name' => $func,
280 'descr' => $descr,
281 'type' => $type,
282 'args' => $args,
283 'man' => $man,
284 'xref' => \%xref,
285 'errors' => \@errors,
287 if ($source =~ m/^ \* NODOC\s*$/m) {
288 $FUNCTIONS{$func}->{'nodoc'} = 1;
290 if ($source !~ m/^ \* XSSO \d/m) {
291 $FUNCTIONS{$func}->{'openpam'} = 1;
293 expand_errors($FUNCTIONS{$func});
294 return $FUNCTIONS{$func};
297 sub expand_errors($);
298 sub expand_errors($) {
299 my $func = shift; # Ref to function hash
301 my %errors;
302 my $ref;
303 my $fn;
305 if (defined($func->{'recursed'})) {
306 warn("$func->{'name'}(): loop in error spec\n");
307 return qw();
309 $func->{'recursed'} = 1;
311 foreach (@{$func->{'errors'}}) {
312 if (m/^(PAM_[A-Z_]+)$/) {
313 if (!defined($PAMERR{$1})) {
314 warn("$func->{'name'}(): unrecognized error: $1\n");
315 next;
317 $errors{$1} = 1;
318 } elsif (m/^!(PAM_[A-Z_]+)$/) {
319 # treat negations separately
320 } elsif (m/^=([a-z_]+)$/) {
321 $ref = $1;
322 if (!defined($FUNCTIONS{$ref})) {
323 $fn = $func->{'source'};
324 $fn =~ s/$func->{'name'}/$ref/;
325 parse_source($fn);
327 if (!defined($FUNCTIONS{$ref})) {
328 warn("$func->{'name'}(): reference to unknown $ref()\n");
329 next;
331 foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
332 $errors{$_} = 1;
334 } else {
335 warn("$func->{'name'}(): invalid error specification: $_\n");
338 foreach (@{$func->{'errors'}}) {
339 if (m/^!(PAM_[A-Z_]+)$/) {
340 delete($errors{$1});
343 delete($func->{'recursed'});
344 $func->{'errors'} = [ sort(keys(%errors)) ];
347 sub dictionary_order($$) {
348 my ($a, $b) = @_;
350 $a =~ s/[^[:alpha:]]//g;
351 $b =~ s/[^[:alpha:]]//g;
352 $a cmp $b;
355 sub genxref($) {
356 my $xref = shift; # References
358 my $mdoc = '';
359 my @refs = ();
360 foreach my $sect (sort(keys(%{$xref}))) {
361 foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
362 push(@refs, "$page $sect");
365 while ($_ = shift(@refs)) {
366 $mdoc .= ".Xr $_" .
367 (@refs ? " ,\n" : "\n");
369 return $mdoc;
372 sub gendoc($) {
373 my $func = shift; # Ref to function hash
375 local *FILE;
376 my $mdoc;
377 my $fn;
379 return if defined($func->{'nodoc'});
381 $mdoc = ".\\\"\t\$".
382 "NetBSD\$
383 .\\\"
384 $COPYRIGHT
385 .Dd $TODAY
386 .Dt " . uc($func->{'name'}) . " 3
388 .Sh NAME
389 .Nm $func->{'name'}
390 .Nd $func->{'descr'}
391 .Sh LIBRARY
392 .Lb libpam
393 .Sh SYNOPSIS
394 .In sys/types.h
395 .In security/pam_appl.h
397 if ($func->{'name'} =~ m/_sm_/) {
398 $mdoc .= ".In security/pam_modules.h\n"
400 if ($func->{'name'} =~ m/openpam/) {
401 $mdoc .= ".In security/openpam.h\n"
403 $mdoc .= ".Ft \"$func->{'type'}\"
404 .Fn $func->{'name'} $func->{'args'}
405 .Sh DESCRIPTION
406 $func->{'man'}
408 if ($func->{'type'} eq "int") {
409 $mdoc .= ".Sh RETURN VALUES
412 function returns one of the following values:
413 .Bl -tag -width 18n
415 my @errors = @{$func->{'errors'}};
416 warn("$func->{'name'}(): no error specification\n")
417 unless(@errors);
418 foreach (@errors) {
419 $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
421 $mdoc .= ".El\n";
422 } else {
423 if ($func->{'type'} =~ m/\*$/) {
424 $mdoc .= ".Sh RETURN VALUES
427 function returns
428 .Dv NULL
429 on failure.
433 $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
434 $mdoc .= ".Sh STANDARDS\n";
435 if ($func->{'openpam'}) {
436 $mdoc .= "The
438 function is an OpenPAM extension.
440 } else {
441 $mdoc .= ".Rs
442 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
443 .%D \"June 1997\"
447 $mdoc .= ".Sh AUTHORS
450 function and this manual page were developed for the
452 Project by ThinkSec AS and Network Associates Laboratories, the
453 Security Research Division of Network Associates, Inc.\\& under
454 DARPA/SPAWAR contract N66001-01-C-8035
455 .Pq Dq CBOSS ,
456 as part of the DARPA CHATS research program.
459 $fn = "$func->{'name'}.3";
460 if (sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC)) {
461 print(FILE $mdoc);
462 close(FILE);
463 } else {
464 warn("$fn: open(): $!\n");
468 sub readproto($) {
469 my $fn = shift; # File name
471 local *FILE;
472 my %func;
474 sysopen(FILE, $fn, O_RDONLY)
475 or die("$fn: open(): $!\n");
476 while (<FILE>) {
477 if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
478 $func{'Nm'} = $func{'Nm'} || $1;
479 } elsif (m/^\.Ft (\S.*?)\s*$/) {
480 $func{'Ft'} = $func{'Ft'} || $1;
481 } elsif (m/^\.Fn (\S.*?)\s*$/) {
482 $func{'Fn'} = $func{'Fn'} || $1;
485 close(FILE);
486 if ($func{'Nm'}) {
487 $FUNCTIONS{$func{'Nm'}} = \%func;
488 } else {
489 warn("No function found\n");
493 sub gensummary($) {
494 my $page = shift; # Which page to produce
496 local *FILE;
497 my $upage;
498 my $func;
499 my %xref;
501 sysopen(FILE, "$page.3", O_RDWR|O_CREAT|O_TRUNC)
502 or die("$page.3: $!\n");
504 $upage = uc($page);
505 print FILE "$COPYRIGHT
506 .Dd $TODAY
507 .Dt $upage 3
509 .Sh NAME
511 my @funcs = sort(keys(%FUNCTIONS));
512 while ($func = shift(@funcs)) {
513 print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
514 print FILE " ,"
515 if (@funcs);
516 print FILE "\n";
518 print FILE ".Nd Pluggable Authentication Modules Library
519 .Sh LIBRARY
520 .Lb libpam
521 .Sh SYNOPSIS\n";
522 if ($page eq 'pam') {
523 print FILE ".In security/pam_appl.h\n";
524 } else {
525 print FILE ".In security/openpam.h\n";
527 foreach $func (sort(keys(%FUNCTIONS))) {
528 print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
529 print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
531 while (<STDIN>) {
532 if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
533 ++$xref{int($2)}->{$1};
535 print FILE $_;
538 if ($page eq 'pam') {
539 print FILE ".Sh RETURN VALUES
540 The following return codes are defined by
541 .In security/pam_constants.h :
542 .Bl -tag -width 18n
544 foreach (sort(keys(%PAMERR))) {
545 print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
547 print FILE ".El\n";
549 print FILE ".Sh SEE ALSO
551 if ($page eq 'pam') {
552 ++$xref{3}->{'openpam'};
554 foreach $func (keys(%FUNCTIONS)) {
555 ++$xref{3}->{$func};
557 print FILE genxref(\%xref);
558 print FILE ".Sh STANDARDS
560 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
561 .%D \"June 1997\"
563 .Sh AUTHORS
564 The OpenPAM library and this manual page were developed for the
566 Project by ThinkSec AS and Network Associates Laboratories, the
567 Security Research Division of Network Associates, Inc.\\& under
568 DARPA/SPAWAR contract N66001-01-C-8035
569 .Pq Dq CBOSS ,
570 as part of the DARPA CHATS research program.
572 close(FILE);
575 sub usage() {
577 print(STDERR "usage: gendoc [-s] source [...]\n");
578 exit(1);
581 MAIN:{
582 my %opts;
584 usage()
585 unless (@ARGV && getopts("op", \%opts));
586 setlocale(LC_ALL, "en_US.ISO8859-1");
587 $TODAY = strftime("%B %e, %Y", localtime(time()));
588 $TODAY =~ s,\s+, ,g;
589 if ($opts{'o'} || $opts{'p'}) {
590 foreach my $fn (@ARGV) {
591 readproto($fn);
593 gensummary('openpam')
594 if ($opts{'o'});
595 gensummary('pam')
596 if ($opts{'p'});
597 } else {
598 foreach my $fn (@ARGV) {
599 my $func = parse_source($fn);
600 gendoc($func)
601 if (defined($func));
604 exit(0);