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 465 2011-11-02 20:34:26Z 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 => "ThinkSec AS and Network Associates Laboratories, the
85 Security Research Division of Network Associates, Inc.\\& under
86 DARPA/SPAWAR contract N66001-01-C-8035
88 as part of the DARPA CHATS research program.",
89 DES => ".An Dag-Erling Sm\\(/orgrav Aq des\@FreeBSD.org .",
93 PAM_SUCCESS => "Success",
94 PAM_OPEN_ERR => "Failed to load module",
95 PAM_SYMBOL_ERR => "Invalid symbol",
96 PAM_SERVICE_ERR => "Error in service module",
97 PAM_SYSTEM_ERR => "System error",
98 PAM_BUF_ERR => "Memory buffer error",
99 PAM_CONV_ERR => "Conversation failure",
100 PAM_PERM_DENIED => "Permission denied",
101 PAM_MAXTRIES => "Maximum number of tries exceeded",
102 PAM_AUTH_ERR => "Authentication error",
103 PAM_NEW_AUTHTOK_REQD => "New authentication token required",
104 PAM_CRED_INSUFFICIENT => "Insufficient credentials",
105 PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable",
106 PAM_USER_UNKNOWN => "Unknown user",
107 PAM_CRED_UNAVAIL => "Failed to retrieve user credentials",
108 PAM_CRED_EXPIRED => "User credentials have expired",
109 PAM_CRED_ERR => "Failed to set user credentials",
110 PAM_ACCT_EXPIRED => "User account has expired",
111 PAM_AUTHTOK_EXPIRED => "Password has expired",
112 PAM_SESSION_ERR => "Session failure",
113 PAM_AUTHTOK_ERR => "Authentication token failure",
114 PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token",
115 PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy",
116 PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled",
117 PAM_NO_MODULE_DATA => "Module data not found",
118 PAM_IGNORE => "Ignore this module",
119 PAM_ABORT => "General failure",
120 PAM_TRY_AGAIN => "Try again",
121 PAM_MODULE_UNKNOWN => "Unknown module type",
122 PAM_DOMAIN_UNKNOWN => "Unknown authentication domain",
125 sub parse_source($) {
143 if ($fn !~ m,\.c$,) {
144 warn("$fn: not C source, ignoring\n");
148 open(FILE, "<", "$fn")
149 or die("$fn: open(): $!\n");
150 $source = join('', <FILE>);
154 if ($source =~ m/^ \* NOPARSE\s*$/m);
156 $author = 'THINKSEC';
157 if ($source =~ s/^ \* AUTHOR\s+(.*?)\s*$//m) {
162 $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
163 if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
164 warn("$fn: can't find $func\n");
167 ($descr, $type, $args) = ($1, $2, $3);
168 $descr =~ s,^([A-Z][a-z]),lc($1),e;
169 $descr =~ s,[\.\s]*$,,;
170 while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
173 $args =~ s/,\s+/, /gs;
180 if ($type eq "int") {
181 foreach (split("\n", $source)) {
182 next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
185 ++$xref{3}->{'pam_strerror'};
189 # extract names of regular arguments
190 $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
191 # extract names of function pointer arguments
192 $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
193 # escape metacharacters (there shouldn't be any, but...)
194 $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
195 # separate argument names with |
196 $argnames =~ s/\" \"/|/g;
197 # and surround with ()
198 $argnames =~ s/^\"(.*)\"$/($1)/;
199 # $argnames is now a regexp that matches argument names
200 $inliteral = $inlist = $intaglist = 0;
201 foreach (split("\n", $source)) {
203 if (!defined($man)) {
209 last if (m/^ \*\/$/);
213 # paragraph separator
214 if ($man ne "" && $man !~ m/\.Pp\n$/s) {
217 } elsif ($inlist || $intaglist) {
218 $man .= ".El\n.Pp\n";
219 $inlist = $intaglist = 0;
226 if (m/^>(\w+)(\s+\d)?$/) {
227 # "see also" cross-reference
228 my ($page, $sect) = ($1, $2 ? int($2) : 3);
229 ++$xref{$sect}->{$page};
233 # item in bullet list
239 $man .= ".El\n.Pp\n";
243 $man =~ s/\.Pp\n$//s;
244 $man .= ".Bl -bullet\n";
249 } elsif (s/^\s+(\S+):\s*/.It $1/) {
256 $man .= ".El\n.Pp\n";
260 $man =~ s/\.Pp\n$//s;
261 $man .= ".Bl -tag -width 18n\n";
264 s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
267 } elsif (($inlist || $intaglist) && m/^\S/) {
268 # regular text after list
269 $man .= ".El\n.Pp\n";
270 $inlist = $intaglist = 0;
271 } elsif ($inliteral && m/^\S/) {
272 # regular text after literal section
275 } elsif ($inliteral) {
276 # additional text within literal section
279 } elsif ($inlist || $intaglist) {
280 # additional text within list
283 # new literal section
284 $man .= ".Bd -literal\n";
289 s/\s*=$func\b\s*/\n.Nm\n/gs;
290 s/\s*=$argnames\b\s*/\n.Fa $1\n/gs;
291 s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
292 s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
293 s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
294 while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
297 s/\s*\"(?=\w)/\n.Do\n/gs;
298 s/\"(?!\w)\s*/\n.Dc\n/gs;
299 s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
300 s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
301 s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
305 if ($inlist || $intaglist) {
307 $inlist = $intaglist = 0;
313 $man =~ s/\%/\\&\%/gs;
314 $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([\.,:;-]\S*)\s*/$1 $2\n/gs;
315 $man =~ s/\s*$/\n/gm;
318 $man =~ s/\n\n\./\n\./gs;
321 $man = "No description available.";
324 $FUNCTIONS{$func} = {
332 'errors' => \@errors,
335 if ($source =~ m/^ \* NODOC\s*$/m) {
336 $FUNCTIONS{$func}->{'nodoc'} = 1;
338 if ($source !~ m/^ \* XSSO \d/m) {
339 $FUNCTIONS{$func}->{'openpam'} = 1;
341 expand_errors($FUNCTIONS{$func});
342 return $FUNCTIONS{$func};
345 sub expand_errors($);
346 sub expand_errors($) {
347 my $func = shift; # Ref to function hash
353 if (defined($func->{'recursed'})) {
354 warn("$func->{'name'}(): loop in error spec\n");
357 $func->{'recursed'} = 1;
359 foreach (@{$func->{'errors'}}) {
360 if (m/^(PAM_[A-Z_]+)$/) {
361 if (!defined($PAMERR{$1})) {
362 warn("$func->{'name'}(): unrecognized error: $1\n");
366 } elsif (m/^!(PAM_[A-Z_]+)$/) {
367 # treat negations separately
368 } elsif (m/^=([a-z_]+)$/) {
370 if (!defined($FUNCTIONS{$ref})) {
371 $fn = $func->{'source'};
372 $fn =~ s/$func->{'name'}/$ref/;
375 if (!defined($FUNCTIONS{$ref})) {
376 warn("$func->{'name'}(): reference to unknown $ref()\n");
379 foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
383 warn("$func->{'name'}(): invalid error specification: $_\n");
386 foreach (@{$func->{'errors'}}) {
387 if (m/^!(PAM_[A-Z_]+)$/) {
391 delete($func->{'recursed'});
392 $func->{'errors'} = [ sort(keys(%errors)) ];
395 sub dictionary_order($$) {
398 $a =~ s/[^[:alpha:]]//g;
399 $b =~ s/[^[:alpha:]]//g;
404 my $xref = shift; # References
408 foreach my $sect (sort(keys(%{$xref}))) {
409 foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
410 push(@refs, "$page $sect");
413 while ($_ = shift(@refs)) {
415 (@refs ? " ,\n" : "\n");
421 my $func = shift; # Ref to function hash
427 return if defined($func->{'nodoc'});
431 .Dt " . uc($func->{'name'}) . " 3
440 .In security/pam_appl.h
442 if ($func->{'name'} =~ m/_sm_/) {
443 $mdoc .= ".In security/pam_modules.h\n"
445 if ($func->{'name'} =~ m/openpam/) {
446 $mdoc .= ".In security/openpam.h\n"
448 $mdoc .= ".Ft \"$func->{'type'}\"
449 .Fn $func->{'name'} $func->{'args'}
453 if ($func->{'type'} eq "int") {
454 $mdoc .= ".Sh RETURN VALUES
457 function returns one of the following values:
460 my @errors = @{$func->{'errors'}};
461 warn("$func->{'name'}(): no error specification\n")
464 $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
468 if ($func->{'type'} =~ m/\*$/) {
469 $mdoc .= ".Sh RETURN VALUES
478 $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
479 $mdoc .= ".Sh STANDARDS\n";
480 if ($func->{'openpam'}) {
483 function is an OpenPAM extension.
487 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
492 $mdoc .= ".Sh AUTHORS
495 function and this manual page were developed for the
497 Project by\n" . $AUTHORS{$func->{'author'} // 'THINKSEC_DARPA'} . "\n";
498 $fn = "$func->{'name'}.3";
499 if (open(FILE, ">", $fn)) {
503 warn("$fn: open(): $!\n");
508 my $fn = shift; # File name
513 open(FILE, "<", "$fn")
514 or die("$fn: open(): $!\n");
516 if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
517 $func{'Nm'} = $func{'Nm'} || $1;
518 } elsif (m/^\.Ft (\S.*?)\s*$/) {
519 $func{'Ft'} = $func{'Ft'} || $1;
520 } elsif (m/^\.Fn (\S.*?)\s*$/) {
521 $func{'Fn'} = $func{'Fn'} || $1;
526 $FUNCTIONS{$func{'Nm'}} = \%func;
528 warn("No function found\n");
533 my $page = shift; # Which page to produce
540 open(FILE, ">", "$page.3")
541 or die("$page.3: $!\n");
545 print FILE "$COPYRIGHT
551 my @funcs = sort(keys(%FUNCTIONS));
552 while ($func = shift(@funcs)) {
553 print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
558 print FILE ".Nd Pluggable Authentication Modules Library
562 if ($page eq 'pam') {
563 print FILE ".In security/pam_appl.h\n";
565 print FILE ".In security/openpam.h\n";
567 foreach $func (sort(keys(%FUNCTIONS))) {
568 print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
569 print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
572 if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
573 ++$xref{int($2)}->{$1};
578 if ($page eq 'pam') {
579 print FILE ".Sh RETURN VALUES
580 The following return codes are defined by
581 .In security/pam_constants.h :
584 foreach (sort(keys(%PAMERR))) {
585 print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
589 print FILE ".Sh SEE ALSO
591 if ($page eq 'pam') {
592 ++$xref{3}->{'openpam'};
594 foreach $func (keys(%FUNCTIONS)) {
597 print FILE genxref(\%xref);
598 print FILE ".Sh STANDARDS
600 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
604 The OpenPAM library and this manual page were developed for the
606 Project by ThinkSec AS and Network Associates Laboratories, the
607 Security Research Division of Network Associates, Inc.\\& under
608 DARPA/SPAWAR contract N66001-01-C-8035
610 as part of the DARPA CHATS research program.
617 print(STDERR "usage: gendoc [-op] source [...]\n");
625 unless (@ARGV && getopts("op", \%opts));
626 setlocale(LC_ALL, "en_US.UTF-8");
627 $TODAY = strftime("%B %e, %Y", localtime(time()));
629 if ($opts{'o'} || $opts{'p'}) {
630 foreach my $fn (@ARGV) {
633 gensummary('openpam')
638 foreach my $fn (@ARGV) {
639 my $func = parse_source($fn);