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

Last change on this file since 144 was 144, checked in by des, 13 years ago

Add support for marking up variable names and values.

File size: 11.7 KB
Line 
1#!/usr/bin/perl -w
2#-
3# Copyright (c) 2002 Networks Associates Technology, Inc.
4# All rights reserved.
5#
6# This software was developed for the FreeBSD Project by ThinkSec AS and
7# NAI Labs, the Security Research Division of Network Associates, Inc.
8# under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9# 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#14 $
36#
37
38use strict;
39use Fcntl;
40use POSIX qw(strftime);
41use vars qw($COPYRIGHT $TODAY %FUNCTIONS %PAMERR);
42
43%PAMERR = (
44    PAM_SUCCESS                 => "Success",
45    PAM_OPEN_ERR                => "Failed to load module",
46    PAM_SYMBOL_ERR              => "Invalid symbol",
47    PAM_SERVICE_ERR             => "Error in service module",
48    PAM_SYSTEM_ERR              => "System error",
49    PAM_BUF_ERR                 => "Memory buffer error",
50    PAM_CONV_ERR                => "Conversation failure",
51    PAM_PERM_DENIED             => "Permission denied",
52    PAM_MAXTRIES                => "Maximum number of tries exceeded",
53    PAM_AUTH_ERR                => "Authentication error",
54    PAM_NEW_AUTHTOK_REQD        => "New authentication token required",
55    PAM_CRED_INSUFFICIENT       => "Insufficient credentials",
56    PAM_AUTHINFO_UNAVAIL        => "Authentication information is unavailable",
57    PAM_USER_UNKNOWN            => "Unknown user",
58    PAM_CRED_UNAVAIL            => "Failed to retrieve user credentials",
59    PAM_CRED_EXPIRED            => "User credentials have expired",
60    PAM_CRED_ERR                => "Failed to set user credentials",
61    PAM_ACCT_EXPIRED            => "User accound has expired",
62    PAM_AUTHTOK_EXPIRED         => "Password has expired",
63    PAM_SESSION_ERR             => "Session failure",
64    PAM_AUTHTOK_ERR             => "Authentication token failure",
65    PAM_AUTHTOK_RECOVERY_ERR    => "Failed to recover old authentication token",
66    PAM_AUTHTOK_LOCK_BUSY       => "Authentication token lock busy",
67    PAM_AUTHTOK_DISABLE_AGING   => "Authentication token aging disabled",
68    PAM_NO_MODULE_DATA          => "Module data not found",
69    PAM_IGNORE                  => "Ignore this module",
70    PAM_ABORT                   => "General failure",
71    PAM_TRY_AGAIN               => "Try again",
72    PAM_MODULE_UNKNOWN          => "Unknown module type",
73    PAM_DOMAIN_UNKNOWN          => "Unknown authentication domain",
74);
75
76sub parse_source($) {
77    my $fn = shift;
78
79    local *FILE;
80    my $source;
81    my $func;
82    my $descr;
83    my $type;
84    my $args;
85    my $argnames;
86    my $man;
87    my $inlist;
88    my $inliteral;
89    my %xref;
90    my @errors;
91
92    if ($fn !~ m,\.c$,) {
93        warn("$fn: not C source, ignoring\n");
94        return;
95    }
96
97    sysopen(FILE, $fn, O_RDONLY)
98        or die("$fn: open(): $!\n");
99    $source = join('', <FILE>);
100    close(FILE);
101
102    return if ($source =~ m/^ \* NOPARSE\s*$/m);
103
104    if (!defined($COPYRIGHT) && $source =~ m,^(/\*-\n.*?)\s*\*/,s) {
105        $COPYRIGHT = $1;
106        $COPYRIGHT =~ s,^.\*,.\\\",gm;
107        $COPYRIGHT =~ s,(\$(?:)P4).*?\$,$1\$,;
108        $COPYRIGHT .= "\n.\\\"";
109    }
110    $func = $fn;
111    $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
112    if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
113        warn("$fn: can't find $func\n");
114        return;
115    }
116    ($descr, $type, $args) = ($1, $2, $3);
117    $descr =~ s,^([A-Z][a-z]),lc($1),e;
118    $descr =~ s,[\.\s]*$,,;
119    while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
120        # nothing
121    }
122    $args =~ s/,\s+/, /gs;
123    $args = "\"$args\"";
124
125    %xref = (
126        "pam 3" => 1
127    );
128
129    if ($type eq "int") {
130        foreach (split("\n", $source)) {
131            next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
132            push(@errors, $1);
133        }
134        $xref{"pam_strerror 3"} = 1;
135    }
136
137    $argnames = $args;
138    $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
139    $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
140    $argnames =~ s/\" \"/|/g;
141    $argnames =~ s/^\"(.*)\"$/($1)/;
142    $inliteral = $inlist = 0;
143    foreach (split("\n", $source)) {
144        s/\s*$//;
145        if (!defined($man)) {
146            if (m/^\/\*\*$/) {
147                $man = "";
148            }
149            next;
150        }
151        last if (m/^ \*\/$/);
152        s/^ \* ?//;
153        s/\\(.)/$1/gs;
154        if (m/^$/) {
155            if ($man ne "" && $man !~ m/\.Pp\n$/s) {
156                if ($inliteral) {
157                    $man .= "\0\n";
158                } elsif ($inlist) {
159                    $man .= ".El\n";
160                    $inlist = 0;
161                } else {
162                    $man .= ".Pp\n";
163                }
164            }
165            next;
166        }
167        if (m/^>(\w+)(?:\s+(\d))?$/) {
168            ++$xref{$2 ? "$1 $2" : "$1 3"};
169            next;
170        }
171        if (s/^\s+(=?\w+):\s*/.It $1/) {
172            if ($inliteral) {
173                $man .= ".Ed\n";
174                $inliteral = 0;
175            }
176            if (!$inlist) {
177                $man =~ s/\.Pp\n$//s;
178                $man .= ".Bl -tag -width 18n\n";
179                $inlist = 1;
180            }
181            s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
182            $man .= "$_\n";
183            next;
184        } elsif ($inlist && m/^\S/) {
185            $man .= ".El\n";
186            $inlist = 0;
187        } elsif ($inliteral && m/^\S/) {
188            $man .= ".Ed\n";
189            $inliteral = 0;
190        } elsif ($inliteral) {
191            $man .= "$_\n";
192            next;
193        } elsif ($inlist) {
194            s/^\s+//;
195        } elsif (m/^\s+/) {
196            $man .= ".Bd -literal\n";
197            $inliteral = 1;
198            $man .= "$_\n";
199            next;
200        }
201        s/\s*=$func\b\s*/\n.Nm\n/gs;
202        s/\s*=$argnames\b\s*/\n.Va $1\n/gs;
203        s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
204        s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
205        s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
206        if (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/gs) {
207            ++$xref{"$1 3"};
208        }
209        s/\s*\"(?=\w)/\n.Do\n/gs;
210        s/\"(?!\w)\s*/\n.Dc\n/gs;
211        s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
212        s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
213        s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
214        $man .= "$_\n";
215    }
216    if (defined($man)) {
217        if ($inlist) {
218            $man .= ".El\n";
219        }
220        if ($inliteral) {
221            $man .= ".Ed\n";
222        }
223        $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([\.,:;-]\S*)\s*/$1 $2\n/gs;
224        $man =~ s/\s*$/\n/gm;
225        $man =~ s/\n+/\n/gs;
226        $man =~ s/\0//gs;
227        $man =~ s/\n\n\./\n\./gs;
228        chomp($man);
229    } else {
230        $man = "No description available.";
231    }
232
233    $FUNCTIONS{$func} = {
234        'name'          => $func,
235        'descr'         => $descr,
236        'type'          => $type,
237        'args'          => $args,
238        'man'           => $man,
239        'xref'          => \%xref,
240        'errors'        => \@errors,
241    };
242    if ($source =~ m/^ \* NODOC\s*$/m) {
243        $FUNCTIONS{$func}->{'nodoc'} = 1;
244        $FUNCTIONS{$func}->{'nolist'} = 1;
245    }
246    if ($source =~ m/^ \* NOLIST\s*$/m) {
247        $FUNCTIONS{$func}->{'nolist'} = 1;
248    }
249    if ($source !~ m/^ \* XSSO \d/m) {
250        $FUNCTIONS{$func}->{'openpam'} = 1;
251    }
252}
253
254sub expand_errors($);
255sub expand_errors($) {
256    my $func = shift;           # Ref to function hash
257
258    my %errors;
259
260    if (defined($func->{'recursed'})) {
261        warn("$func->{'name'}(): loop in error spec\n");
262        return qw();
263    }
264    $func->{'recursed'} = 1;
265
266    foreach (@{$func->{'errors'}}) {
267        if (m/^(PAM_[A-Z_]+)$/) {
268            if (!defined($PAMERR{$1})) {
269                warn("$func->{'name'}(): unrecognized error: $1\n");
270                next;
271            }
272            $errors{$1} = 1;
273        } elsif (m/^!(PAM_[A-Z_]+)$/) {
274            # treat negations separately
275        } elsif (m/^=([a-z_]+)$/) {
276            if (!defined($FUNCTIONS{$1})) {
277                warn("$func->{'name'}(): reference to unknown $1()\n");
278                next;
279            }
280            foreach (expand_errors($FUNCTIONS{$1})) {
281                $errors{$_} = 1;
282            }
283        } else {
284            warn("$func->{'name'}(): invalid error specification: $_\n");
285        }
286    }
287    foreach (@{$func->{'errors'}}) {
288        if (m/^!(PAM_[A-Z_]+)$/) {
289            delete($errors{$1});
290        }
291    }
292    delete($func->{'recursed'});
293    return (sort(keys(%errors)));
294}
295
296sub gendoc($) {
297    my $func = shift;           # Ref to function hash
298
299    local *FILE;
300    my $mdoc;
301    my $fn;
302
303    return if defined($func->{'nodoc'});
304
305    $mdoc = "$COPYRIGHT
306.Dd $TODAY
307.Dt " . uc($func->{'name'}) . " 3
308.Os
309.Sh NAME
310.Nm $func->{'name'}
311.Nd $func->{'descr'}
312.Sh LIBRARY
313.Lb libpam
314.Sh SYNOPSIS
315.In security/pam_appl.h
316";
317    if ($func->{'name'} =~ m/_sm_/) {
318        $mdoc .= ".In security/pam_modules.h\n"
319    }
320    if ($func->{'name'} =~ m/openpam/) {
321        $mdoc .= ".In security/openpam.h\n"
322    }
323    $mdoc .= ".Ft $func->{'type'}
324.Fn $func->{'name'} $func->{'args'}
325.Sh DESCRIPTION
326$func->{'man'}
327";
328    if ($func->{'type'} eq "int") {
329        $mdoc .= ".Sh RETURN VALUES
330The
331.Nm
332function returns one of the following values:
333.Bl -tag -width 18n
334";
335        my @errors = expand_errors($func);
336        warn("$func->{'name'}(): no error specification\n")
337            unless(@errors);
338        foreach (@errors) {
339            $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
340        }
341        $mdoc .= ".El\n";
342    } else {
343        if ($func->{'type'} =~ m/\*$/) {
344            $mdoc .= ".Sh RETURN VALUES
345The
346.Nm
347function returns
348.Dv NULL
349on failure.
350";
351        }
352    }
353    $mdoc .= ".Sh SEE ALSO\n";
354    my @xref = sort(keys(%{$func->{'xref'}}));
355    while (@xref) {
356        $mdoc .= ".Xr " . shift(@xref) . (@xref ? " ,\n" : "\n");
357    }
358    $mdoc .= ".Sh STANDARDS\n";
359    if ($func->{'openpam'}) {
360        $mdoc .= "The
361.Nm
362function is an OpenPAM extension.
363";
364    } else {
365        $mdoc .= ".Rs
366.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
367.%D \"June 1997\"
368.Re
369";
370    }
371    $mdoc .= ".Sh AUTHORS
372The
373.Nm
374function and this manual page were developed for the FreeBSD Project
375by ThinkSec AS and NAI Labs, the Security Research Division of Network
376Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
377.Pq Dq CBOSS ,
378as part of the DARPA CHATS research program.
379";
380
381    $fn = "$func->{'name'}.3";
382    if (sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC)) {
383        print(FILE $mdoc);
384        close(FILE);
385    } else {
386        warn("$fn: open(): $!\n");
387    }
388}
389
390sub gensummary() {
391
392    my $func;
393
394    print "$COPYRIGHT
395.Dd $TODAY
396.Dt PAM 3
397.Os
398.Sh NAME
399";
400    my @funcs = sort(keys(%FUNCTIONS));
401    while ($func = shift(@funcs)) {
402        next if (defined($FUNCTIONS{$func}->{'nolist'}));
403        print ".Nm $func". (@funcs ? " ,\n" : "\n");
404    }
405    print ".Nd Pluggable Authentication Modules Library
406.Sh LIBRARY
407.Lb libpam
408.Sh SYNOPSIS
409.In security/pam_appl.h
410";
411    foreach $func (sort(keys(%FUNCTIONS))) {
412        next if (defined($FUNCTIONS{$func}->{'nolist'}));
413        print ".Ft $FUNCTIONS{$func}->{'type'}\n";
414        print ".Fn $func $FUNCTIONS{$func}->{'args'}\n";
415    }
416    print ".Sh DESCRIPTION
417.Sh RETURN VALUES
418The following return codes are defined in the
419.In security/pam_constants.h
420header:
421.Bl -tag -width 18n
422";
423    foreach (sort(keys(%PAMERR))) {
424        print ".It Bq Er $_\n$PAMERR{$_}.\n";
425    }
426    print ".El
427.Sh SEE ALSO
428";
429    foreach $func (sort(keys(%FUNCTIONS))) {
430        next if (defined($FUNCTIONS{$func}->{'nolist'}));
431        print ".Xr $func 3 ,\n";
432    }
433    print ".Xr pam.conf 5
434.Sh STANDARDS
435.Rs
436.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
437.%D \"June 1997\"
438.Re
439.Sh AUTHORS
440The OpenPAM library and this manual page were developed for the
441FreeBSD Project by ThinkSec AS and NAI Labs, the Security Research
442Division of Network Associates, Inc.  under DARPA/SPAWAR contract
443N66001-01-C-8035
444.Pq Dq CBOSS ,
445as part of the DARPA CHATS research program.
446"
447}
448
449MAIN:{
450    $TODAY = strftime("%B %e, %Y", localtime(time()));
451    $TODAY =~ s,\s+, ,g;
452    foreach my $fn (@ARGV) {
453        parse_source($fn);
454    }
455    foreach my $func (values(%FUNCTIONS)) {
456        gendoc($func);
457    }
458    gensummary();
459}
Note: See TracBrowser for help on using the repository browser.