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} 460