689 lines
17 KiB
Perl
689 lines
17 KiB
Perl
#!/usr/bin/perl -w
|
|
#-
|
|
# Copyright (c) 2002-2003 Networks Associates Technology, Inc.
|
|
# Copyright (c) 2004-2017 Dag-Erling Smørgrav
|
|
# All rights reserved.
|
|
#
|
|
# This software was developed for the FreeBSD Project by ThinkSec AS and
|
|
# Network Associates Laboratories, the Security Research Division of
|
|
# Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
|
# ("CBOSS"), as part of the DARPA CHATS research program.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
# 3. The name of the author may not be used to endorse or promote
|
|
# products derived from this software without specific prior written
|
|
# permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
# SUCH DAMAGE.
|
|
#
|
|
|
|
use strict;
|
|
use warnings;
|
|
use open qw(:utf8);
|
|
use utf8;
|
|
use Fcntl;
|
|
use Getopt::Std;
|
|
use POSIX qw(strftime);
|
|
use vars qw(%AUTHORS $TODAY %FUNCTIONS %PAMERR);
|
|
|
|
%AUTHORS = (
|
|
THINKSEC => "developed for the
|
|
.Fx
|
|
Project by ThinkSec AS and Network Associates Laboratories, the
|
|
Security Research Division of Network Associates, Inc.\\& under
|
|
DARPA/SPAWAR contract N66001-01-C-8035
|
|
.Pq Dq CBOSS ,
|
|
as part of the DARPA CHATS research program.
|
|
.Pp
|
|
The OpenPAM library is maintained by
|
|
.An Dag-Erling Sm\\(/orgrav Aq Mt des\@des.no .",
|
|
UIO => "developed for the University of Oslo by
|
|
.An Dag-Erling Sm\\(/orgrav Aq Mt des\@des.no .",
|
|
DES => "developed by
|
|
.An Dag-Erling Sm\\(/orgrav Aq Mt des\@des.no .",
|
|
);
|
|
|
|
%PAMERR = (
|
|
PAM_SUCCESS => "Success",
|
|
PAM_OPEN_ERR => "Failed to load module",
|
|
PAM_SYMBOL_ERR => "Invalid symbol",
|
|
PAM_SERVICE_ERR => "Error in service module",
|
|
PAM_SYSTEM_ERR => "System error",
|
|
PAM_BUF_ERR => "Memory buffer error",
|
|
PAM_CONV_ERR => "Conversation failure",
|
|
PAM_PERM_DENIED => "Permission denied",
|
|
PAM_MAXTRIES => "Maximum number of tries exceeded",
|
|
PAM_AUTH_ERR => "Authentication error",
|
|
PAM_NEW_AUTHTOK_REQD => "New authentication token required",
|
|
PAM_CRED_INSUFFICIENT => "Insufficient credentials",
|
|
PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable",
|
|
PAM_USER_UNKNOWN => "Unknown user",
|
|
PAM_CRED_UNAVAIL => "Failed to retrieve user credentials",
|
|
PAM_CRED_EXPIRED => "User credentials have expired",
|
|
PAM_CRED_ERR => "Failed to set user credentials",
|
|
PAM_ACCT_EXPIRED => "User account has expired",
|
|
PAM_AUTHTOK_EXPIRED => "Password has expired",
|
|
PAM_SESSION_ERR => "Session failure",
|
|
PAM_AUTHTOK_ERR => "Authentication token failure",
|
|
PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token",
|
|
PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy",
|
|
PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled",
|
|
PAM_NO_MODULE_DATA => "Module data not found",
|
|
PAM_IGNORE => "Ignore this module",
|
|
PAM_ABORT => "General failure",
|
|
PAM_TRY_AGAIN => "Try again",
|
|
PAM_MODULE_UNKNOWN => "Unknown module type",
|
|
PAM_DOMAIN_UNKNOWN => "Unknown authentication domain",
|
|
PAM_BAD_HANDLE => "Invalid PAM handle",
|
|
PAM_BAD_ITEM => "Unrecognized or restricted item",
|
|
PAM_BAD_FEATURE => "Unrecognized or restricted feature",
|
|
PAM_BAD_CONSTANT => "Bad constant",
|
|
);
|
|
|
|
sub parse_source($) {
|
|
my $fn = shift;
|
|
|
|
local *FILE;
|
|
my $source;
|
|
my $func;
|
|
my $descr;
|
|
my $type;
|
|
my $args;
|
|
my $argnames;
|
|
my $man;
|
|
my $inlist;
|
|
my $intaglist;
|
|
my $inliteral;
|
|
my $customrv;
|
|
my $deprecated;
|
|
my $experimental;
|
|
my $version;
|
|
my %xref;
|
|
my %errors;
|
|
my $author;
|
|
|
|
if ($fn !~ m,\.c$,) {
|
|
warn("$fn: not C source, ignoring\n");
|
|
return undef;
|
|
}
|
|
|
|
open(FILE, "<", "$fn")
|
|
or die("$fn: open(): $!\n");
|
|
$source = join('', <FILE>);
|
|
close(FILE);
|
|
|
|
return undef
|
|
if ($source =~ m/^ \* NOPARSE\s*$/m);
|
|
|
|
if ($source =~ m/(\$OpenPAM:[^\$]+\$)/) {
|
|
$version = $1;
|
|
}
|
|
|
|
$author = 'THINKSEC';
|
|
if ($source =~ s/^ \* AUTHOR\s+(\w*)\s*$//m) {
|
|
$author = $1;
|
|
}
|
|
|
|
if ($source =~ s/^ \* DEPRECATED\s*(\w*)\s*$//m) {
|
|
$deprecated = $1 // 0;
|
|
}
|
|
|
|
if ($source =~ s/^ \* EXPERIMENTAL\s*$//m) {
|
|
$experimental = 1;
|
|
}
|
|
|
|
$func = $fn;
|
|
$func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
|
|
if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
|
|
warn("$fn: can't find $func\n");
|
|
return undef;
|
|
}
|
|
($descr, $type, $args) = ($1, $2, $3);
|
|
$descr =~ s,^([A-Z][a-z]),lc($1),e;
|
|
$descr =~ s,[\.\s]*$,,;
|
|
while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
|
|
# nothing
|
|
}
|
|
$args =~ s/,\s+/, /gs;
|
|
$args = "\"$args\"";
|
|
|
|
%xref = (
|
|
3 => { 'pam' => 1 },
|
|
);
|
|
|
|
if ($type eq "int") {
|
|
foreach (split("\n", $source)) {
|
|
next unless (m/^ \*\t(!?PAM_[A-Z_]+|=[a-z_]+)\s*(.*?)\s*$/);
|
|
$errors{$1} = $2;
|
|
}
|
|
++$xref{3}->{pam_strerror};
|
|
}
|
|
|
|
$argnames = $args;
|
|
# extract names of regular arguments
|
|
$argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
|
|
# extract names of function pointer arguments
|
|
$argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
|
|
# escape metacharacters (there shouldn't be any, but...)
|
|
$argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
|
|
# separate argument names with |
|
|
$argnames =~ s/\" \"/|/g;
|
|
# and surround with ()
|
|
$argnames =~ s/^\"(.*)\"$/$1/;
|
|
# $argnames is now a regexp that matches argument names
|
|
$inliteral = $inlist = $intaglist = 0;
|
|
foreach (split("\n", $source)) {
|
|
s/\s*$//;
|
|
if (!defined($man)) {
|
|
if (m/^\/\*\*$/) {
|
|
$man = "";
|
|
}
|
|
next;
|
|
}
|
|
last if (m/^ \*\/$/);
|
|
s/^ \* ?//;
|
|
s/\\(.)/$1/gs;
|
|
if (m/^$/) {
|
|
# paragraph separator
|
|
if ($inlist || $intaglist) {
|
|
# either a blank line between list items, or a blank
|
|
# line after the final list item. The latter case
|
|
# will be handled further down.
|
|
next;
|
|
}
|
|
if ($man =~ m/\n\.Sh [^\n]+\n$/s) {
|
|
# a blank line after a section header
|
|
next;
|
|
}
|
|
if ($man ne "" && $man !~ m/\.Pp\n$/s) {
|
|
if ($inliteral) {
|
|
$man .= "\0\n";
|
|
} else {
|
|
$man .= ".Pp\n";
|
|
}
|
|
}
|
|
next;
|
|
}
|
|
if (m/^>(\w+)(\s+\d)?$/) {
|
|
# "see also" cross-reference
|
|
my ($page, $sect) = ($1, $2 ? int($2) : 3);
|
|
++$xref{$sect}->{$page};
|
|
next;
|
|
}
|
|
if (s/^([A-Z][0-9A-Z -]+)$/.Sh $1/) {
|
|
if ($1 eq "RETURN VALUES") {
|
|
$customrv = $1;
|
|
}
|
|
$man =~ s/\n\.Pp$/\n/s;
|
|
$man .= "$_\n";
|
|
next;
|
|
}
|
|
if (s/^\s+-\s+//) {
|
|
# item in bullet list
|
|
if ($inliteral) {
|
|
$man .= ".Ed\n";
|
|
$inliteral = 0;
|
|
}
|
|
if ($intaglist) {
|
|
$man .= ".El\n.Pp\n";
|
|
$intaglist = 0;
|
|
}
|
|
if (!$inlist) {
|
|
$man =~ s/\.Pp\n$//s;
|
|
$man .= ".Bl -bullet\n";
|
|
$inlist = 1;
|
|
}
|
|
$man .= ".It\n";
|
|
# fall through
|
|
} elsif (s/^\s+(\S+):\s*/.It $1/) {
|
|
# item in tag list
|
|
if ($inliteral) {
|
|
$man .= ".Ed\n";
|
|
$inliteral = 0;
|
|
}
|
|
if ($inlist) {
|
|
$man .= ".El\n.Pp\n";
|
|
$inlist = 0;
|
|
}
|
|
if (!$intaglist) {
|
|
$man =~ s/\.Pp\n$//s;
|
|
$man .= ".Bl -tag -width 18n\n";
|
|
$intaglist = 1;
|
|
}
|
|
s/^\.It [=;]([A-Za-z][0-9A-Za-z_]+)$/.It Dv $1/gs;
|
|
$man .= "$_\n";
|
|
next;
|
|
} elsif (($inlist || $intaglist) && m/^\S/) {
|
|
# regular text after list
|
|
$man .= ".El\n.Pp\n";
|
|
$inlist = $intaglist = 0;
|
|
} elsif ($inliteral && m/^\S/) {
|
|
# regular text after literal section
|
|
$man .= ".Ed\n";
|
|
$inliteral = 0;
|
|
} elsif ($inliteral) {
|
|
# additional text within literal section
|
|
$man .= "$_\n";
|
|
next;
|
|
} elsif ($inlist || $intaglist) {
|
|
# additional text within list
|
|
s/^\s+//;
|
|
} elsif (m/^\s+/) {
|
|
# new literal section
|
|
$man .= ".Bd -literal\n";
|
|
$inliteral = 1;
|
|
$man .= "$_\n";
|
|
next;
|
|
}
|
|
s/\s*=($func)\b\s*/\n.Fn $1\n/gs;
|
|
s/\s*=($argnames)\b\s*/\n.Fa $1\n/gs;
|
|
s/\s*=((?:enum|struct|union) \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
|
|
s/\s*:([a-z][0-9a-z_]+)\b\s*/\n.Va $1\n/gs;
|
|
s/\s*;([a-z][0-9a-z_]+)\b\s*/\n.Dv $1\n/gs;
|
|
s/\s*=!([a-z][0-9a-z_]+)\b\s*/\n.Xr $1 3\n/gs;
|
|
while (s/\s*=([a-z][0-9a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
|
|
++$xref{3}->{$1};
|
|
}
|
|
s/\s*\"(?=\w)/\n.Do\n/gs;
|
|
s/\"(?!\w)\s*/\n.Dc\n/gs;
|
|
s/\s*=([A-Z][0-9A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
|
|
s/\s*=([A-Z][0-9A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
|
|
s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
|
|
$man .= "$_\n";
|
|
}
|
|
if (defined($man)) {
|
|
if ($inlist || $intaglist) {
|
|
$man .= ".El\n";
|
|
$inlist = $intaglist = 0;
|
|
}
|
|
if ($inliteral) {
|
|
$man .= ".Ed\n";
|
|
$inliteral = 0;
|
|
}
|
|
$man =~ s/\%/\\&\%/gs;
|
|
$man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([.,:;-])\s+/$1 $2\n/gs;
|
|
$man =~ s/\s*$/\n/gm;
|
|
$man =~ s/\n+/\n/gs;
|
|
$man =~ s/\0//gs;
|
|
$man =~ s/\n\n\./\n\./gs;
|
|
chomp($man);
|
|
} else {
|
|
$man = "No description available.";
|
|
}
|
|
|
|
$FUNCTIONS{$func} = {
|
|
'source' => $fn,
|
|
'version' => $version,
|
|
'name' => $func,
|
|
'descr' => $descr,
|
|
'type' => $type,
|
|
'args' => $args,
|
|
'man' => $man,
|
|
'xref' => \%xref,
|
|
'errors' => \%errors,
|
|
'author' => $author,
|
|
'customrv' => $customrv,
|
|
'deprecated' => $deprecated,
|
|
'experimental' => $experimental,
|
|
};
|
|
if ($source =~ m/^ \* NODOC\s*$/m) {
|
|
$FUNCTIONS{$func}->{nodoc} = 1;
|
|
}
|
|
if ($source !~ m/^ \* XSSO \d/m) {
|
|
$FUNCTIONS{$func}->{openpam} = 1;
|
|
}
|
|
expand_errors($FUNCTIONS{$func});
|
|
return $FUNCTIONS{$func};
|
|
}
|
|
|
|
sub expand_errors($);
|
|
sub expand_errors($) {
|
|
my $func = shift; # Ref to function hash
|
|
|
|
my %errors;
|
|
my $ref;
|
|
my $fn;
|
|
|
|
if (defined($$func{recursed})) {
|
|
warn("$$func{name}(): loop in error spec\n");
|
|
return qw();
|
|
}
|
|
$$func{recursed} = 1;
|
|
|
|
foreach (keys %{$$func{errors}}) {
|
|
if (m/^(PAM_[A-Z_]+)$/) {
|
|
if (!defined($PAMERR{$1})) {
|
|
warn("$$func{name}(): unrecognized error: $1\n");
|
|
next;
|
|
}
|
|
$errors{$1} = $$func{errors}->{$_};
|
|
} elsif (m/^!(PAM_[A-Z_]+)$/) {
|
|
# treat negations separately
|
|
} elsif (m/^=([a-z_]+)$/) {
|
|
$ref = $1;
|
|
if (!defined($FUNCTIONS{$ref})) {
|
|
$fn = $$func{source};
|
|
$fn =~ s/$$func{name}/$ref/;
|
|
parse_source($fn);
|
|
}
|
|
if (!defined($FUNCTIONS{$ref})) {
|
|
warn("$$func{name}(): reference to unknown $ref()\n");
|
|
next;
|
|
}
|
|
foreach (keys %{$FUNCTIONS{$ref}->{errors}}) {
|
|
$errors{$_} //= $FUNCTIONS{$ref}->{errors}->{$_};
|
|
}
|
|
} else {
|
|
warn("$$func{name}(): invalid error specification: $_\n");
|
|
}
|
|
}
|
|
foreach (keys %{$$func{errors}}) {
|
|
if (m/^!(PAM_[A-Z_]+)$/) {
|
|
delete($errors{$1});
|
|
}
|
|
}
|
|
delete($$func{recursed});
|
|
$$func{errors} = \%errors;
|
|
}
|
|
|
|
sub dictionary_order($$) {
|
|
my ($a, $b) = @_;
|
|
|
|
$a =~ s/[^[:alpha:]]//g;
|
|
$b =~ s/[^[:alpha:]]//g;
|
|
$a cmp $b;
|
|
}
|
|
|
|
sub genxref($) {
|
|
my $xref = shift; # References
|
|
|
|
my $mdoc = '';
|
|
my @refs = ();
|
|
foreach my $sect (sort(keys(%{$xref}))) {
|
|
foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
|
|
push(@refs, "$page $sect");
|
|
}
|
|
}
|
|
while ($_ = shift(@refs)) {
|
|
$mdoc .= ".Xr $_" .
|
|
(@refs ? " ,\n" : "\n");
|
|
}
|
|
return $mdoc;
|
|
}
|
|
|
|
sub gendoc($) {
|
|
my $func = shift; # Ref to function hash
|
|
|
|
local *FILE;
|
|
my %errors;
|
|
my $mdoc;
|
|
my $fn;
|
|
|
|
return if defined($$func{nodoc});
|
|
|
|
$$func{source} =~ m/([^\/]+)$/;
|
|
$mdoc = ".\\\" Generated from $1 by gendoc.pl\n";
|
|
if ($$func{version}) {
|
|
$mdoc .= ".\\\" $$func{version}\n";
|
|
}
|
|
$mdoc .= ".Dd $TODAY
|
|
.Dt " . uc($$func{name}) . " 3
|
|
.Os
|
|
.Sh NAME
|
|
.Nm $$func{name}
|
|
.Nd $$func{descr}
|
|
";
|
|
if ($func =~ m/^(?:open)?pam_/) {
|
|
$mdoc .= ".Sh LIBRARY
|
|
.Lb libpam
|
|
";
|
|
}
|
|
$mdoc .= ".Sh SYNOPSIS
|
|
.In sys/types.h
|
|
";
|
|
if ($$func{args} =~ m/\bFILE \*\b/) {
|
|
$mdoc .= ".In stdio.h\n";
|
|
}
|
|
if ($$func{name} =~ m/^(?:open)?pam/) {
|
|
$mdoc .= ".In security/pam_appl.h
|
|
";
|
|
}
|
|
if ($$func{name} =~ m/_sm_/) {
|
|
$mdoc .= ".In security/pam_modules.h\n";
|
|
}
|
|
if ($$func{name} =~ m/openpam/) {
|
|
$mdoc .= ".In security/openpam.h\n";
|
|
}
|
|
$mdoc .= ".Ft \"$$func{type}\"
|
|
.Fn $$func{name} $$func{args}
|
|
.Sh DESCRIPTION
|
|
";
|
|
if (defined($$func{deprecated})) {
|
|
$mdoc .= ".Bf Sy\n" .
|
|
"This function is deprecated and may be removed " .
|
|
"in a future release without further warning.\n";
|
|
if ($$func{deprecated}) {
|
|
$mdoc .= "The\n.Fn $$func{deprecated}\nfunction " .
|
|
"may be used to achieve similar results.\n";
|
|
}
|
|
$mdoc .= ".Ef\n.Pp\n";
|
|
}
|
|
if ($$func{experimental}) {
|
|
$mdoc .= ".Bf Sy\n" .
|
|
"This function is experimental and may be modified or removed " .
|
|
"in a future release without prior warning.\n";
|
|
$mdoc .= ".Ef\n.Pp\n";
|
|
}
|
|
$mdoc .= "$$func{man}\n";
|
|
%errors = %{$$func{errors}};
|
|
if ($$func{customrv}) {
|
|
# leave it
|
|
} elsif ($$func{type} eq "int" && %errors) {
|
|
$mdoc .= ".Sh RETURN VALUES
|
|
The
|
|
.Fn $$func{name}
|
|
function returns one of the following values:
|
|
.Bl -tag -width 18n
|
|
";
|
|
delete($errors{PAM_SUCCESS});
|
|
foreach ('PAM_SUCCESS', sort keys %errors) {
|
|
$mdoc .= ".It Bq Er $_\n" .
|
|
($errors{$_} || $PAMERR{$_}) .
|
|
".\n";
|
|
}
|
|
$mdoc .= ".El\n";
|
|
} elsif ($$func{type} eq "int") {
|
|
$mdoc .= ".Sh RETURN VALUES
|
|
The
|
|
.Fn $$func{name}
|
|
function returns 0 on success and -1 on failure.
|
|
";
|
|
} elsif ($$func{type} =~ m/\*$/) {
|
|
$mdoc .= ".Sh RETURN VALUES
|
|
The
|
|
.Fn $$func{name}
|
|
function returns
|
|
.Dv NULL
|
|
on failure.
|
|
";
|
|
} elsif ($$func{type} ne "void") {
|
|
warn("$$func{name}(): no error specification\n");
|
|
}
|
|
$mdoc .= ".Sh SEE ALSO\n" . genxref($$func{xref});
|
|
$mdoc .= ".Sh STANDARDS\n";
|
|
if ($$func{openpam}) {
|
|
$mdoc .= "The
|
|
.Fn $$func{name}
|
|
function is an OpenPAM extension.
|
|
";
|
|
} else {
|
|
$mdoc .= ".Rs
|
|
.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
|
|
.%D \"June 1997\"
|
|
.Re
|
|
";
|
|
}
|
|
$mdoc .= ".Sh AUTHORS
|
|
The
|
|
.Fn $$func{name}
|
|
function and this manual page were\n";
|
|
$mdoc .= $AUTHORS{$$func{author} // 'THINKSEC_DARPA'} . "\n";
|
|
$fn = "$$func{name}.3";
|
|
if (open(FILE, ">", $fn)) {
|
|
print(FILE $mdoc);
|
|
close(FILE);
|
|
} else {
|
|
warn("$fn: open(): $!\n");
|
|
}
|
|
}
|
|
|
|
sub readproto($) {
|
|
my $fn = shift; # File name
|
|
|
|
local *FILE;
|
|
my %func;
|
|
|
|
open(FILE, "<", "$fn")
|
|
or die("$fn: open(): $!\n");
|
|
while (<FILE>) {
|
|
if (m/^\.Nm ((?:(?:open)?pam)_.*?)\s*$/) {
|
|
$func{Nm} = $func{Nm} || $1;
|
|
} elsif (m/^\.Ft (\S.*?)\s*$/) {
|
|
$func{Ft} = $func{Ft} || $1;
|
|
} elsif (m/^\.Fn (\S.*?)\s*$/) {
|
|
$func{Fn} = $func{Fn} || $1;
|
|
}
|
|
}
|
|
close(FILE);
|
|
if ($func{Nm}) {
|
|
$FUNCTIONS{$func{Nm}} = \%func;
|
|
} else {
|
|
warn("No function found\n");
|
|
}
|
|
}
|
|
|
|
sub gensummary($) {
|
|
my $page = shift; # Which page to produce
|
|
|
|
local *FILE;
|
|
my $upage;
|
|
my $func;
|
|
my %xref;
|
|
|
|
open(FILE, ">", "$page.3")
|
|
or die("$page.3: $!\n");
|
|
|
|
$page =~ m/(\w+)$/;
|
|
$upage = uc($1);
|
|
print FILE ".\\\" Generated by gendoc.pl
|
|
.Dd $TODAY
|
|
.Dt $upage 3
|
|
.Os
|
|
.Sh NAME
|
|
";
|
|
my @funcs = sort(keys(%FUNCTIONS));
|
|
while ($func = shift(@funcs)) {
|
|
print FILE ".Nm $FUNCTIONS{$func}->{Nm}";
|
|
print FILE " ,"
|
|
if (@funcs);
|
|
print FILE "\n";
|
|
}
|
|
print FILE ".Nd Pluggable Authentication Modules Library
|
|
.Sh LIBRARY
|
|
.Lb libpam
|
|
.Sh SYNOPSIS\n";
|
|
if ($page eq 'pam') {
|
|
print FILE ".In security/pam_appl.h\n";
|
|
} else {
|
|
print FILE ".In security/openpam.h\n";
|
|
}
|
|
foreach $func (sort(keys(%FUNCTIONS))) {
|
|
print FILE ".Ft $FUNCTIONS{$func}->{Ft}\n";
|
|
print FILE ".Fn $FUNCTIONS{$func}->{Fn}\n";
|
|
}
|
|
while (<STDIN>) {
|
|
if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
|
|
++$xref{int($2)}->{$1};
|
|
}
|
|
print FILE $_;
|
|
}
|
|
|
|
if ($page eq 'pam') {
|
|
print FILE ".Sh RETURN VALUES
|
|
The following return codes are defined by
|
|
.In security/pam_constants.h :
|
|
.Bl -tag -width 18n
|
|
";
|
|
foreach (sort(keys(%PAMERR))) {
|
|
print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
|
|
}
|
|
print FILE ".El\n";
|
|
}
|
|
print FILE ".Sh SEE ALSO
|
|
";
|
|
if ($page eq 'pam') {
|
|
++$xref{3}->{openpam};
|
|
}
|
|
foreach $func (keys(%FUNCTIONS)) {
|
|
++$xref{3}->{$func};
|
|
}
|
|
print FILE genxref(\%xref);
|
|
print FILE ".Sh STANDARDS
|
|
.Rs
|
|
.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
|
|
.%D \"June 1997\"
|
|
.Re
|
|
";
|
|
print FILE ".Sh AUTHORS
|
|
The OpenPAM library and this manual page were $AUTHORS{THINKSEC}
|
|
";
|
|
close(FILE);
|
|
}
|
|
|
|
sub usage() {
|
|
|
|
print(STDERR "usage: gendoc [-op] source [...]\n");
|
|
exit(1);
|
|
}
|
|
|
|
MAIN:{
|
|
my %opts;
|
|
|
|
usage()
|
|
unless (@ARGV && getopts("op", \%opts));
|
|
$TODAY = strftime("%B %e, %Y", localtime(time()));
|
|
$TODAY =~ s,\s+, ,g;
|
|
if ($opts{o} || $opts{p}) {
|
|
foreach my $fn (@ARGV) {
|
|
readproto($fn);
|
|
}
|
|
gensummary('openpam')
|
|
if ($opts{o});
|
|
gensummary('pam')
|
|
if ($opts{p});
|
|
} else {
|
|
foreach my $fn (@ARGV) {
|
|
my $func = parse_source($fn);
|
|
gendoc($func)
|
|
if (defined($func));
|
|
}
|
|
}
|
|
exit(0);
|
|
}
|