]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/openpam/misc/gendoc.pl
Upgrade to OpenPAM Lycopsida.
[FreeBSD/FreeBSD.git] / contrib / openpam / misc / gendoc.pl
1 #!/usr/bin/perl -w
2 #-
3 # Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4 # Copyright (c) 2004-2011 Dag-Erling Smørgrav
5 # All rights reserved.
6 #
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.
11 #
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.
23 #
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.
35 #
36 # $Id: gendoc.pl 465 2011-11-02 20:34:26Z des $
37 #
38
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 %AUTHORS $TODAY %FUNCTIONS %PAMERR);
45
46 $COPYRIGHT = ".\\\"-
47 .\\\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
48 .\\\" Copyright (c) 2004-2011 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 .\\\" \$" . "Id" . "\$
81 .\\\"";
82
83 %AUTHORS = (
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
87 .Pq Dq CBOSS ,
88 as part of the DARPA CHATS research program.",
89     DES => ".An Dag-Erling Sm\\(/orgrav Aq des\@FreeBSD.org .",
90 );
91
92 %PAMERR = (
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",
123 );
124
125 sub parse_source($) {
126     my $fn = shift;
127
128     local *FILE;
129     my $source;
130     my $func;
131     my $descr;
132     my $type;
133     my $args;
134     my $argnames;
135     my $man;
136     my $inlist;
137     my $intaglist;
138     my $inliteral;
139     my %xref;
140     my @errors;
141     my $author;
142
143     if ($fn !~ m,\.c$,) {
144         warn("$fn: not C source, ignoring\n");
145         return undef;
146     }
147
148     open(FILE, "<", "$fn")
149         or die("$fn: open(): $!\n");
150     $source = join('', <FILE>);
151     close(FILE);
152
153     return undef
154         if ($source =~ m/^ \* NOPARSE\s*$/m);
155
156     $author = 'THINKSEC';
157     if ($source =~ s/^ \* AUTHOR\s+(.*?)\s*$//m) {
158         $author = $1;
159     }
160
161     $func = $fn;
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");
165         return undef;
166     }
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) {
171         # nothing
172     }
173     $args =~ s/,\s+/, /gs;
174     $args = "\"$args\"";
175
176     %xref = (
177         3 => { 'pam' => 1 },
178     );
179
180     if ($type eq "int") {
181         foreach (split("\n", $source)) {
182             next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
183             push(@errors, $1);
184         }
185         ++$xref{3}->{'pam_strerror'};
186     }
187
188     $argnames = $args;
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)) {
202         s/\s*$//;
203         if (!defined($man)) {
204             if (m/^\/\*\*$/) {
205                 $man = "";
206             }
207             next;
208         }
209         last if (m/^ \*\/$/);
210         s/^ \* ?//;
211         s/\\(.)/$1/gs;
212         if (m/^$/) {
213             # paragraph separator
214             if ($man ne "" && $man !~ m/\.Pp\n$/s) {
215                 if ($inliteral) {
216                     $man .= "\0\n";
217                 } elsif ($inlist || $intaglist) {
218                     $man .= ".El\n.Pp\n";
219                     $inlist = $intaglist = 0;
220                 } else {
221                     $man .= ".Pp\n";
222                 }
223             }
224             next;
225         }
226         if (m/^>(\w+)(\s+\d)?$/) {
227             # "see also" cross-reference
228             my ($page, $sect) = ($1, $2 ? int($2) : 3);
229             ++$xref{$sect}->{$page};
230             next;
231         }
232         if (s/^\s+-\s+//) {
233             # item in bullet list
234             if ($inliteral) {
235                 $man .= ".Ed\n";
236                 $inliteral = 0;
237             }
238             if ($intaglist) {
239                 $man .= ".El\n.Pp\n";
240                 $intaglist = 0;
241             }
242             if (!$inlist) {
243                 $man =~ s/\.Pp\n$//s;
244                 $man .= ".Bl -bullet\n";
245                 $inlist = 1;
246             }
247             $man .= ".It\n";
248             # fall through
249         } elsif (s/^\s+(\S+):\s*/.It $1/) {
250             # item in tag list
251             if ($inliteral) {
252                 $man .= ".Ed\n";
253                 $inliteral = 0;
254             }
255             if ($inlist) {
256                 $man .= ".El\n.Pp\n";
257                 $inlist = 0;
258             }
259             if (!$intaglist) {
260                 $man =~ s/\.Pp\n$//s;
261                 $man .= ".Bl -tag -width 18n\n";
262                 $intaglist = 1;
263             }
264             s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
265             $man .= "$_\n";
266             next;
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
273             $man .= ".Ed\n";
274             $inliteral = 0;
275         } elsif ($inliteral) {
276             # additional text within literal section
277             $man .= "$_\n";
278             next;
279         } elsif ($inlist || $intaglist) {
280             # additional text within list
281             s/^\s+//;
282         } elsif (m/^\s+/) {
283             # new literal section
284             $man .= ".Bd -literal\n";
285             $inliteral = 1;
286             $man .= "$_\n";
287             next;
288         }
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) {
295             ++$xref{3}->{$1};
296         }
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;
302         $man .= "$_\n";
303     }
304     if (defined($man)) {
305         if ($inlist || $intaglist) {
306             $man .= ".El\n";
307             $inlist = $intaglist = 0;
308         }
309         if ($inliteral) {
310             $man .= ".Ed\n";
311             $inliteral = 0;
312         }
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;
316         $man =~ s/\n+/\n/gs;
317         $man =~ s/\0//gs;
318         $man =~ s/\n\n\./\n\./gs;
319         chomp($man);
320     } else {
321         $man = "No description available.";
322     }
323
324     $FUNCTIONS{$func} = {
325         'source'        => $fn,
326         'name'          => $func,
327         'descr'         => $descr,
328         'type'          => $type,
329         'args'          => $args,
330         'man'           => $man,
331         'xref'          => \%xref,
332         'errors'        => \@errors,
333         'author'        => $author,
334     };
335     if ($source =~ m/^ \* NODOC\s*$/m) {
336         $FUNCTIONS{$func}->{'nodoc'} = 1;
337     }
338     if ($source !~ m/^ \* XSSO \d/m) {
339         $FUNCTIONS{$func}->{'openpam'} = 1;
340     }
341     expand_errors($FUNCTIONS{$func});
342     return $FUNCTIONS{$func};
343 }
344
345 sub expand_errors($);
346 sub expand_errors($) {
347     my $func = shift;           # Ref to function hash
348
349     my %errors;
350     my $ref;
351     my $fn;
352
353     if (defined($func->{'recursed'})) {
354         warn("$func->{'name'}(): loop in error spec\n");
355         return qw();
356     }
357     $func->{'recursed'} = 1;
358
359     foreach (@{$func->{'errors'}}) {
360         if (m/^(PAM_[A-Z_]+)$/) {
361             if (!defined($PAMERR{$1})) {
362                 warn("$func->{'name'}(): unrecognized error: $1\n");
363                 next;
364             }
365             $errors{$1} = 1;
366         } elsif (m/^!(PAM_[A-Z_]+)$/) {
367             # treat negations separately
368         } elsif (m/^=([a-z_]+)$/) {
369             $ref = $1;
370             if (!defined($FUNCTIONS{$ref})) {
371                 $fn = $func->{'source'};
372                 $fn =~ s/$func->{'name'}/$ref/;
373                 parse_source($fn);
374             }
375             if (!defined($FUNCTIONS{$ref})) {
376                 warn("$func->{'name'}(): reference to unknown $ref()\n");
377                 next;
378             }
379             foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
380                 $errors{$_} = 1;
381             }
382         } else {
383             warn("$func->{'name'}(): invalid error specification: $_\n");
384         }
385     }
386     foreach (@{$func->{'errors'}}) {
387         if (m/^!(PAM_[A-Z_]+)$/) {
388             delete($errors{$1});
389         }
390     }
391     delete($func->{'recursed'});
392     $func->{'errors'} = [ sort(keys(%errors)) ];
393 }
394
395 sub dictionary_order($$) {
396     my ($a, $b) = @_;
397
398     $a =~ s/[^[:alpha:]]//g;
399     $b =~ s/[^[:alpha:]]//g;
400     $a cmp $b;
401 }
402
403 sub genxref($) {
404     my $xref = shift;           # References
405
406     my $mdoc = '';
407     my @refs = ();
408     foreach my $sect (sort(keys(%{$xref}))) {
409         foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
410             push(@refs, "$page $sect");
411         }
412     }
413     while ($_ = shift(@refs)) {
414         $mdoc .= ".Xr $_" .
415             (@refs ? " ,\n" : "\n");
416     }
417     return $mdoc;
418 }
419
420 sub gendoc($) {
421     my $func = shift;           # Ref to function hash
422
423     local *FILE;
424     my $mdoc;
425     my $fn;
426
427     return if defined($func->{'nodoc'});
428
429     $mdoc = "$COPYRIGHT
430 .Dd $TODAY
431 .Dt " . uc($func->{'name'}) . " 3
432 .Os
433 .Sh NAME
434 .Nm $func->{'name'}
435 .Nd $func->{'descr'}
436 .Sh LIBRARY
437 .Lb libpam
438 .Sh SYNOPSIS
439 .In sys/types.h
440 .In security/pam_appl.h
441 ";
442     if ($func->{'name'} =~ m/_sm_/) {
443         $mdoc .= ".In security/pam_modules.h\n"
444     }
445     if ($func->{'name'} =~ m/openpam/) {
446         $mdoc .= ".In security/openpam.h\n"
447     }
448     $mdoc .= ".Ft \"$func->{'type'}\"
449 .Fn $func->{'name'} $func->{'args'}
450 .Sh DESCRIPTION
451 $func->{'man'}
452 ";
453     if ($func->{'type'} eq "int") {
454         $mdoc .= ".Sh RETURN VALUES
455 The
456 .Nm
457 function returns one of the following values:
458 .Bl -tag -width 18n
459 ";
460         my @errors = @{$func->{'errors'}};
461         warn("$func->{'name'}(): no error specification\n")
462             unless(@errors);
463         foreach (@errors) {
464             $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
465         }
466         $mdoc .= ".El\n";
467     } else {
468         if ($func->{'type'} =~ m/\*$/) {
469             $mdoc .= ".Sh RETURN VALUES
470 The
471 .Nm
472 function returns
473 .Dv NULL
474 on failure.
475 ";
476         }
477     }
478     $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
479     $mdoc .= ".Sh STANDARDS\n";
480     if ($func->{'openpam'}) {
481         $mdoc .= "The
482 .Nm
483 function is an OpenPAM extension.
484 ";
485     } else {
486         $mdoc .= ".Rs
487 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
488 .%D \"June 1997\"
489 .Re
490 ";
491     }
492     $mdoc .= ".Sh AUTHORS
493 The
494 .Nm
495 function and this manual page were developed for the
496 .Fx
497 Project by\n" . $AUTHORS{$func->{'author'} // 'THINKSEC_DARPA'} . "\n";
498     $fn = "$func->{'name'}.3";
499     if (open(FILE, ">", $fn)) {
500         print(FILE $mdoc);
501         close(FILE);
502     } else {
503         warn("$fn: open(): $!\n");
504     }
505 }
506
507 sub readproto($) {
508     my $fn = shift;             # File name
509
510     local *FILE;
511     my %func;
512
513     open(FILE, "<", "$fn")
514         or die("$fn: open(): $!\n");
515     while (<FILE>) {
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;
522         }
523     }
524     close(FILE);
525     if ($func{'Nm'}) {
526         $FUNCTIONS{$func{'Nm'}} = \%func;
527     } else {
528         warn("No function found\n");
529     }
530 }
531
532 sub gensummary($) {
533     my $page = shift;           # Which page to produce
534
535     local *FILE;
536     my $upage;
537     my $func;
538     my %xref;
539
540     open(FILE, ">", "$page.3")
541         or die("$page.3: $!\n");
542
543     $page =~ m/(\w+)$/;
544     $upage = uc($1);
545     print FILE "$COPYRIGHT
546 .Dd $TODAY
547 .Dt $upage 3
548 .Os
549 .Sh NAME
550 ";
551     my @funcs = sort(keys(%FUNCTIONS));
552     while ($func = shift(@funcs)) {
553         print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
554         print FILE " ,"
555                 if (@funcs);
556         print FILE "\n";
557     }
558     print FILE ".Nd Pluggable Authentication Modules Library
559 .Sh LIBRARY
560 .Lb libpam
561 .Sh SYNOPSIS\n";
562     if ($page eq 'pam') {
563         print FILE ".In security/pam_appl.h\n";
564     } else {
565         print FILE ".In security/openpam.h\n";
566     }
567     foreach $func (sort(keys(%FUNCTIONS))) {
568         print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
569         print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
570     }
571     while (<STDIN>) {
572         if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
573             ++$xref{int($2)}->{$1};
574         }
575         print FILE $_;
576     }
577
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 :
582 .Bl -tag -width 18n
583 ";
584         foreach (sort(keys(%PAMERR))) {
585             print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
586         }
587         print FILE ".El\n";
588     }
589     print FILE ".Sh SEE ALSO
590 ";
591     if ($page eq 'pam') {
592         ++$xref{3}->{'openpam'};
593     }
594     foreach $func (keys(%FUNCTIONS)) {
595         ++$xref{3}->{$func};
596     }
597     print FILE genxref(\%xref);
598     print FILE ".Sh STANDARDS
599 .Rs
600 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
601 .%D \"June 1997\"
602 .Re
603 .Sh AUTHORS
604 The OpenPAM library and this manual page were developed for the
605 .Fx
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
609 .Pq Dq CBOSS ,
610 as part of the DARPA CHATS research program.
611 ";
612     close(FILE);
613 }
614
615 sub usage() {
616
617     print(STDERR "usage: gendoc [-op] source [...]\n");
618     exit(1);
619 }
620
621 MAIN:{
622     my %opts;
623
624     usage()
625         unless (@ARGV && getopts("op", \%opts));
626     setlocale(LC_ALL, "en_US.UTF-8");
627     $TODAY = strftime("%B %e, %Y", localtime(time()));
628     $TODAY =~ s,\s+, ,g;
629     if ($opts{'o'} || $opts{'p'}) {
630         foreach my $fn (@ARGV) {
631             readproto($fn);
632         }
633         gensummary('openpam')
634             if ($opts{'o'});
635         gensummary('pam')
636             if ($opts{'p'});
637     } else {
638         foreach my $fn (@ARGV) {
639             my $func = parse_source($fn);
640             gendoc($func)
641                 if (defined($func));
642         }
643     }
644     exit(0);
645 }