3 # Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4 # Copyright (c) 2004-2011 Dag-Erling Smørgrav
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
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
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
36 # $Id: gendoc.pl 599 2012-04-14 15:06:41Z des $
43 use POSIX qw(locale_h strftime);
44 use vars qw($COPYRIGHT %AUTHORS $TODAY %FUNCTIONS %PAMERR);
47 .\\\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
48 .\\\" Copyright (c) 2004-2011 Dag-Erling Smørgrav
49 .\\\" All rights reserved.
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.
56 .\\\" Redistribution and use in source and binary forms, with or without
57 .\\\" modification, are permitted provided that the following conditions
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
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
80 .\\\" \$" . "Id" . "\$
84 THINKSEC => "developed for the
86 Project by ThinkSec AS and Network Associates Laboratories, the
87 Security Research Division of Network Associates, Inc.\\& under
88 DARPA/SPAWAR contract N66001-01-C-8035
90 as part of the DARPA CHATS research program.",
92 .An Dag-Erling Sm\\(/orgrav Aq des\@des.no .",
96 PAM_SUCCESS => "Success",
97 PAM_OPEN_ERR => "Failed to load module",
98 PAM_SYMBOL_ERR => "Invalid symbol",
99 PAM_SERVICE_ERR => "Error in service module",
100 PAM_SYSTEM_ERR => "System error",
101 PAM_BUF_ERR => "Memory buffer error",
102 PAM_CONV_ERR => "Conversation failure",
103 PAM_PERM_DENIED => "Permission denied",
104 PAM_MAXTRIES => "Maximum number of tries exceeded",
105 PAM_AUTH_ERR => "Authentication error",
106 PAM_NEW_AUTHTOK_REQD => "New authentication token required",
107 PAM_CRED_INSUFFICIENT => "Insufficient credentials",
108 PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable",
109 PAM_USER_UNKNOWN => "Unknown user",
110 PAM_CRED_UNAVAIL => "Failed to retrieve user credentials",
111 PAM_CRED_EXPIRED => "User credentials have expired",
112 PAM_CRED_ERR => "Failed to set user credentials",
113 PAM_ACCT_EXPIRED => "User account has expired",
114 PAM_AUTHTOK_EXPIRED => "Password has expired",
115 PAM_SESSION_ERR => "Session failure",
116 PAM_AUTHTOK_ERR => "Authentication token failure",
117 PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token",
118 PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy",
119 PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled",
120 PAM_NO_MODULE_DATA => "Module data not found",
121 PAM_IGNORE => "Ignore this module",
122 PAM_ABORT => "General failure",
123 PAM_TRY_AGAIN => "Try again",
124 PAM_MODULE_UNKNOWN => "Unknown module type",
125 PAM_DOMAIN_UNKNOWN => "Unknown authentication domain",
128 sub parse_source($) {
149 if ($fn !~ m,\.c$,) {
150 warn("$fn: not C source, ignoring\n");
154 open(FILE, "<", "$fn")
155 or die("$fn: open(): $!\n");
156 $source = join('', <FILE>);
160 if ($source =~ m/^ \* NOPARSE\s*$/m);
162 $author = 'THINKSEC';
163 if ($source =~ s/^ \* AUTHOR\s+(\w*)\s*$//m) {
167 if ($source =~ s/^ \* DEPRECATED\s*(\w*)\s*$//m) {
168 $deprecated = $1 // 0;
171 if ($source =~ s/^ \* EXPERIMENTAL\s*$//m) {
176 $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
177 if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
178 warn("$fn: can't find $func\n");
181 ($descr, $type, $args) = ($1, $2, $3);
182 $descr =~ s,^([A-Z][a-z]),lc($1),e;
183 $descr =~ s,[\.\s]*$,,;
184 while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
187 $args =~ s/,\s+/, /gs;
194 if ($type eq "int") {
195 foreach (split("\n", $source)) {
196 next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
199 ++$xref{3}->{'pam_strerror'};
203 # extract names of regular arguments
204 $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
205 # extract names of function pointer arguments
206 $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
207 # escape metacharacters (there shouldn't be any, but...)
208 $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
209 # separate argument names with |
210 $argnames =~ s/\" \"/|/g;
211 # and surround with ()
212 $argnames =~ s/^\"(.*)\"$/$1/;
213 # $argnames is now a regexp that matches argument names
214 $inliteral = $inlist = $intaglist = 0;
215 foreach (split("\n", $source)) {
217 if (!defined($man)) {
223 last if (m/^ \*\/$/);
227 # paragraph separator
228 if ($inlist || $intaglist) {
229 # either a blank line between list items, or a blank
230 # line after the final list item. The latter case
231 # will be handled further down.
234 if ($man =~ m/\n\.Sh [^\n]+\n$/s) {
235 # a blank line after a section header
238 if ($man ne "" && $man !~ m/\.Pp\n$/s) {
247 if (m/^>(\w+)(\s+\d)?$/) {
248 # "see also" cross-reference
249 my ($page, $sect) = ($1, $2 ? int($2) : 3);
250 ++$xref{$sect}->{$page};
253 if (s/^([A-Z][0-9A-Z -]+)$/.Sh $1/) {
254 if ($1 eq "RETURN VALUES") {
257 $man =~ s/\n\.Pp$/\n/s;
262 # item in bullet list
268 $man .= ".El\n.Pp\n";
272 $man =~ s/\.Pp\n$//s;
273 $man .= ".Bl -bullet\n";
278 } elsif (s/^\s+(\S+):\s*/.It $1/) {
285 $man .= ".El\n.Pp\n";
289 $man =~ s/\.Pp\n$//s;
290 $man .= ".Bl -tag -width 18n\n";
293 s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
296 } elsif (($inlist || $intaglist) && m/^\S/) {
297 # regular text after list
298 $man .= ".El\n.Pp\n";
299 $inlist = $intaglist = 0;
300 } elsif ($inliteral && m/^\S/) {
301 # regular text after literal section
304 } elsif ($inliteral) {
305 # additional text within literal section
308 } elsif ($inlist || $intaglist) {
309 # additional text within list
312 # new literal section
313 $man .= ".Bd -literal\n";
318 s/\s*=($func)\b\s*/\n.Fn $1\n/gs;
319 s/\s*=($argnames)\b\s*/\n.Fa $1\n/gs;
320 s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
321 s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
322 s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
323 s/\s*=!([a-z_]+)\b\s*/\n.Xr $1 3\n/gs;
324 while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
327 s/\s*\"(?=\w)/\n.Do\n/gs;
328 s/\"(?!\w)\s*/\n.Dc\n/gs;
329 s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
330 s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
331 s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
335 if ($inlist || $intaglist) {
337 $inlist = $intaglist = 0;
343 $man =~ s/\%/\\&\%/gs;
344 $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([.,:;-])\s+/$1 $2\n/gs;
345 $man =~ s/\s*$/\n/gm;
348 $man =~ s/\n\n\./\n\./gs;
351 $man = "No description available.";
354 $FUNCTIONS{$func} = {
362 'errors' => \@errors,
364 'customrv' => $customrv,
365 'deprecated' => $deprecated,
366 'experimental' => $experimental,
368 if ($source =~ m/^ \* NODOC\s*$/m) {
369 $FUNCTIONS{$func}->{'nodoc'} = 1;
371 if ($source !~ m/^ \* XSSO \d/m) {
372 $FUNCTIONS{$func}->{'openpam'} = 1;
374 expand_errors($FUNCTIONS{$func});
375 return $FUNCTIONS{$func};
378 sub expand_errors($);
379 sub expand_errors($) {
380 my $func = shift; # Ref to function hash
386 if (defined($func->{'recursed'})) {
387 warn("$func->{'name'}(): loop in error spec\n");
390 $func->{'recursed'} = 1;
392 foreach (@{$func->{'errors'}}) {
393 if (m/^(PAM_[A-Z_]+)$/) {
394 if (!defined($PAMERR{$1})) {
395 warn("$func->{'name'}(): unrecognized error: $1\n");
399 } elsif (m/^!(PAM_[A-Z_]+)$/) {
400 # treat negations separately
401 } elsif (m/^=([a-z_]+)$/) {
403 if (!defined($FUNCTIONS{$ref})) {
404 $fn = $func->{'source'};
405 $fn =~ s/$func->{'name'}/$ref/;
408 if (!defined($FUNCTIONS{$ref})) {
409 warn("$func->{'name'}(): reference to unknown $ref()\n");
412 foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
416 warn("$func->{'name'}(): invalid error specification: $_\n");
419 foreach (@{$func->{'errors'}}) {
420 if (m/^!(PAM_[A-Z_]+)$/) {
424 delete($func->{'recursed'});
425 $func->{'errors'} = [ sort(keys(%errors)) ];
428 sub dictionary_order($$) {
431 $a =~ s/[^[:alpha:]]//g;
432 $b =~ s/[^[:alpha:]]//g;
437 my $xref = shift; # References
441 foreach my $sect (sort(keys(%{$xref}))) {
442 foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
443 push(@refs, "$page $sect");
446 while ($_ = shift(@refs)) {
448 (@refs ? " ,\n" : "\n");
454 my $func = shift; # Ref to function hash
460 return if defined($func->{'nodoc'});
464 .Dt " . uc($func->{'name'}) . " 3
474 if ($func->{'args'} =~ m/\bFILE \*\b/) {
475 $mdoc .= ".In stdio.h\n";
477 $mdoc .= ".In security/pam_appl.h
479 if ($func->{'name'} =~ m/_sm_/) {
480 $mdoc .= ".In security/pam_modules.h\n";
482 if ($func->{'name'} =~ m/openpam/) {
483 $mdoc .= ".In security/openpam.h\n";
485 $mdoc .= ".Ft \"$func->{'type'}\"
486 .Fn $func->{'name'} $func->{'args'}
489 if (defined($func->{'deprecated'})) {
490 $mdoc .= ".Bf Sy\n" .
491 "This function is deprecated and may be removed " .
492 "in a future release without further warning.\n";
493 if ($func->{'deprecated'}) {
494 $mdoc .= "The\n.Fn $func->{'deprecated'}\nfunction " .
495 "may be used to achieve similar results.\n";
497 $mdoc .= ".Ef\n.Pp\n";
499 if ($func->{'experimental'}) {
500 $mdoc .= ".Bf Sy\n" .
501 "This function is experimental and may be modified or removed " .
502 "in a future release without further warning.\n";
503 $mdoc .= ".Ef\n.Pp\n";
505 $mdoc .= "$func->{'man'}\n";
506 my @errors = @{$func->{'errors'}};
507 if ($func->{'customrv'}) {
509 } elsif ($func->{'type'} eq "int" && @errors) {
510 $mdoc .= ".Sh RETURN VALUES
513 function returns one of the following values:
517 $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
520 } elsif ($func->{'type'} eq "int") {
521 $mdoc .= ".Sh RETURN VALUES
524 function returns 0 on success and -1 on failure.
526 } elsif ($func->{'type'} =~ m/\*$/) {
527 $mdoc .= ".Sh RETURN VALUES
534 } elsif ($func->{'type'} ne "void") {
535 warn("$func->{'name'}(): no error specification\n");
537 $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
538 $mdoc .= ".Sh STANDARDS\n";
539 if ($func->{'openpam'}) {
542 function is an OpenPAM extension.
546 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
551 $mdoc .= ".Sh AUTHORS
554 function and this manual page were\n";
555 $mdoc .= $AUTHORS{$func->{'author'} // 'THINKSEC_DARPA'} . "\n";
556 $fn = "$func->{'name'}.3";
557 if (open(FILE, ">", $fn)) {
561 warn("$fn: open(): $!\n");
566 my $fn = shift; # File name
571 open(FILE, "<", "$fn")
572 or die("$fn: open(): $!\n");
574 if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
575 $func{'Nm'} = $func{'Nm'} || $1;
576 } elsif (m/^\.Ft (\S.*?)\s*$/) {
577 $func{'Ft'} = $func{'Ft'} || $1;
578 } elsif (m/^\.Fn (\S.*?)\s*$/) {
579 $func{'Fn'} = $func{'Fn'} || $1;
584 $FUNCTIONS{$func{'Nm'}} = \%func;
586 warn("No function found\n");
591 my $page = shift; # Which page to produce
598 open(FILE, ">", "$page.3")
599 or die("$page.3: $!\n");
603 print FILE "$COPYRIGHT
609 my @funcs = sort(keys(%FUNCTIONS));
610 while ($func = shift(@funcs)) {
611 print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
616 print FILE ".Nd Pluggable Authentication Modules Library
620 if ($page eq 'pam') {
621 print FILE ".In security/pam_appl.h\n";
623 print FILE ".In security/openpam.h\n";
625 foreach $func (sort(keys(%FUNCTIONS))) {
626 print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
627 print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
630 if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
631 ++$xref{int($2)}->{$1};
636 if ($page eq 'pam') {
637 print FILE ".Sh RETURN VALUES
638 The following return codes are defined by
639 .In security/pam_constants.h :
642 foreach (sort(keys(%PAMERR))) {
643 print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
647 print FILE ".Sh SEE ALSO
649 if ($page eq 'pam') {
650 ++$xref{3}->{'openpam'};
652 foreach $func (keys(%FUNCTIONS)) {
655 print FILE genxref(\%xref);
656 print FILE ".Sh STANDARDS
658 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
662 The OpenPAM library and this manual page were developed for the
664 Project by ThinkSec AS and Network Associates Laboratories, the
665 Security Research Division of Network Associates, Inc.\\& under
666 DARPA/SPAWAR contract N66001-01-C-8035
668 as part of the DARPA CHATS research program.
670 The OpenPAM library is maintained by
671 .An Dag-Erling Sm\\(/orgrav Aq des\@des.no .
678 print(STDERR "usage: gendoc [-op] source [...]\n");
686 unless (@ARGV && getopts("op", \%opts));
687 setlocale(LC_ALL, "en_US.UTF-8");
688 $TODAY = strftime("%B %e, %Y", localtime(time()));
690 if ($opts{'o'} || $opts{'p'}) {
691 foreach my $fn (@ARGV) {
694 gensummary('openpam')
699 foreach my $fn (@ARGV) {
700 my $func = parse_source($fn);