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

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

s/accound/account/

Spotted by: rwatson

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