191100Sdes#!/usr/bin/perl -w 291100Sdes#- 3115619Sdes# Copyright (c) 2002-2003 Networks Associates Technology, Inc. 4247568Sdes# Copyright (c) 2004-2011 Dag-Erling Sm��rgrav 591100Sdes# All rights reserved. 691100Sdes# 791100Sdes# This software was developed for the FreeBSD Project by ThinkSec AS and 899158Sdes# Network Associates Laboratories, the Security Research Division of 999158Sdes# Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1099158Sdes# ("CBOSS"), as part of the DARPA CHATS research program. 1191100Sdes# 1291100Sdes# Redistribution and use in source and binary forms, with or without 1391100Sdes# modification, are permitted provided that the following conditions 1491100Sdes# are met: 1591100Sdes# 1. Redistributions of source code must retain the above copyright 1691100Sdes# notice, this list of conditions and the following disclaimer. 1791100Sdes# 2. Redistributions in binary form must reproduce the above copyright 1891100Sdes# notice, this list of conditions and the following disclaimer in the 1991100Sdes# documentation and/or other materials provided with the distribution. 2091100Sdes# 3. The name of the author may not be used to endorse or promote 2191100Sdes# products derived from this software without specific prior written 2291100Sdes# permission. 2391100Sdes# 2491100Sdes# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2591100Sdes# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2691100Sdes# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2791100Sdes# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2891100Sdes# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2991100Sdes# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3091100Sdes# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3191100Sdes# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3291100Sdes# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3391100Sdes# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3491100Sdes# SUCH DAMAGE. 3591100Sdes# 36263421Sdes# $Id: gendoc.pl 736 2013-09-07 12:52:42Z des $ 3791100Sdes# 3891100Sdes 3991100Sdesuse strict; 40263421Sdesuse warnings; 41263421Sdesuse open qw(:utf8); 42263421Sdesuse utf8; 4391100Sdesuse Fcntl; 4499158Sdesuse Getopt::Std; 45263421Sdesuse POSIX qw(strftime); 46263421Sdesuse vars qw(%AUTHORS $TODAY %FUNCTIONS %PAMERR); 4791100Sdes 48247568Sdes%AUTHORS = ( 49247568Sdes THINKSEC => "developed for the 50247568Sdes.Fx 51247568SdesProject by ThinkSec AS and Network Associates Laboratories, the 52247568SdesSecurity Research Division of Network Associates, Inc.\\& under 53247568SdesDARPA/SPAWAR contract N66001-01-C-8035 54247568Sdes.Pq Dq CBOSS , 55263421Sdesas part of the DARPA CHATS research program. 56263421Sdes.Pp 57263421SdesThe OpenPAM library is maintained by 58263421Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no .", 59263421Sdes UIO => "developed for the University of Oslo by 60263421Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no .", 61247568Sdes DES => "developed by 62247568Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no .", 63247568Sdes); 64247568Sdes 6591100Sdes%PAMERR = ( 6691100Sdes PAM_SUCCESS => "Success", 6791100Sdes PAM_OPEN_ERR => "Failed to load module", 6891100Sdes PAM_SYMBOL_ERR => "Invalid symbol", 6991100Sdes PAM_SERVICE_ERR => "Error in service module", 7091100Sdes PAM_SYSTEM_ERR => "System error", 7191100Sdes PAM_BUF_ERR => "Memory buffer error", 7291100Sdes PAM_CONV_ERR => "Conversation failure", 7391100Sdes PAM_PERM_DENIED => "Permission denied", 7491100Sdes PAM_MAXTRIES => "Maximum number of tries exceeded", 7591100Sdes PAM_AUTH_ERR => "Authentication error", 7691100Sdes PAM_NEW_AUTHTOK_REQD => "New authentication token required", 7791100Sdes PAM_CRED_INSUFFICIENT => "Insufficient credentials", 7891100Sdes PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable", 7991100Sdes PAM_USER_UNKNOWN => "Unknown user", 8091100Sdes PAM_CRED_UNAVAIL => "Failed to retrieve user credentials", 8191100Sdes PAM_CRED_EXPIRED => "User credentials have expired", 8291100Sdes PAM_CRED_ERR => "Failed to set user credentials", 83141098Sdes PAM_ACCT_EXPIRED => "User account has expired", 8491100Sdes PAM_AUTHTOK_EXPIRED => "Password has expired", 8591100Sdes PAM_SESSION_ERR => "Session failure", 8691100Sdes PAM_AUTHTOK_ERR => "Authentication token failure", 8791100Sdes PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token", 8891100Sdes PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy", 8991100Sdes PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled", 9091100Sdes PAM_NO_MODULE_DATA => "Module data not found", 9191100Sdes PAM_IGNORE => "Ignore this module", 9291100Sdes PAM_ABORT => "General failure", 9391100Sdes PAM_TRY_AGAIN => "Try again", 9491100Sdes PAM_MODULE_UNKNOWN => "Unknown module type", 9591100Sdes PAM_DOMAIN_UNKNOWN => "Unknown authentication domain", 9691100Sdes); 9791100Sdes 9891100Sdessub parse_source($) { 9991100Sdes my $fn = shift; 10091100Sdes 10191100Sdes local *FILE; 10291100Sdes my $source; 10391100Sdes my $func; 10491100Sdes my $descr; 10591100Sdes my $type; 10691100Sdes my $args; 10791100Sdes my $argnames; 10891100Sdes my $man; 10991100Sdes my $inlist; 110247568Sdes my $intaglist; 11191100Sdes my $inliteral; 112247568Sdes my $customrv; 113247568Sdes my $deprecated; 114247568Sdes my $experimental; 115263421Sdes my $version; 11691100Sdes my %xref; 11791100Sdes my @errors; 118247568Sdes my $author; 11991100Sdes 12091100Sdes if ($fn !~ m,\.c$,) { 12191100Sdes warn("$fn: not C source, ignoring\n"); 12299158Sdes return undef; 12391100Sdes } 12491100Sdes 125247568Sdes open(FILE, "<", "$fn") 12691100Sdes or die("$fn: open(): $!\n"); 12791100Sdes $source = join('', <FILE>); 12891100Sdes close(FILE); 12991100Sdes 13099158Sdes return undef 13199158Sdes if ($source =~ m/^ \* NOPARSE\s*$/m); 13291100Sdes 133263421Sdes if ($source =~ m/(\$Id:[^\$]+\$)/) { 134263421Sdes $version = $1; 135263421Sdes } 136263421Sdes 137247568Sdes $author = 'THINKSEC'; 138247568Sdes if ($source =~ s/^ \* AUTHOR\s+(\w*)\s*$//m) { 139247568Sdes $author = $1; 140247568Sdes } 141247568Sdes 142247568Sdes if ($source =~ s/^ \* DEPRECATED\s*(\w*)\s*$//m) { 143247568Sdes $deprecated = $1 // 0; 144247568Sdes } 145247568Sdes 146247568Sdes if ($source =~ s/^ \* EXPERIMENTAL\s*$//m) { 147247568Sdes $experimental = 1; 148247568Sdes } 149247568Sdes 15091100Sdes $func = $fn; 15191100Sdes $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,; 15291100Sdes if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) { 15391100Sdes warn("$fn: can't find $func\n"); 15499158Sdes return undef; 15591100Sdes } 15691100Sdes ($descr, $type, $args) = ($1, $2, $3); 15791100Sdes $descr =~ s,^([A-Z][a-z]),lc($1),e; 15891100Sdes $descr =~ s,[\.\s]*$,,; 15991100Sdes while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) { 16091100Sdes # nothing 16191100Sdes } 16291100Sdes $args =~ s/,\s+/, /gs; 16391100Sdes $args = "\"$args\""; 16491100Sdes 16591100Sdes %xref = ( 166141098Sdes 3 => { 'pam' => 1 }, 16791100Sdes ); 16891100Sdes 16991100Sdes if ($type eq "int") { 17091100Sdes foreach (split("\n", $source)) { 17191100Sdes next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/); 17291100Sdes push(@errors, $1); 17391100Sdes } 174263421Sdes ++$xref{3}->{pam_strerror}; 17591100Sdes } 17691100Sdes 17791100Sdes $argnames = $args; 178141098Sdes # extract names of regular arguments 17991100Sdes $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g; 180141098Sdes # extract names of function pointer arguments 181141098Sdes $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g; 182141098Sdes # escape metacharacters (there shouldn't be any, but...) 18391100Sdes $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g; 184141098Sdes # separate argument names with | 18591100Sdes $argnames =~ s/\" \"/|/g; 186141098Sdes # and surround with () 187247568Sdes $argnames =~ s/^\"(.*)\"$/$1/; 188141098Sdes # $argnames is now a regexp that matches argument names 189247568Sdes $inliteral = $inlist = $intaglist = 0; 19091100Sdes foreach (split("\n", $source)) { 19191100Sdes s/\s*$//; 19291100Sdes if (!defined($man)) { 19391100Sdes if (m/^\/\*\*$/) { 19491100Sdes $man = ""; 19591100Sdes } 19691100Sdes next; 19791100Sdes } 19891100Sdes last if (m/^ \*\/$/); 19991100Sdes s/^ \* ?//; 20091100Sdes s/\\(.)/$1/gs; 20191100Sdes if (m/^$/) { 202247568Sdes # paragraph separator 203247568Sdes if ($inlist || $intaglist) { 204247568Sdes # either a blank line between list items, or a blank 205247568Sdes # line after the final list item. The latter case 206247568Sdes # will be handled further down. 207247568Sdes next; 208247568Sdes } 209247568Sdes if ($man =~ m/\n\.Sh [^\n]+\n$/s) { 210247568Sdes # a blank line after a section header 211247568Sdes next; 212247568Sdes } 21391100Sdes if ($man ne "" && $man !~ m/\.Pp\n$/s) { 21491100Sdes if ($inliteral) { 21591100Sdes $man .= "\0\n"; 21691100Sdes } else { 21791100Sdes $man .= ".Pp\n"; 21891100Sdes } 21991100Sdes } 22091100Sdes next; 22191100Sdes } 222141098Sdes if (m/^>(\w+)(\s+\d)?$/) { 223247568Sdes # "see also" cross-reference 224141098Sdes my ($page, $sect) = ($1, $2 ? int($2) : 3); 225141098Sdes ++$xref{$sect}->{$page}; 22691100Sdes next; 22791100Sdes } 228247568Sdes if (s/^([A-Z][0-9A-Z -]+)$/.Sh $1/) { 229247568Sdes if ($1 eq "RETURN VALUES") { 230247568Sdes $customrv = $1; 231247568Sdes } 232247568Sdes $man =~ s/\n\.Pp$/\n/s; 233247568Sdes $man .= "$_\n"; 234247568Sdes next; 235247568Sdes } 236247568Sdes if (s/^\s+-\s+//) { 237247568Sdes # item in bullet list 23891100Sdes if ($inliteral) { 23991100Sdes $man .= ".Ed\n"; 24091100Sdes $inliteral = 0; 24191100Sdes } 242247568Sdes if ($intaglist) { 243247568Sdes $man .= ".El\n.Pp\n"; 244247568Sdes $intaglist = 0; 245247568Sdes } 24691100Sdes if (!$inlist) { 24791100Sdes $man =~ s/\.Pp\n$//s; 248247568Sdes $man .= ".Bl -bullet\n"; 24991100Sdes $inlist = 1; 25091100Sdes } 251247568Sdes $man .= ".It\n"; 252247568Sdes # fall through 253247568Sdes } elsif (s/^\s+(\S+):\s*/.It $1/) { 254247568Sdes # item in tag list 255247568Sdes if ($inliteral) { 256247568Sdes $man .= ".Ed\n"; 257247568Sdes $inliteral = 0; 258247568Sdes } 259247568Sdes if ($inlist) { 260247568Sdes $man .= ".El\n.Pp\n"; 261247568Sdes $inlist = 0; 262247568Sdes } 263247568Sdes if (!$intaglist) { 264247568Sdes $man =~ s/\.Pp\n$//s; 265247568Sdes $man .= ".Bl -tag -width 18n\n"; 266247568Sdes $intaglist = 1; 267247568Sdes } 268263421Sdes s/^\.It [=;]([A-Za-z][0-9A-Za-z_]+)$/.It Dv $1/gs; 26991100Sdes $man .= "$_\n"; 27091100Sdes next; 271247568Sdes } elsif (($inlist || $intaglist) && m/^\S/) { 272247568Sdes # regular text after list 27399158Sdes $man .= ".El\n.Pp\n"; 274247568Sdes $inlist = $intaglist = 0; 27591100Sdes } elsif ($inliteral && m/^\S/) { 276247568Sdes # regular text after literal section 27791100Sdes $man .= ".Ed\n"; 27895908Sdes $inliteral = 0; 27991100Sdes } elsif ($inliteral) { 280247568Sdes # additional text within literal section 28191100Sdes $man .= "$_\n"; 28291100Sdes next; 283247568Sdes } elsif ($inlist || $intaglist) { 284247568Sdes # additional text within list 28591100Sdes s/^\s+//; 28691100Sdes } elsif (m/^\s+/) { 287247568Sdes # new literal section 28891100Sdes $man .= ".Bd -literal\n"; 28991100Sdes $inliteral = 1; 29091100Sdes $man .= "$_\n"; 29191100Sdes next; 29291100Sdes } 293247568Sdes s/\s*=($func)\b\s*/\n.Fn $1\n/gs; 294247568Sdes s/\s*=($argnames)\b\s*/\n.Fa $1\n/gs; 29591100Sdes s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs; 296263421Sdes s/\s*:([a-z][0-9a-z_]+)\b\s*/\n.Va $1\n/gs; 297263421Sdes s/\s*;([a-z][0-9a-z_]+)\b\s*/\n.Dv $1\n/gs; 298263421Sdes s/\s*=!([a-z][0-9a-z_]+)\b\s*/\n.Xr $1 3\n/gs; 299263421Sdes while (s/\s*=([a-z][0-9a-z_]+)\b\s*/\n.Xr $1 3\n/s) { 300141098Sdes ++$xref{3}->{$1}; 30191100Sdes } 30291100Sdes s/\s*\"(?=\w)/\n.Do\n/gs; 30391100Sdes s/\"(?!\w)\s*/\n.Dc\n/gs; 304263421Sdes s/\s*=([A-Z][0-9A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs; 305263421Sdes s/\s*=([A-Z][0-9A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs; 30691100Sdes s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs; 30791100Sdes $man .= "$_\n"; 30891100Sdes } 30991100Sdes if (defined($man)) { 310247568Sdes if ($inlist || $intaglist) { 31195908Sdes $man .= ".El\n"; 312247568Sdes $inlist = $intaglist = 0; 31395908Sdes } 31495908Sdes if ($inliteral) { 31595908Sdes $man .= ".Ed\n"; 316247568Sdes $inliteral = 0; 31795908Sdes } 318247568Sdes $man =~ s/\%/\\&\%/gs; 319247568Sdes $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([.,:;-])\s+/$1 $2\n/gs; 32091100Sdes $man =~ s/\s*$/\n/gm; 32191100Sdes $man =~ s/\n+/\n/gs; 32291100Sdes $man =~ s/\0//gs; 32395908Sdes $man =~ s/\n\n\./\n\./gs; 32491100Sdes chomp($man); 32591100Sdes } else { 32691100Sdes $man = "No description available."; 32791100Sdes } 32891100Sdes 32991100Sdes $FUNCTIONS{$func} = { 33099158Sdes 'source' => $fn, 331263421Sdes 'version' => $version, 33291100Sdes 'name' => $func, 33391100Sdes 'descr' => $descr, 33491100Sdes 'type' => $type, 33591100Sdes 'args' => $args, 33691100Sdes 'man' => $man, 33791100Sdes 'xref' => \%xref, 33891100Sdes 'errors' => \@errors, 339247568Sdes 'author' => $author, 340247568Sdes 'customrv' => $customrv, 341247568Sdes 'deprecated' => $deprecated, 342247568Sdes 'experimental' => $experimental, 34391100Sdes }; 34491100Sdes if ($source =~ m/^ \* NODOC\s*$/m) { 345263421Sdes $FUNCTIONS{$func}->{nodoc} = 1; 34691100Sdes } 34791100Sdes if ($source !~ m/^ \* XSSO \d/m) { 348263421Sdes $FUNCTIONS{$func}->{openpam} = 1; 34991100Sdes } 35099158Sdes expand_errors($FUNCTIONS{$func}); 35199158Sdes return $FUNCTIONS{$func}; 35291100Sdes} 35391100Sdes 35491100Sdessub expand_errors($); 35591100Sdessub expand_errors($) { 35691100Sdes my $func = shift; # Ref to function hash 35791100Sdes 35891100Sdes my %errors; 35999158Sdes my $ref; 36099158Sdes my $fn; 36191100Sdes 362263421Sdes if (defined($$func{recursed})) { 363263421Sdes warn("$$func{name}(): loop in error spec\n"); 36491100Sdes return qw(); 36591100Sdes } 366263421Sdes $$func{recursed} = 1; 36791100Sdes 368263421Sdes foreach (@{$$func{errors}}) { 36991100Sdes if (m/^(PAM_[A-Z_]+)$/) { 37091100Sdes if (!defined($PAMERR{$1})) { 371263421Sdes warn("$$func{name}(): unrecognized error: $1\n"); 37291100Sdes next; 37391100Sdes } 37491100Sdes $errors{$1} = 1; 37591100Sdes } elsif (m/^!(PAM_[A-Z_]+)$/) { 37691100Sdes # treat negations separately 37791100Sdes } elsif (m/^=([a-z_]+)$/) { 37899158Sdes $ref = $1; 37999158Sdes if (!defined($FUNCTIONS{$ref})) { 380263421Sdes $fn = $$func{source}; 381263421Sdes $fn =~ s/$$func{name}/$ref/; 38299158Sdes parse_source($fn); 38399158Sdes } 38499158Sdes if (!defined($FUNCTIONS{$ref})) { 385263421Sdes warn("$$func{name}(): reference to unknown $ref()\n"); 38691100Sdes next; 38791100Sdes } 388263421Sdes foreach (@{$FUNCTIONS{$ref}->{errors}}) { 38991100Sdes $errors{$_} = 1; 39091100Sdes } 39191100Sdes } else { 392263421Sdes warn("$$func{name}(): invalid error specification: $_\n"); 39391100Sdes } 39491100Sdes } 395263421Sdes foreach (@{$$func{errors}}) { 39691100Sdes if (m/^!(PAM_[A-Z_]+)$/) { 39791100Sdes delete($errors{$1}); 39891100Sdes } 39991100Sdes } 400263421Sdes delete($$func{recursed}); 401263421Sdes $$func{errors} = [ sort(keys(%errors)) ]; 40291100Sdes} 40391100Sdes 404147455Sdessub dictionary_order($$) { 405147455Sdes my ($a, $b) = @_; 406147455Sdes 407147455Sdes $a =~ s/[^[:alpha:]]//g; 408147455Sdes $b =~ s/[^[:alpha:]]//g; 409147455Sdes $a cmp $b; 410147455Sdes} 411147455Sdes 412141098Sdessub genxref($) { 413141098Sdes my $xref = shift; # References 414141098Sdes 415141098Sdes my $mdoc = ''; 416141098Sdes my @refs = (); 417141098Sdes foreach my $sect (sort(keys(%{$xref}))) { 418147455Sdes foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) { 419141098Sdes push(@refs, "$page $sect"); 420141098Sdes } 421141098Sdes } 422141098Sdes while ($_ = shift(@refs)) { 423141098Sdes $mdoc .= ".Xr $_" . 424141098Sdes (@refs ? " ,\n" : "\n"); 425141098Sdes } 426141098Sdes return $mdoc; 427141098Sdes} 428141098Sdes 42991100Sdessub gendoc($) { 43091100Sdes my $func = shift; # Ref to function hash 43191100Sdes 43291100Sdes local *FILE; 43391100Sdes my $mdoc; 43491100Sdes my $fn; 43591100Sdes 436263421Sdes return if defined($$func{nodoc}); 43791100Sdes 438263421Sdes $$func{source} =~ m/([^\/]+)$/; 439263421Sdes $mdoc = ".\\\" Generated from $1 by gendoc.pl\n"; 440263421Sdes if ($$func{version}) { 441263421Sdes $mdoc .= ".\\\" $$func{version}\n"; 442263421Sdes } 443263421Sdes $mdoc .= ".Dd $TODAY 444263421Sdes.Dt " . uc($$func{name}) . " 3 44591100Sdes.Os 44691100Sdes.Sh NAME 447263421Sdes.Nm $$func{name} 448263421Sdes.Nd $$func{descr} 44991100Sdes.Sh LIBRARY 45091100Sdes.Lb libpam 45191100Sdes.Sh SYNOPSIS 452108794Sdes.In sys/types.h 45391100Sdes"; 454263421Sdes if ($$func{args} =~ m/\bFILE \*\b/) { 455247568Sdes $mdoc .= ".In stdio.h\n"; 456247568Sdes } 457247568Sdes $mdoc .= ".In security/pam_appl.h 458247568Sdes"; 459263421Sdes if ($$func{name} =~ m/_sm_/) { 460247568Sdes $mdoc .= ".In security/pam_modules.h\n"; 46191100Sdes } 462263421Sdes if ($$func{name} =~ m/openpam/) { 463247568Sdes $mdoc .= ".In security/openpam.h\n"; 46495908Sdes } 465263421Sdes $mdoc .= ".Ft \"$$func{type}\" 466263421Sdes.Fn $$func{name} $$func{args} 46791100Sdes.Sh DESCRIPTION 46891100Sdes"; 469263421Sdes if (defined($$func{deprecated})) { 470247568Sdes $mdoc .= ".Bf Sy\n" . 471247568Sdes "This function is deprecated and may be removed " . 472247568Sdes "in a future release without further warning.\n"; 473263421Sdes if ($$func{deprecated}) { 474263421Sdes $mdoc .= "The\n.Fn $$func{deprecated}\nfunction " . 475247568Sdes "may be used to achieve similar results.\n"; 476247568Sdes } 477247568Sdes $mdoc .= ".Ef\n.Pp\n"; 478247568Sdes } 479263421Sdes if ($$func{experimental}) { 480247568Sdes $mdoc .= ".Bf Sy\n" . 481247568Sdes "This function is experimental and may be modified or removed " . 482263421Sdes "in a future release without prior warning.\n"; 483247568Sdes $mdoc .= ".Ef\n.Pp\n"; 484247568Sdes } 485263421Sdes $mdoc .= "$$func{man}\n"; 486263421Sdes my @errors = @{$$func{errors}}; 487263421Sdes if ($$func{customrv}) { 488247568Sdes # leave it 489263421Sdes } elsif ($$func{type} eq "int" && @errors) { 49091100Sdes $mdoc .= ".Sh RETURN VALUES 49191100SdesThe 492263421Sdes.Fn $$func{name} 49391100Sdesfunction returns one of the following values: 49491100Sdes.Bl -tag -width 18n 49591100Sdes"; 49691100Sdes foreach (@errors) { 49791100Sdes $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n"; 49891100Sdes } 49991100Sdes $mdoc .= ".El\n"; 500263421Sdes } elsif ($$func{type} eq "int") { 501247568Sdes $mdoc .= ".Sh RETURN VALUES 50291100SdesThe 503263421Sdes.Fn $$func{name} 504247568Sdesfunction returns 0 on success and -1 on failure. 505247568Sdes"; 506263421Sdes } elsif ($$func{type} =~ m/\*$/) { 507247568Sdes $mdoc .= ".Sh RETURN VALUES 508247568SdesThe 509263421Sdes.Fn $$func{name} 51091100Sdesfunction returns 51191100Sdes.Dv NULL 51291100Sdeson failure. 51391100Sdes"; 514263421Sdes } elsif ($$func{type} ne "void") { 515263421Sdes warn("$$func{name}(): no error specification\n"); 51691100Sdes } 517263421Sdes $mdoc .= ".Sh SEE ALSO\n" . genxref($$func{xref}); 51891100Sdes $mdoc .= ".Sh STANDARDS\n"; 519263421Sdes if ($$func{openpam}) { 52091100Sdes $mdoc .= "The 521263421Sdes.Fn $$func{name} 52291100Sdesfunction is an OpenPAM extension. 52391100Sdes"; 52491100Sdes } else { 52591100Sdes $mdoc .= ".Rs 52691100Sdes.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\" 52791100Sdes.%D \"June 1997\" 52891100Sdes.Re 52991100Sdes"; 53091100Sdes } 53191100Sdes $mdoc .= ".Sh AUTHORS 53291100SdesThe 533263421Sdes.Fn $$func{name} 534247568Sdesfunction and this manual page were\n"; 535263421Sdes $mdoc .= $AUTHORS{$$func{author} // 'THINKSEC_DARPA'} . "\n"; 536263421Sdes $fn = "$$func{name}.3"; 537247568Sdes if (open(FILE, ">", $fn)) { 53897241Sdes print(FILE $mdoc); 53997241Sdes close(FILE); 54095908Sdes } else { 54195908Sdes warn("$fn: open(): $!\n"); 54295908Sdes } 54391100Sdes} 54491100Sdes 54599158Sdessub readproto($) { 54699158Sdes my $fn = shift; # File name 54791100Sdes 54899158Sdes local *FILE; 54999158Sdes my %func; 55099158Sdes 551247568Sdes open(FILE, "<", "$fn") 55299158Sdes or die("$fn: open(): $!\n"); 55399158Sdes while (<FILE>) { 55499158Sdes if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) { 555263421Sdes $func{Nm} = $func{Nm} || $1; 55699158Sdes } elsif (m/^\.Ft (\S.*?)\s*$/) { 557263421Sdes $func{Ft} = $func{Ft} || $1; 55899158Sdes } elsif (m/^\.Fn (\S.*?)\s*$/) { 559263421Sdes $func{Fn} = $func{Fn} || $1; 56099158Sdes } 56199158Sdes } 56299158Sdes close(FILE); 563263421Sdes if ($func{Nm}) { 564263421Sdes $FUNCTIONS{$func{Nm}} = \%func; 56599158Sdes } else { 56699158Sdes warn("No function found\n"); 56799158Sdes } 56899158Sdes} 56999158Sdes 57099158Sdessub gensummary($) { 57199158Sdes my $page = shift; # Which page to produce 57299158Sdes 57399158Sdes local *FILE; 57499158Sdes my $upage; 57591100Sdes my $func; 57699158Sdes my %xref; 57791100Sdes 578247568Sdes open(FILE, ">", "$page.3") 57999158Sdes or die("$page.3: $!\n"); 58099158Sdes 581247568Sdes $page =~ m/(\w+)$/; 582247568Sdes $upage = uc($1); 583263421Sdes print FILE ".\\\" Generated by gendoc.pl 58491100Sdes.Dd $TODAY 58599158Sdes.Dt $upage 3 58691100Sdes.Os 58791100Sdes.Sh NAME 58891100Sdes"; 58991100Sdes my @funcs = sort(keys(%FUNCTIONS)); 59091100Sdes while ($func = shift(@funcs)) { 591263421Sdes print FILE ".Nm $FUNCTIONS{$func}->{Nm}"; 59299158Sdes print FILE " ," 59399158Sdes if (@funcs); 59499158Sdes print FILE "\n"; 59591100Sdes } 59699158Sdes print FILE ".Nd Pluggable Authentication Modules Library 59791100Sdes.Sh LIBRARY 59891100Sdes.Lb libpam 59999158Sdes.Sh SYNOPSIS\n"; 60099158Sdes if ($page eq 'pam') { 60199158Sdes print FILE ".In security/pam_appl.h\n"; 60299158Sdes } else { 60399158Sdes print FILE ".In security/openpam.h\n"; 60499158Sdes } 60591100Sdes foreach $func (sort(keys(%FUNCTIONS))) { 606263421Sdes print FILE ".Ft $FUNCTIONS{$func}->{Ft}\n"; 607263421Sdes print FILE ".Fn $FUNCTIONS{$func}->{Fn}\n"; 60891100Sdes } 60999158Sdes while (<STDIN>) { 61099158Sdes if (m/^\.Xr (\S+)\s*(\d)\s*$/) { 611141098Sdes ++$xref{int($2)}->{$1}; 612115619Sdes } 61399158Sdes print FILE $_; 61499158Sdes } 61599158Sdes 61699158Sdes if ($page eq 'pam') { 61799158Sdes print FILE ".Sh RETURN VALUES 61899158SdesThe following return codes are defined by 619141098Sdes.In security/pam_constants.h : 62091100Sdes.Bl -tag -width 18n 62191100Sdes"; 62299158Sdes foreach (sort(keys(%PAMERR))) { 62399158Sdes print FILE ".It Bq Er $_\n$PAMERR{$_}.\n"; 62499158Sdes } 62599158Sdes print FILE ".El\n"; 62691100Sdes } 62799158Sdes print FILE ".Sh SEE ALSO 62891100Sdes"; 629141098Sdes if ($page eq 'pam') { 630263421Sdes ++$xref{3}->{openpam}; 631141098Sdes } 63299158Sdes foreach $func (keys(%FUNCTIONS)) { 633141098Sdes ++$xref{3}->{$func}; 63491100Sdes } 635141098Sdes print FILE genxref(\%xref); 63699158Sdes print FILE ".Sh STANDARDS 63791100Sdes.Rs 63891100Sdes.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\" 63991100Sdes.%D \"June 1997\" 64091100Sdes.Re 64191100Sdes.Sh AUTHORS 64291100SdesThe OpenPAM library and this manual page were developed for the 643117610Sdes.Fx 644117610SdesProject by ThinkSec AS and Network Associates Laboratories, the 645147464SdesSecurity Research Division of Network Associates, Inc.\\& under 64699158SdesDARPA/SPAWAR contract N66001-01-C-8035 64791100Sdes.Pq Dq CBOSS , 64891100Sdesas part of the DARPA CHATS research program. 649247568Sdes.Pp 650247568SdesThe OpenPAM library is maintained by 651247568Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no . 65299158Sdes"; 65399158Sdes close(FILE); 65491100Sdes} 65591100Sdes 65699158Sdessub usage() { 65799158Sdes 658247568Sdes print(STDERR "usage: gendoc [-op] source [...]\n"); 65999158Sdes exit(1); 66099158Sdes} 66199158Sdes 66291100SdesMAIN:{ 66399158Sdes my %opts; 66499158Sdes 66599158Sdes usage() 66699158Sdes unless (@ARGV && getopts("op", \%opts)); 66791100Sdes $TODAY = strftime("%B %e, %Y", localtime(time())); 66891100Sdes $TODAY =~ s,\s+, ,g; 669263421Sdes if ($opts{o} || $opts{p}) { 67099158Sdes foreach my $fn (@ARGV) { 67199158Sdes readproto($fn); 67299158Sdes } 67399158Sdes gensummary('openpam') 674263421Sdes if ($opts{o}); 67599158Sdes gensummary('pam') 676263421Sdes if ($opts{p}); 67799158Sdes } else { 67899158Sdes foreach my $fn (@ARGV) { 67999158Sdes my $func = parse_source($fn); 68099158Sdes gendoc($func) 68199158Sdes if (defined($func)); 68299158Sdes } 68391100Sdes } 68499158Sdes exit(0); 68591100Sdes} 686