source: openpam/trunk/misc/gendoc.pl @ 221

Last change on this file since 221 was 221, checked in by Dag-Erling Smørgrav, 15 years ago

Update copyright dates for files that have changed this year. Also
change the copyright date on generated man pages from 2002 to 2001-2003
since work on this part of OpenPAM started in late 2001.

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