191100Sdes#!/usr/bin/perl -w 291100Sdes#- 3115619Sdes# Copyright (c) 2002-2003 Networks Associates Technology, Inc. 4228692Sdes# 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# 36255376Sdes# $Id: gendoc.pl 736 2013-09-07 12:52:42Z des $ 3791100Sdes# 3891100Sdes 3991100Sdesuse strict; 40255376Sdesuse warnings; 41255376Sdesuse open qw(:utf8); 42255376Sdesuse utf8; 4391100Sdesuse Fcntl; 4499158Sdesuse Getopt::Std; 45255376Sdesuse POSIX qw(strftime); 46255376Sdesuse vars qw(%AUTHORS $TODAY %FUNCTIONS %PAMERR); 4791100Sdes 48228692Sdes%AUTHORS = ( 49236109Sdes THINKSEC => "developed for the 50236109Sdes.Fx 51236109SdesProject by ThinkSec AS and Network Associates Laboratories, the 52228692SdesSecurity Research Division of Network Associates, Inc.\\& under 53228692SdesDARPA/SPAWAR contract N66001-01-C-8035 54228692Sdes.Pq Dq CBOSS , 55255376Sdesas part of the DARPA CHATS research program. 56255376Sdes.Pp 57255376SdesThe OpenPAM library is maintained by 58255376Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no .", 59255376Sdes UIO => "developed for the University of Oslo by 60255376Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no .", 61236109Sdes DES => "developed by 62236109Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no .", 63228692Sdes); 64228692Sdes 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; 110228692Sdes my $intaglist; 11191100Sdes my $inliteral; 112236109Sdes my $customrv; 113236109Sdes my $deprecated; 114236109Sdes my $experimental; 115255376Sdes my $version; 11691100Sdes my %xref; 11791100Sdes my @errors; 118228692Sdes my $author; 11991100Sdes 12091100Sdes if ($fn !~ m,\.c$,) { 12191100Sdes warn("$fn: not C source, ignoring\n"); 12299158Sdes return undef; 12391100Sdes } 12491100Sdes 125228692Sdes 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 133255376Sdes if ($source =~ m/(\$Id:[^\$]+\$)/) { 134255376Sdes $version = $1; 135255376Sdes } 136255376Sdes 137228692Sdes $author = 'THINKSEC'; 138236109Sdes if ($source =~ s/^ \* AUTHOR\s+(\w*)\s*$//m) { 139228692Sdes $author = $1; 140228692Sdes } 141228692Sdes 142236109Sdes if ($source =~ s/^ \* DEPRECATED\s*(\w*)\s*$//m) { 143236109Sdes $deprecated = $1 // 0; 144236109Sdes } 145236109Sdes 146236109Sdes if ($source =~ s/^ \* EXPERIMENTAL\s*$//m) { 147236109Sdes $experimental = 1; 148236109Sdes } 149236109Sdes 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 } 174255376Sdes ++$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 () 187236109Sdes $argnames =~ s/^\"(.*)\"$/$1/; 188141098Sdes # $argnames is now a regexp that matches argument names 189228692Sdes $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/^$/) { 202228692Sdes # paragraph separator 203236109Sdes if ($inlist || $intaglist) { 204236109Sdes # either a blank line between list items, or a blank 205236109Sdes # line after the final list item. The latter case 206236109Sdes # will be handled further down. 207236109Sdes next; 208236109Sdes } 209236109Sdes if ($man =~ m/\n\.Sh [^\n]+\n$/s) { 210236109Sdes # a blank line after a section header 211236109Sdes next; 212236109Sdes } 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)?$/) { 223228692Sdes # "see also" cross-reference 224141098Sdes my ($page, $sect) = ($1, $2 ? int($2) : 3); 225141098Sdes ++$xref{$sect}->{$page}; 22691100Sdes next; 22791100Sdes } 228236109Sdes if (s/^([A-Z][0-9A-Z -]+)$/.Sh $1/) { 229236109Sdes if ($1 eq "RETURN VALUES") { 230236109Sdes $customrv = $1; 231236109Sdes } 232236109Sdes $man =~ s/\n\.Pp$/\n/s; 233236109Sdes $man .= "$_\n"; 234236109Sdes next; 235236109Sdes } 236228692Sdes if (s/^\s+-\s+//) { 237228692Sdes # item in bullet list 23891100Sdes if ($inliteral) { 23991100Sdes $man .= ".Ed\n"; 24091100Sdes $inliteral = 0; 24191100Sdes } 242228692Sdes if ($intaglist) { 243228692Sdes $man .= ".El\n.Pp\n"; 244228692Sdes $intaglist = 0; 245228692Sdes } 24691100Sdes if (!$inlist) { 24791100Sdes $man =~ s/\.Pp\n$//s; 248228692Sdes $man .= ".Bl -bullet\n"; 24991100Sdes $inlist = 1; 25091100Sdes } 251228692Sdes $man .= ".It\n"; 252228692Sdes # fall through 253228692Sdes } elsif (s/^\s+(\S+):\s*/.It $1/) { 254228692Sdes # item in tag list 255228692Sdes if ($inliteral) { 256228692Sdes $man .= ".Ed\n"; 257228692Sdes $inliteral = 0; 258228692Sdes } 259228692Sdes if ($inlist) { 260228692Sdes $man .= ".El\n.Pp\n"; 261228692Sdes $inlist = 0; 262228692Sdes } 263228692Sdes if (!$intaglist) { 264228692Sdes $man =~ s/\.Pp\n$//s; 265228692Sdes $man .= ".Bl -tag -width 18n\n"; 266228692Sdes $intaglist = 1; 267228692Sdes } 268255376Sdes s/^\.It [=;]([A-Za-z][0-9A-Za-z_]+)$/.It Dv $1/gs; 26991100Sdes $man .= "$_\n"; 27091100Sdes next; 271228692Sdes } elsif (($inlist || $intaglist) && m/^\S/) { 272228692Sdes # regular text after list 27399158Sdes $man .= ".El\n.Pp\n"; 274228692Sdes $inlist = $intaglist = 0; 27591100Sdes } elsif ($inliteral && m/^\S/) { 276228692Sdes # regular text after literal section 27791100Sdes $man .= ".Ed\n"; 27895908Sdes $inliteral = 0; 27991100Sdes } elsif ($inliteral) { 280228692Sdes # additional text within literal section 28191100Sdes $man .= "$_\n"; 28291100Sdes next; 283228692Sdes } elsif ($inlist || $intaglist) { 284228692Sdes # additional text within list 28591100Sdes s/^\s+//; 28691100Sdes } elsif (m/^\s+/) { 287228692Sdes # new literal section 28891100Sdes $man .= ".Bd -literal\n"; 28991100Sdes $inliteral = 1; 29091100Sdes $man .= "$_\n"; 29191100Sdes next; 29291100Sdes } 293236109Sdes s/\s*=($func)\b\s*/\n.Fn $1\n/gs; 294236109Sdes s/\s*=($argnames)\b\s*/\n.Fa $1\n/gs; 29591100Sdes s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs; 296255376Sdes s/\s*:([a-z][0-9a-z_]+)\b\s*/\n.Va $1\n/gs; 297255376Sdes s/\s*;([a-z][0-9a-z_]+)\b\s*/\n.Dv $1\n/gs; 298255376Sdes s/\s*=!([a-z][0-9a-z_]+)\b\s*/\n.Xr $1 3\n/gs; 299255376Sdes 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; 304255376Sdes s/\s*=([A-Z][0-9A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs; 305255376Sdes 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)) { 310228692Sdes if ($inlist || $intaglist) { 31195908Sdes $man .= ".El\n"; 312228692Sdes $inlist = $intaglist = 0; 31395908Sdes } 31495908Sdes if ($inliteral) { 31595908Sdes $man .= ".Ed\n"; 316228692Sdes $inliteral = 0; 31795908Sdes } 318228692Sdes $man =~ s/\%/\\&\%/gs; 319236109Sdes $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, 331255376Sdes 'version' => $version, 33291100Sdes 'name' => $func, 33391100Sdes 'descr' => $descr, 33491100Sdes 'type' => $type, 33591100Sdes 'args' => $args, 33691100Sdes 'man' => $man, 33791100Sdes 'xref' => \%xref, 33891100Sdes 'errors' => \@errors, 339228692Sdes 'author' => $author, 340236109Sdes 'customrv' => $customrv, 341236109Sdes 'deprecated' => $deprecated, 342236109Sdes 'experimental' => $experimental, 34391100Sdes }; 34491100Sdes if ($source =~ m/^ \* NODOC\s*$/m) { 345255376Sdes $FUNCTIONS{$func}->{nodoc} = 1; 34691100Sdes } 34791100Sdes if ($source !~ m/^ \* XSSO \d/m) { 348255376Sdes $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 362255376Sdes if (defined($$func{recursed})) { 363255376Sdes warn("$$func{name}(): loop in error spec\n"); 36491100Sdes return qw(); 36591100Sdes } 366255376Sdes $$func{recursed} = 1; 36791100Sdes 368255376Sdes foreach (@{$$func{errors}}) { 36991100Sdes if (m/^(PAM_[A-Z_]+)$/) { 37091100Sdes if (!defined($PAMERR{$1})) { 371255376Sdes 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})) { 380255376Sdes $fn = $$func{source}; 381255376Sdes $fn =~ s/$$func{name}/$ref/; 38299158Sdes parse_source($fn); 38399158Sdes } 38499158Sdes if (!defined($FUNCTIONS{$ref})) { 385255376Sdes warn("$$func{name}(): reference to unknown $ref()\n"); 38691100Sdes next; 38791100Sdes } 388255376Sdes foreach (@{$FUNCTIONS{$ref}->{errors}}) { 38991100Sdes $errors{$_} = 1; 39091100Sdes } 39191100Sdes } else { 392255376Sdes warn("$$func{name}(): invalid error specification: $_\n"); 39391100Sdes } 39491100Sdes } 395255376Sdes foreach (@{$$func{errors}}) { 39691100Sdes if (m/^!(PAM_[A-Z_]+)$/) { 39791100Sdes delete($errors{$1}); 39891100Sdes } 39991100Sdes } 400255376Sdes delete($$func{recursed}); 401255376Sdes $$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 436255376Sdes return if defined($$func{nodoc}); 43791100Sdes 438255376Sdes $$func{source} =~ m/([^\/]+)$/; 439255376Sdes $mdoc = ".\\\" Generated from $1 by gendoc.pl\n"; 440255376Sdes if ($$func{version}) { 441255376Sdes $mdoc .= ".\\\" $$func{version}\n"; 442255376Sdes } 443255376Sdes $mdoc .= ".Dd $TODAY 444255376Sdes.Dt " . uc($$func{name}) . " 3 44591100Sdes.Os 44691100Sdes.Sh NAME 447255376Sdes.Nm $$func{name} 448255376Sdes.Nd $$func{descr} 44991100Sdes.Sh LIBRARY 45091100Sdes.Lb libpam 45191100Sdes.Sh SYNOPSIS 452108794Sdes.In sys/types.h 45391100Sdes"; 454255376Sdes if ($$func{args} =~ m/\bFILE \*\b/) { 455236109Sdes $mdoc .= ".In stdio.h\n"; 456236109Sdes } 457236109Sdes $mdoc .= ".In security/pam_appl.h 458236109Sdes"; 459255376Sdes if ($$func{name} =~ m/_sm_/) { 460236109Sdes $mdoc .= ".In security/pam_modules.h\n"; 46191100Sdes } 462255376Sdes if ($$func{name} =~ m/openpam/) { 463236109Sdes $mdoc .= ".In security/openpam.h\n"; 46495908Sdes } 465255376Sdes $mdoc .= ".Ft \"$$func{type}\" 466255376Sdes.Fn $$func{name} $$func{args} 46791100Sdes.Sh DESCRIPTION 46891100Sdes"; 469255376Sdes if (defined($$func{deprecated})) { 470236109Sdes $mdoc .= ".Bf Sy\n" . 471236109Sdes "This function is deprecated and may be removed " . 472236109Sdes "in a future release without further warning.\n"; 473255376Sdes if ($$func{deprecated}) { 474255376Sdes $mdoc .= "The\n.Fn $$func{deprecated}\nfunction " . 475236109Sdes "may be used to achieve similar results.\n"; 476236109Sdes } 477236109Sdes $mdoc .= ".Ef\n.Pp\n"; 478236109Sdes } 479255376Sdes if ($$func{experimental}) { 480236109Sdes $mdoc .= ".Bf Sy\n" . 481236109Sdes "This function is experimental and may be modified or removed " . 482255376Sdes "in a future release without prior warning.\n"; 483236109Sdes $mdoc .= ".Ef\n.Pp\n"; 484236109Sdes } 485255376Sdes $mdoc .= "$$func{man}\n"; 486255376Sdes my @errors = @{$$func{errors}}; 487255376Sdes if ($$func{customrv}) { 488236109Sdes # leave it 489255376Sdes } elsif ($$func{type} eq "int" && @errors) { 49091100Sdes $mdoc .= ".Sh RETURN VALUES 49191100SdesThe 492255376Sdes.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"; 500255376Sdes } elsif ($$func{type} eq "int") { 501236109Sdes $mdoc .= ".Sh RETURN VALUES 50291100SdesThe 503255376Sdes.Fn $$func{name} 504236109Sdesfunction returns 0 on success and -1 on failure. 505236109Sdes"; 506255376Sdes } elsif ($$func{type} =~ m/\*$/) { 507236109Sdes $mdoc .= ".Sh RETURN VALUES 508236109SdesThe 509255376Sdes.Fn $$func{name} 51091100Sdesfunction returns 51191100Sdes.Dv NULL 51291100Sdeson failure. 51391100Sdes"; 514255376Sdes } elsif ($$func{type} ne "void") { 515255376Sdes warn("$$func{name}(): no error specification\n"); 51691100Sdes } 517255376Sdes $mdoc .= ".Sh SEE ALSO\n" . genxref($$func{xref}); 51891100Sdes $mdoc .= ".Sh STANDARDS\n"; 519255376Sdes if ($$func{openpam}) { 52091100Sdes $mdoc .= "The 521255376Sdes.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 533255376Sdes.Fn $$func{name} 534236109Sdesfunction and this manual page were\n"; 535255376Sdes $mdoc .= $AUTHORS{$$func{author} // 'THINKSEC_DARPA'} . "\n"; 536255376Sdes $fn = "$$func{name}.3"; 537228692Sdes 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 551228692Sdes open(FILE, "<", "$fn") 55299158Sdes or die("$fn: open(): $!\n"); 55399158Sdes while (<FILE>) { 55499158Sdes if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) { 555255376Sdes $func{Nm} = $func{Nm} || $1; 55699158Sdes } elsif (m/^\.Ft (\S.*?)\s*$/) { 557255376Sdes $func{Ft} = $func{Ft} || $1; 55899158Sdes } elsif (m/^\.Fn (\S.*?)\s*$/) { 559255376Sdes $func{Fn} = $func{Fn} || $1; 56099158Sdes } 56199158Sdes } 56299158Sdes close(FILE); 563255376Sdes if ($func{Nm}) { 564255376Sdes $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 578228692Sdes open(FILE, ">", "$page.3") 57999158Sdes or die("$page.3: $!\n"); 58099158Sdes 581228692Sdes $page =~ m/(\w+)$/; 582228692Sdes $upage = uc($1); 583255376Sdes 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)) { 591255376Sdes 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))) { 606255376Sdes print FILE ".Ft $FUNCTIONS{$func}->{Ft}\n"; 607255376Sdes 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') { 630255376Sdes ++$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. 649236109Sdes.Pp 650236109SdesThe OpenPAM library is maintained by 651236109Sdes.An Dag-Erling Sm\\(/orgrav Aq des\@des.no . 65299158Sdes"; 65399158Sdes close(FILE); 65491100Sdes} 65591100Sdes 65699158Sdessub usage() { 65799158Sdes 658228692Sdes 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; 669255376Sdes if ($opts{o} || $opts{p}) { 67099158Sdes foreach my $fn (@ARGV) { 67199158Sdes readproto($fn); 67299158Sdes } 67399158Sdes gensummary('openpam') 674255376Sdes if ($opts{o}); 67599158Sdes gensummary('pam') 676255376Sdes 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