aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Polstra <jdp@FreeBSD.org>1998-11-18 01:16:21 +0000
committerJohn Polstra <jdp@FreeBSD.org>1998-11-18 01:16:21 +0000
commitfff5887d38e30654e1d5da89af2ad7614c05cfc8 (patch)
tree34d7fe17cf8b2fe7fe61c7fe8ce3a5574bbfa23a
downloadsrc-fff5887d38e30654e1d5da89af2ad7614c05cfc8.tar.gz
src-fff5887d38e30654e1d5da89af2ad7614c05cfc8.zip
Initial import of virgin Linux-PAM 0.65, slightly stripped down.vendor/libpam/0.65
Notes
Notes: svn path=/vendor/libpam/dist/; revision=41220 svn path=/vendor/libpam/0.65/; revision=41222; tag=vendor/libpam/0.65
-rw-r--r--contrib/libpam/CHANGELOG1091
-rw-r--r--contrib/libpam/Copyright41
-rw-r--r--contrib/libpam/Makefile282
-rw-r--r--contrib/libpam/README167
-rw-r--r--contrib/libpam/TODO59
-rw-r--r--contrib/libpam/bin/README39
-rw-r--r--contrib/libpam/conf/Makefile60
-rwxr-xr-xcontrib/libpam/conf/install178
-rwxr-xr-xcontrib/libpam/conf/install_conf36
-rwxr-xr-xcontrib/libpam/conf/md5itall45
-rwxr-xr-xcontrib/libpam/conf/mkdirp50
-rw-r--r--contrib/libpam/conf/pam.conf126
-rw-r--r--contrib/libpam/conf/pam_conv1/Makefile41
-rw-r--r--contrib/libpam/conf/pam_conv1/README10
-rw-r--r--contrib/libpam/conf/pam_conv1/lex.yy.c1553
-rw-r--r--contrib/libpam/conf/pam_conv1/pam_conv.lex42
-rw-r--r--contrib/libpam/conf/pam_conv1/pam_conv.tab.c1019
-rw-r--r--contrib/libpam/conf/pam_conv1/pam_conv.y203
-rw-r--r--contrib/libpam/defs/hpux.defs36
-rw-r--r--contrib/libpam/defs/linux.defs32
-rw-r--r--contrib/libpam/defs/morgan.defs35
-rw-r--r--contrib/libpam/defs/redhat.defs34
-rw-r--r--contrib/libpam/defs/solaris.defs48
-rw-r--r--contrib/libpam/defs/sunos.defs37
-rw-r--r--contrib/libpam/doc/CREDITS37
-rw-r--r--contrib/libpam/doc/Makefile77
-rw-r--r--contrib/libpam/doc/NOTES16
-rw-r--r--contrib/libpam/doc/figs/pam_orient.txt23
-rw-r--r--contrib/libpam/doc/html/index.html21
-rw-r--r--contrib/libpam/doc/man/pam.8279
-rw-r--r--contrib/libpam/doc/man/pam.conf.81
-rw-r--r--contrib/libpam/doc/man/pam.d.81
-rw-r--r--contrib/libpam/doc/man/pam_authenticate.391
-rw-r--r--contrib/libpam/doc/man/pam_chauthtok.3101
-rw-r--r--contrib/libpam/doc/man/pam_close_session.31
-rw-r--r--contrib/libpam/doc/man/pam_end.31
-rw-r--r--contrib/libpam/doc/man/pam_fail_delay.3130
-rw-r--r--contrib/libpam/doc/man/pam_open_session.399
-rw-r--r--contrib/libpam/doc/man/pam_setcred.379
-rw-r--r--contrib/libpam/doc/man/pam_start.398
-rw-r--r--contrib/libpam/doc/man/pam_strerror.349
-rw-r--r--contrib/libpam/doc/man/template-man52
-rw-r--r--contrib/libpam/doc/modules/README13
-rw-r--r--contrib/libpam/doc/modules/module.sgml-template170
-rw-r--r--contrib/libpam/doc/modules/pam_chroot.sgml86
-rw-r--r--contrib/libpam/doc/modules/pam_cracklib.sgml254
-rw-r--r--contrib/libpam/doc/modules/pam_deny.sgml179
-rw-r--r--contrib/libpam/doc/modules/pam_env.sgml125
-rw-r--r--contrib/libpam/doc/modules/pam_filter.sgml150
-rw-r--r--contrib/libpam/doc/modules/pam_ftp.sgml93
-rw-r--r--contrib/libpam/doc/modules/pam_group.sgml108
-rw-r--r--contrib/libpam/doc/modules/pam_krb4.sgml126
-rw-r--r--contrib/libpam/doc/modules/pam_lastlog.sgml119
-rw-r--r--contrib/libpam/doc/modules/pam_limits.sgml196
-rw-r--r--contrib/libpam/doc/modules/pam_listfile.sgml138
-rw-r--r--contrib/libpam/doc/modules/pam_mail.sgml124
-rw-r--r--contrib/libpam/doc/modules/pam_nologin.sgml75
-rw-r--r--contrib/libpam/doc/modules/pam_permit.sgml83
-rw-r--r--contrib/libpam/doc/modules/pam_pwdb.sgml245
-rw-r--r--contrib/libpam/doc/modules/pam_radius.sgml117
-rw-r--r--contrib/libpam/doc/modules/pam_rhosts.sgml157
-rw-r--r--contrib/libpam/doc/modules/pam_rootok.sgml85
-rw-r--r--contrib/libpam/doc/modules/pam_securetty.sgml72
-rw-r--r--contrib/libpam/doc/modules/pam_time.sgml166
-rw-r--r--contrib/libpam/doc/modules/pam_warn.sgml67
-rw-r--r--contrib/libpam/doc/modules/pam_wheel.sgml124
-rw-r--r--contrib/libpam/doc/pam_appl.sgml1567
-rw-r--r--contrib/libpam/doc/pam_modules.sgml1425
-rw-r--r--contrib/libpam/doc/pam_source.sgml985
-rw-r--r--contrib/libpam/doc/ps/README3
-rw-r--r--contrib/libpam/doc/specs/draft-morgan-pam-00.raw270
-rw-r--r--contrib/libpam/doc/specs/formatter/Makefile16
-rw-r--r--contrib/libpam/doc/specs/formatter/parse.lex11
-rw-r--r--contrib/libpam/doc/specs/formatter/parse.y293
-rw-r--r--contrib/libpam/doc/specs/rfc86.0.txt1851
-rw-r--r--contrib/libpam/doc/txts/README3
-rw-r--r--contrib/libpam/examples/Makefile42
-rw-r--r--contrib/libpam/examples/blank.c173
-rw-r--r--contrib/libpam/examples/check_user.c65
-rw-r--r--contrib/libpam/examples/test.c99
-rw-r--r--contrib/libpam/examples/vpass.c47
-rw-r--r--contrib/libpam/examples/xsh.c139
-rw-r--r--contrib/libpam/libpam/Makefile177
-rw-r--r--contrib/libpam/libpam/include/security/_pam_compat.h109
-rw-r--r--contrib/libpam/libpam/include/security/_pam_macros.h165
-rw-r--r--contrib/libpam/libpam/include/security/_pam_types.h356
-rw-r--r--contrib/libpam/libpam/include/security/pam_appl.h99
-rw-r--r--contrib/libpam/libpam/include/security/pam_malloc.h73
-rw-r--r--contrib/libpam/libpam/include/security/pam_modules.h189
-rw-r--r--contrib/libpam/libpam/pam_account.c13
-rw-r--r--contrib/libpam/libpam/pam_auth.c61
-rw-r--r--contrib/libpam/libpam/pam_data.c123
-rw-r--r--contrib/libpam/libpam/pam_delay.c152
-rw-r--r--contrib/libpam/libpam/pam_dispatch.c286
-rw-r--r--contrib/libpam/libpam/pam_end.c77
-rw-r--r--contrib/libpam/libpam/pam_env.c403
-rw-r--r--contrib/libpam/libpam/pam_handlers.c901
-rw-r--r--contrib/libpam/libpam/pam_item.c313
-rw-r--r--contrib/libpam/libpam/pam_log.c425
-rw-r--r--contrib/libpam/libpam/pam_malloc.c394
-rw-r--r--contrib/libpam/libpam/pam_map.c79
-rw-r--r--contrib/libpam/libpam/pam_misc.c334
-rw-r--r--contrib/libpam/libpam/pam_password.c51
-rw-r--r--contrib/libpam/libpam/pam_private.h322
-rw-r--r--contrib/libpam/libpam/pam_second.c40
-rw-r--r--contrib/libpam/libpam/pam_session.c35
-rw-r--r--contrib/libpam/libpam/pam_start.c117
-rw-r--r--contrib/libpam/libpam/pam_static.c153
-rw-r--r--contrib/libpam/libpam/pam_strerror.c106
-rw-r--r--contrib/libpam/libpam/pam_tokens.h105
-rw-r--r--contrib/libpam/libpam_misc/Makefile109
-rw-r--r--contrib/libpam/libpam_misc/help_env.c112
-rw-r--r--contrib/libpam/libpam_misc/misc_conv.c371
-rw-r--r--contrib/libpam/libpam_misc/pam_misc.h70
-rw-r--r--contrib/libpam/libpam_misc/xstrdup.c38
-rw-r--r--contrib/libpam/modules/Makefile132
-rw-r--r--contrib/libpam/modules/README55
-rw-r--r--contrib/libpam/modules/dont_makefile19
-rw-r--r--contrib/libpam/modules/pam_access/Makefile111
-rw-r--r--contrib/libpam/modules/pam_access/README40
-rw-r--r--contrib/libpam/modules/pam_access/access.conf52
-rwxr-xr-xcontrib/libpam/modules/pam_access/install_conf46
-rw-r--r--contrib/libpam/modules/pam_access/pam_access.c424
-rw-r--r--contrib/libpam/modules/pam_cracklib/Makefile110
-rw-r--r--contrib/libpam/modules/pam_cracklib/README21
-rw-r--r--contrib/libpam/modules/pam_cracklib/pam_cracklib.c687
-rw-r--r--contrib/libpam/modules/pam_deny/Makefile125
-rw-r--r--contrib/libpam/modules/pam_deny/README4
-rw-r--r--contrib/libpam/modules/pam_deny/pam_deny.c94
-rw-r--r--contrib/libpam/modules/pam_env/Makefile107
-rw-r--r--contrib/libpam/modules/pam_env/README72
-rwxr-xr-xcontrib/libpam/modules/pam_env/install_conf46
-rw-r--r--contrib/libpam/modules/pam_env/pam_env.c779
-rw-r--r--contrib/libpam/modules/pam_env/pam_env.conf-example72
-rw-r--r--contrib/libpam/modules/pam_filter/Makefile150
-rw-r--r--contrib/libpam/modules/pam_filter/README94
-rw-r--r--contrib/libpam/modules/pam_filter/include/pam_filter.h32
-rw-r--r--contrib/libpam/modules/pam_filter/pam_filter.c747
-rw-r--r--contrib/libpam/modules/pam_filter/upperLOWER/Makefile58
-rw-r--r--contrib/libpam/modules/pam_filter/upperLOWER/upperLOWER.c160
-rw-r--r--contrib/libpam/modules/pam_ftp/Makefile96
-rw-r--r--contrib/libpam/modules/pam_ftp/README20
-rw-r--r--contrib/libpam/modules/pam_ftp/pam_ftp.c295
-rw-r--r--contrib/libpam/modules/pam_group/Makefile114
-rw-r--r--contrib/libpam/modules/pam_group/group.conf60
-rwxr-xr-xcontrib/libpam/modules/pam_group/install_conf46
-rw-r--r--contrib/libpam/modules/pam_group/pam_group.c862
-rw-r--r--contrib/libpam/modules/pam_lastlog/Makefile106
-rw-r--r--contrib/libpam/modules/pam_lastlog/pam_lastlog.c469
-rw-r--r--contrib/libpam/modules/pam_limits/Makefile102
-rw-r--r--contrib/libpam/modules/pam_limits/README87
-rwxr-xr-xcontrib/libpam/modules/pam_limits/install_conf46
-rw-r--r--contrib/libpam/modules/pam_limits/limits.skel41
-rw-r--r--contrib/libpam/modules/pam_limits/pam_limits.c592
-rw-r--r--contrib/libpam/modules/pam_listfile/Makefile84
-rw-r--r--contrib/libpam/modules/pam_listfile/README25
-rw-r--r--contrib/libpam/modules/pam_listfile/pam_listfile.c436
-rw-r--r--contrib/libpam/modules/pam_mail/Makefile107
-rw-r--r--contrib/libpam/modules/pam_mail/pam_mail.c401
-rw-r--r--contrib/libpam/modules/pam_nologin/Makefile86
-rw-r--r--contrib/libpam/modules/pam_nologin/README12
-rw-r--r--contrib/libpam/modules/pam_nologin/pam_nologin.c124
-rw-r--r--contrib/libpam/modules/pam_permit/Makefile126
-rw-r--r--contrib/libpam/modules/pam_permit/README4
-rw-r--r--contrib/libpam/modules/pam_permit/pam_permit.c122
-rw-r--r--contrib/libpam/modules/pam_pwdb/BUGS8
-rw-r--r--contrib/libpam/modules/pam_pwdb/CHANGELOG10
-rw-r--r--contrib/libpam/modules/pam_pwdb/Makefile155
-rw-r--r--contrib/libpam/modules/pam_pwdb/README41
-rw-r--r--contrib/libpam/modules/pam_pwdb/TODO34
-rw-r--r--contrib/libpam/modules/pam_pwdb/bigcrypt.-c114
-rw-r--r--contrib/libpam/modules/pam_pwdb/md5.c259
-rw-r--r--contrib/libpam/modules/pam_pwdb/md5.h30
-rw-r--r--contrib/libpam/modules/pam_pwdb/md5_crypt.c164
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_pwdb.c257
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_unix_acct.-c292
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_unix_auth.-c129
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_unix_md.-c55
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_unix_passwd.-c371
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_unix_pwupd.-c272
-rw-r--r--contrib/libpam/modules/pam_pwdb/pam_unix_sess.-c112
-rw-r--r--contrib/libpam/modules/pam_pwdb/pwdb_chkpwd.c208
-rw-r--r--contrib/libpam/modules/pam_pwdb/support.-c910
-rw-r--r--contrib/libpam/modules/pam_radius/Makefile99
-rw-r--r--contrib/libpam/modules/pam_radius/README58
-rw-r--r--contrib/libpam/modules/pam_radius/pam_radius.c193
-rw-r--r--contrib/libpam/modules/pam_radius/pam_radius.h35
-rw-r--r--contrib/libpam/modules/pam_rhosts/Makefile94
-rw-r--r--contrib/libpam/modules/pam_rhosts/README57
-rw-r--r--contrib/libpam/modules/pam_rhosts/pam_rhosts_auth.c788
-rw-r--r--contrib/libpam/modules/pam_rootok/Makefile111
-rw-r--r--contrib/libpam/modules/pam_rootok/README18
-rw-r--r--contrib/libpam/modules/pam_rootok/pam_rootok.c118
-rw-r--r--contrib/libpam/modules/pam_securetty/Makefile83
-rw-r--r--contrib/libpam/modules/pam_securetty/README9
-rw-r--r--contrib/libpam/modules/pam_securetty/pam_securetty.c204
-rw-r--r--contrib/libpam/modules/pam_shells/Makefile84
-rw-r--r--contrib/libpam/modules/pam_shells/README10
-rw-r--r--contrib/libpam/modules/pam_shells/pam_shells.c131
-rw-r--r--contrib/libpam/modules/pam_stress/Makefile109
-rw-r--r--contrib/libpam/modules/pam_stress/README66
-rw-r--r--contrib/libpam/modules/pam_stress/pam_stress.c581
-rw-r--r--contrib/libpam/modules/pam_tally/Makefile93
-rw-r--r--contrib/libpam/modules/pam_tally/README51
-rw-r--r--contrib/libpam/modules/pam_tally/pam_tally.c634
-rw-r--r--contrib/libpam/modules/pam_time/Makefile121
-rw-r--r--contrib/libpam/modules/pam_time/README37
-rwxr-xr-xcontrib/libpam/modules/pam_time/install_conf46
-rw-r--r--contrib/libpam/modules/pam_time/pam_time.c614
-rw-r--r--contrib/libpam/modules/pam_time/time.conf64
-rw-r--r--contrib/libpam/modules/pam_unix/CHANGELOG6
-rw-r--r--contrib/libpam/modules/pam_unix/Makefile155
-rw-r--r--contrib/libpam/modules/pam_unix/README39
-rw-r--r--contrib/libpam/modules/pam_unix/pam_unix_acct.c117
-rw-r--r--contrib/libpam/modules/pam_unix/pam_unix_auth.c307
-rw-r--r--contrib/libpam/modules/pam_unix/pam_unix_passwd.c813
-rw-r--r--contrib/libpam/modules/pam_unix/pam_unix_sess.c181
-rw-r--r--contrib/libpam/modules/pam_unix/support.c152
-rw-r--r--contrib/libpam/modules/pam_warn/Makefile96
-rw-r--r--contrib/libpam/modules/pam_warn/README23
-rw-r--r--contrib/libpam/modules/pam_warn/pam_warn.c112
-rw-r--r--contrib/libpam/modules/pam_wheel/Makefile94
-rw-r--r--contrib/libpam/modules/pam_wheel/README33
-rw-r--r--contrib/libpam/modules/pam_wheel/pam_wheel.c277
-rwxr-xr-xcontrib/libpam/modules/register_static49
225 files changed, 41922 insertions, 0 deletions
diff --git a/contrib/libpam/CHANGELOG b/contrib/libpam/CHANGELOG
new file mode 100644
index 000000000000..99872a4704c7
--- /dev/null
+++ b/contrib/libpam/CHANGELOG
@@ -0,0 +1,1091 @@
+
+$Id$
+
+-----------------------------
+
+0.66: whenever
+
+TODO
+ - need to supply a backward compatability path for syslog & friends
+ - need to make pam_system_log() thread safe.
+ - need to make logging fix available to non-Linux PAM libraries
+ - need to change modules to make use of new logging API.
+ - document PAM_INCOMPLETE changes
+ - document pam_system_log() changes
+ - verify that the PAM_INCOMPLETE interface is sensible. Can we
+ catch errors? should we permit item changing etc between
+ pam_authenticate re-invocations?
+ - verify that the PAM_INCOMPLETE interface works
+ - add PAM_INCOMPLETE support to modules
+ - verify that
+ - work on RFC.
+
+0.65: Sun Apr 5 22:29:09 PDT 1998 <morgan@linux.kernel.org>
+
+* added event driven programming extensions to libpam
+ - added PAM_INCOMPLETE handling to libpam/pam_dispatch.c
+ - added PAM_CONV_AGAIN which is a new conversation response that
+ should be mapped to PAM_INCOMPLETE by the module.
+ - ensured that the pam_get_user() function can resume
+ - changes to pam_strerror to accommodate above return codes
+ - clean up _pam_former_state at pam_end()
+ - ensured that former state is correctly initialized
+ - added resumption tests to pam_authenticate(), pam_chauthtok()
+ - added PAM_FAIL_DELAY item for pausing on failure
+
+* improved _pam_macros.h so that macros can be used as single commands
+ (Andrey)
+
+* reimplemented logging to avoid bad interactions with libc. Added
+ new functions, pam_[,v]system_log() to libpam's API. A programmer
+ can check for this function's availablility by checking if
+ HAVE_PAM_SYSTEM_LOG is #defined.
+
+* removed the reduce conflict from pam_conv1 creation -- I can sleep
+ again now. :^]
+
+* made building of static and dynamic libpam separate. This is
+ towards making it possible to build both under Solaris (for Derrick)
+
+* made USE_CRACKLIB a condition in unix module (Luke Kenneth Casson Leighton)
+
+* automated (quiet) config installation (Andrey)
+
+0.64: Thu Feb 19 23:30:24 PST 1998 Andrew Morgan <morgan@linux.kernel.org>
+
+* miscellaneous patches for building under Solaris (Derrick J Brashear)
+
+* removed STATIC support from a number of module Makefiles. Notably,
+ these modules are those that use libpwdb and caused difficulties
+ satisfying the build process. (Please submit patches to fix this...;)
+
+* reomved the union for binary packet conversations from
+ (_pam_types.h). This is now completely implemented in libpam_client.
+
+* Andrey's patch for working environment variable handling in
+ sh_secret module.
+
+* made the libpam_misc conversation function a bit more flexible with
+ respect to binary conversations.
+
+* added top level define (DEBUG_REL) for compiling in the form of
+ a debugging release. I use this on a Red Hat 4.2 system with little
+ chance of crashing the system as a whole. (Andrey has another
+ implementation of this -- with a spec file to match..)
+
+0.63: Wed Jan 28 22:55:30 PST 1998 Andrew Morgan <morgan@linux.kernel.org>
+
+* added libpam_client "convention" library. This makes explicit the
+ use of PAM_BINARY_PROMPT. It is a first cut, so don't take it too
+ seriously yet. Comments/suggestions for improvements are very
+ welcome. Note, this library does not compile by default. It will
+ be enabled when it is judged stable. The library comes with two
+ module/agent pairs and can be used with ssh using a patch available
+ from my pre-release directory [where you got this file.]
+
+* backward compatibility patch for libpam/pam_handlers.c (PAM_IGNORE
+ was working with neither "requistie" nor "required") and a DEBUG'ing
+ compile time bug with pam_dispatch.c (Savochkin Andrey Vladimirovich)
+
+* minor Makefile change from (Savochkin Andrey Vladimirovich)
+
+* added pam_afsauth, pam_afspass, pam_restrict, and pam_syslog hooks
+ (Derrick J Brashear)
+
+* pam_access use of uname(2) problematic (security problem
+ highlighted by Olaf Kirch).
+
+* pam_listfile went a bit crazy reading group membersips (problem
+ highlighted by Olaf Kirch and patched independently by Cristian
+ Gafton and Savochkin Andrey Vladimirovich)
+
+* compatibility hooks for solaris and hpux (Derrick J Brashear)
+
+* 64 bit Linux/alpha bug fixed in pam_rhosts (Andrew D. Isaacson)
+
+0.62: Wed Jan 14 14:10:55 PST 1998 Andrew Morgan <morgan@linux.kernel.org>
+
+* Derrick J Brashear's patches: adds the HP stuff missed in the first
+ patch; adds SunOS support; adds support for the Solaris native ld
+ instead of requiring gnu ld.
+
+* last line of .rhosts file need not contain a newline. (Bug reported by
+ Thompson Freeman.)
+
+0.61: Thu Jan 8 22:57:44 PST 1998 Andrew Morgan <morgan@linux.kernel.org>
+
+* complete rewrite of the "control flag" logic. Formerly, we were
+ limited to four flags: requisite, required, sufficient, optional.
+ We can now use these keywords _and_ a great deal more besides.
+ The extra logic was inspired by Vipin Samar, a preliminary patch was
+ written by Andy Berkheimer, but I "had some ideas of my own" and
+ that's what I've actually included. The basic idea is to allow the
+ admin to custom build a control flag with a series of token=value
+ pairs inside square brackets. Eg., '[default=die success=ok]' which
+ is pretty close to a synonym for 'requisite'. I'll try to document it
+ better in the sys-admin guide but I'm pretty sure it is a change for
+ the better.... If what is in the sys-admin guide is not good enough
+ for you, just take a look at the source for libpam ;^)
+
+0.59: Thu Jan 8 22:27:22 PST 1998 Andrew Morgan <morgan@linux.kernel.org>
+
+* better handling of empty lines in .rhosts file. (Formerly, we asked
+ the nameserver about them!) Fix from Hugh Daschbach.
+
+* _broke_some_binary_compatibility_ with previous versions to become
+ compliant with X/Open's XSSO spec. Specifically, this has been
+ by changing the prototype for pam_strerror().
+
+* altered the convention for the conversation mechanism to agree
+ with that of Sun. (number of responses 'now=' number of messages
+ with help from Cristian for finding a bug.. Cristian also found a
+ nasty speradic segfault bug -- Thanks!)
+
+* added NIS+ support to pam_unix_*
+
+* fixed a "regular file checking" problem with the ~/.rhosts sanity
+ check. Added "privategroup" option to permit group write permission
+ on the ~/.rhosts file in the case that the group owner has the same
+ name as the authenticating user. :*) "promiscuous" and "suppress"
+ were not usable!
+
+* added glibc compatibility to pam_rhosts_auth (protected __USE_MISC
+ with #ifndef since my libc already defines it!).
+
+* Security fix from Savochkin Andrey Vladimirovich with suggested
+ modification from Olaf Seibert.
+
+* preC contains mostly code clean-ups and a number of changes to
+ _pam_macros.
+
+0.58: whenever
+
+* pam_getenvlist() has a more robust definition (XSSO) than was previously
+ thought. It would seem that we no longer need pam_misc_copy_env()
+ which was there to provide the robustness that pam_getenvlist()
+ lacked before...
+
+ Accordingly, I have REMOVED the prototype from libpam_misc. (The
+ function, however, will remain in the library as a wrapper for
+ legacy apps, but will likely be removed from libpam_misc-1.0.) PLEASE
+ FIX YOUR APPS *BEFORE* WE GET THERE!
+
+* Alexy Nogin reported garbage output from pam_env in the case of
+ a non-existent environment variable.
+
+* 'fixed' pwdb compilation for pam_wheel. Not very cleanly
+ done.. Mmmm. Should really clean up the entire source tree...
+
+* added prototypes for mapping functions
+
+ <**WARNING**>
+
+ various constants have had there names changed. Numerical values have
+ been retained but be aware some source old modules/applications will
+ need to be fixed before recompilation.
+
+ </**WARNING**>
+
+* appended documentation to README for pam_rhosts module (Nicolai
+ Langfeldt).
+
+* verified X/Open compatibility of header files - note, where we differ
+ it is at the level of compilation warnings and the use of 'const char *'
+ instead of 'char *'. Previously, Sun(X/open) have revised their spec
+ to be more 'const'-ervative in the light of comments from Linux-PAM
+ development.
+
+* Ooops! PAM_AUTHTOKEN_REQD should have been PAM_NEW_AUTHTOK_REQD.
+
+ changed: pam_pwdb(pam_unix_acct) (also bug fix for
+ _shadow_acct_mgmt_exp() return value), pam_stress,
+ libpam/pam_dispatch, blank, xsh.
+
+* New: PAM_AUTHTOK_EXPIRED - password has expired.
+
+* Ooops! PAM_CRED_ESTABLISH (etc.) should have been PAM_ESTABLISH_CRED
+ etc... (changed - this may break some people's modules - PLEASE TAKE
+ NOTE!)
+ changed: pam_group, pam_mail, blank, xsh; module and appl
+ docs, pam_setcred manual page.
+
+* renamed internal _pam_handle structure to be pam_handle as per XSSO.
+
+* added PAM_RADIO_TYPE (for multiple choice input method). Also
+ added PAM_BINARY_{MSG,PROMPT} (for interaction out of sight of user
+ - this could be used for RSA type authentication but is currently
+ just there for experimental purposes). The _BINARY_ types are now
+ usable with hooks in the libpam_misc conversation function. Still
+ have to add PAM_RADIO_TYPE.
+
+* added pam_access module (Alexei Nogin)
+
+* added documentation for pam_lastlog. Also modified the module to
+ not (by default) print "welcome to your new account" when it cannot
+ find a utmp entry for the user (you can turn this on with the
+ "never" argument).
+
+* small correction to the pam_fail_delay manual page. Either the appl or
+ the modules header file will prototype this function.
+
+* added "bigcrypt" (DEC's C2) algorithm(0) to pam_pwdb. (Andy Phillips)
+
+* *BSD tweaking for various #include's etc. (pam_lastlog, pam_rhosts,
+ pam_wheel, libpam/pam_handlers). (Michael Smith)
+
+* added configuration directory $SCONFIGED for module specific
+ configuration files.
+
+* added two new "linked" man pages (pam.conf(8) and pam.d(8))
+
+* included a reasonable default for /etc/pam.conf (which can be
+ translated to /etc/pam.d/* files with the pam_conv1 binary)
+
+* fixed the names of the new configuration files in
+ conf/pam_conv1/pam_conv.y
+
+* fixed make check.
+
+* pam_lastlog fixed to handle UID in virgin part of /var/log/lastlog
+ (bug report from Ronald Wahl).
+
+* grammar fix in pam_cracklib
+
+* segfault avoided in pam_pwdb (getting user). Updating of passwords
+ that are directed to a "new" database are more robust now (bug noted
+ by Michael K. Johnson). Added "unix" module argument for migrating
+ passwords from another database to /etc/passwd. (documentation
+ updated). Removed "bad username []" warning for empty passwords -
+ on again if you supply the 'debug' module argument.
+
+* ctrl-D respected in conversation function (libpam_misc)
+
+* Removed -DPAM_FAIL_DELAY_ON from top-level Makefile. Nothing in
+ the distribution uses it. I guess this change happened a while
+ back, basically I'm trying to make the module parts of the
+ distribution "source compatible" with the RFC definition of PAM.
+ This implementation of PAM is a superset of that definition. I have
+ added the following symbols to the Linux-PAM header files:
+
+ PAM_DATA_SILENT (see _pam_types.h)
+ HAVE_PAM_FAIL_DELAY (see _pam_types.h)
+ PAM_DATA_REPLACE (see _pam_modules.h)
+
+ Any module (or application) that wants to utilize these features,
+ should check (#ifdef) for these tokens before using the associated
+ functionality. (Credit to Michael K. Johnson for pointing out my
+ earlier omission: not documenting this change :*)
+
+* first stab at making modules more independent of full library
+ source. Modules converted:
+ pam_deny
+ pam_permit
+ pam_lastlog
+ pam_pwdb
+
+* pam_env.c: #include <errno.h> added to ease GNU libc use. (Michael
+ K. Johnson)
+
+* pam_unix_passwd fixes to shadow aging code (Eliot Frank)
+
+* added README for pam_tally
+
+0.57: Fri Apr 4 23:00:45 PST 1997 Andrew Morgan <morgan@parc.power.net>
+
+* added "nodelay" argument to pam_pwdb. This can be used to turn off
+ the call to pam_fail_delay that takes effect when the user fails to
+ authenticate themself.
+
+* added "suppress" argument to pam_rhosts_auth module. This will stop
+ printing the "rlogin failure message" when the user does not have a
+ .rhosts file.
+
+* Extra fixes for FAKEROOT in Makefiles (Savochkin Andrey
+ Vladimirovich)
+
+* pam_tally added to tree courtesy of Tim Baverstock
+
+* pam_rhosts_auth was failing to read NFS mounted .rhosts
+ files. (Fixed by Peter Allgeyer). Refixed and further enhanced
+ (netgroups) by Nicolai Langfeldt. [Credit also to G.Wilford for some
+ changes that were not actually included..]
+
+* optional (#ifdef PAM_READ_BOTH_CONFS) support for parsing of pam.d/
+ AND pam.conf files (Elliot Lee).
+
+* Added (and signed) Cristian's PGP key. (I've never met him, but I am
+ convinced the key belongs to the guy that is making the PAM rpms and
+ also producing libpwdb. Please note, I will not be signing anyone
+ else's key without a personal introduction..)
+
+* fixed erroneous syslog warning in pam_listfile (Savochkin Andrey
+ Vladimirovich, whole file reformatted by Cristian)
+
+* modified pam_securetty to return PAM_IGNORE in the case that the user's
+ name is not known to the system (was previously, PAM_USER_UNKNOWN). The
+ Rationale is that pam_securetty's sole purpose is to prevent superuser
+ login anywhere other than at the console. It is not its concern that the
+ user is unknown - only that they are _not_ root. Returning
+ PAM_IGNORE, however, insures that the pam_securetty can never be used to
+ "authenticate" a non-existent user. (Cristian Gafton with bug report from
+ Roger Hu)
+
+* Modified pam_nologin to display the no-login message when the user
+ is not known. The return value in this case is still PAM_USER_UNKNOWN.
+ (Bug report from Cristian Gafton)
+
+* Added NEED_LCKPWD for pam_unix/ This is used to define the locking
+ functions and should only be turned on if you don't have them in
+ your libc.
+
+* tidied up pam_lastlog and pam_pwdb: removed function that was never used.
+
+* Note for package maintainers: I have added $(FAKEROOT) to the list of
+ environment variables. This should help greatly when you build PAM
+ in a subdirectory. I've gone through the tree and tried to make
+ everything compatible with it.
+
+* added pam_env (courtesy of Dave Kinchlea)
+
+* removed pam_passwd+ from the tree. It has not been maintained in a
+ long time and running a shell script was basically insecure. I've
+ indicated where you can pick up the source if you want it.
+
+* #define HAVE_PAM_FAIL_DELAY . Applications can conditionally compile
+ with this if they want to see if the facility is available. It is
+ now always available. (corresponding compilation cleanups..)
+
+* _pam_sanitize() added to pam_misc. It purges the PAM_AUTHTOK and
+ PAM_OLDAUTHTOK items. (calls replaced in pam_auth and pam_password)
+
+* pam_rhosts now knows about the '+' entry. Since I think this is a
+ dangerous thing, I have required that the sysadmin supply the
+ "promiscuous" flag for it in the corresponding configuration file
+ before it will work.
+
+* FULL_LINUX_PAM_SOURCE_TREE exported from the top level make file.
+ If you want to build a module, you can test for this to determine if
+ it should take its directions from above or supply default locations
+ for installation. Etc.
+
+0.56: Sat Feb 15 12:21:01 PST 1997 <morgan@parc.power.net>
+
+* pam_handlers.c can now interpret the pam.d/ service config tree:
+ - if /etc/pam.d/ exists /etc/pam.conf is IGNORED
+ (otherwise /etc/pam.conf is treated as before)
+ - given /etc/pam.d/
+ . config files are named (in lower case) by service-name
+ . config files have same syntax as /etc/pam.conf except
+ that the "service-name" field is not present. (there
+ are thus three manditory fields (and arguments are
+ optional):
+
+ module-type control-flag module-path optional-args...
+
+ )
+
+* included conf/pam_conv1 for converting pam.conf to a pam.d/ version
+ 1.0 directory tree. This program reads a pam.conf file on the
+ standard input stream and creates ./pam.d/ (in the local directory)
+ and fills it with ./pam.d/"service-name" files.
+
+ *> Note: It will fail if ./pam.d/ already exists.
+
+ PLEASE REPORT ANY BUGS WITH THIS CONVERSION PROGRAM... It currently
+ cannot retain comments from the old conf file, so take care to do this
+ by hand. Also, please email me with the fix that makes the
+ shift/reduce conflict go away...
+
+* Added default module path to libpam for modules (see pam_handlers.c)
+ it makes use of Makfile defined symbol: DEFAULT_MODULE_PATH which is
+ inhereted from the defs/* variable $(SECUREDIR). Removed module
+ paths from the sample pam.conf file as they are no longer needed.
+
+* pam_pwdb can now verify read protected passwords when it is not run
+ by root. This is via a helper binary that is setuid root.
+
+* pam_permit now prompts for a username if it is not already determined
+
+* pam_rhosts now honors "debug" and no longer hardwire's "root" as the
+ superuser's name.
+
+* pam_securetty now honors the "debug" flag
+
+* trouble parsing extra spaces fixed in pam_time and pam_group
+
+* added Michael K. Johnson's PGP key to the pgp.keys.asc list
+
+* pam_end->env not being free()'d: fixed
+
+* manuals relocated to section 3
+
+* fixed bug in pam_mail.c, and enhanced to recognize '~' as a prefix
+ to indicate the $HOME of the user (courtesy David
+ Kinchlea). *Changed* from a "session" module to an "auth"
+ module. It cannot be used to authenticate a user, but it can be used
+ in setting credentials.
+
+* fixed a stupid bug in pam_warn.. Only PAM_SERVICE was being read :*(
+
+* pam_radius rewritten to exclusively make use of libpwdb. (minor fix
+ to Makefile for cleaning up - AGM)
+
+* pam_limits extended to limit the total number of logins on a system
+ at any given time.
+
+* libpam and libpam_misc use $(MAJOR_REL) and $(MINOR_REL) to set their
+ version numbers [defined in top level makefile]
+
+* bugfix in sed command in defs/redhat.defs (AGM's fault)
+
+* The following was related to a possibility of buffer overruns in
+ the syslogging code: removed fixed length array from syslogging
+ function in the following modules [capitalized the log identifier
+ so the sysadmin can "know" these are fixed on the local system],
+
+ pam_ftp, pam_stress, pam_rootok, pam_securetty,
+ pam_listfile, pam_shells, pam_warn, pam_lastlog
+ and
+ pam_unix_passwd (where it was definitely _not_ exploitable)
+
+0.55: Sat Jan 4 14:43:02 PST 1997, Andrew Morgan <morgan@parc.power.net>
+
+* added "requisite" control_flag to /etc/pam.conf syntax. [See
+ Sys. Admin. Guide for explanation] changes to pam_handlers.c
+
+* completely new handling of garbled pam.conf lines. The modus
+ operandi now is to assume that any errors in the line are minor.
+ Errors of this sort should *most definitely* lead to the module
+ failing, however, just ignoring the line (as was the case
+ previously) can lead to gaping security holes(! Not foreseen by the
+ RFC). The "motivation" for the RFC's comments about ignoring garbled
+ lines is present in spirit in the new code: basically a garbled line
+ is treated like an instance of the pam_deny.so module.
+ changes to pam_handlers.c and pam_dispatch.c .
+
+* patched libpam, to (a) call _pam_init_handlers from pam_start() and
+ (b) to log a text error if there are no modules defined for a given
+ service when a call to a module is requested. [pam_start() and
+ pam_dispatch() were changed].
+
+* patched pam_securetty to deal with "/dev/" prefix on PAM_TTY item.
+
+* reorganized the modules/Makefile to include *ALL* modules. It is now
+ the responsibility of the modules themselves to test whether they can
+ be compiled locally or not.
+
+* modified pam_group to add to the getgroups() list rather than overwrite
+ it. [In the case of "HAVE_LIBPWDB" we use the pwdb_..() calls to
+ translate the group names.]. Module now pays attention to
+ PAM_CRED_.. flag(!)
+
+* identified and removed bugs in field reading code of pam_time and
+ (thus) pam_group.
+
+* Cristian's patches to pam_listfile module, corresponding change to
+ documentation.
+
+* I've discovered &ero; for sgml!
+ Added pam_time documentation to the admin guide.
+
+* added manual pages: pam.8, pam_start.2(=pam_end.2),
+ pam_authenticate.2, pam_setcred.2, pam_strerror.2,
+ pam_open_session.2(=pam_close_session.2) and pam_chauthtok.2 .
+
+* added new modules:
+
+ - pam_mail (tells the user if they have any new mail
+ and sets their MAIL env variable)
+ - pam_lastlog (reports on the last time this user called
+ this module)
+
+* new module hooks provided.
+
+* added a timeout feature to the conversation function in
+ libpam_misc. Documented it in the application developers' guide.
+
+* fixed bug in pam_misc_paste_env() function..
+
+* slight modifications to wheel and rhosts writeup.
+
+* more security issues added to module and application guides.
+
+--
+Things present but not mentioned in previous release (sorry)
+
+* pam_pwdb module now resets the "last_change" entry before updating a
+ password.
+--
+
+Sat Nov 30 19:30:20 PST 1996, Andrew Morgan <morgan@parc.power.net>
+
+* added environment handling to libpam. involved change to _pam_types.h
+ also added supplementary functions to libpam_misc
+
+* added pam_radius - Cristian
+
+* slight speed up for pam_rhosts
+
+* significantly enhanced sys-admin documentation (8 p -> 41 p in
+ PostScript). Added to other documentation too. Mostly the changes
+ in the other docs concern the new PAM-environment support, there is
+ also some coverage of libpam_misc in the App. Developers' guide.
+
+* Cristian's patches to pam_limits and pam_pwdb. Fixing bugs. (MORE added)
+
+* adopted Cristian's _pam_macros.h file to help with common macros and
+ debugging stuff, gone through tree tidying up debugging lines to use
+ this [not complete].
+
+ - for consistency replaced DROP() with _pam_drop()
+
+* commented memory debugging in top level makefile
+
+* added the following modules
+
+ - pam_warn log information to syslog(3) about service application
+ - pam_ftp if user is 'ftp' then set PAM_RUSER/PAM_RHOST with password
+ (comment about nologin added to last release's notes)
+
+* modified the pam_listfile module. It now declares a meaningful static
+ structure name.
+
+Sun Nov 10 13:26:39 PST 1996, Andrew Morgan <morgan@parc.power.net>
+
+ **PLEASE *RE*AMEND YOUR PERSONAL LINKS**
+
+ -------> http://parc.power.net/morgan/Linux-PAM/index.html <-------
+
+ **PLEASE *RE*AMEND YOUR PERSONAL LINKS**
+
+A brief summary of what has changed:
+
+* many modules have been modified to accomodate fixing the pam_get_user()
+ change. Please take note if you have a module in this distribution.
+
+* pam_unix is now the pam_unix that Red Hat has been using and which
+ should be fairly well debugged.
+
+ - I've added some #ifdef's to make it compile for me, and also
+ updated it with respect to the libpam-0.53, so have a look at the
+ .../modules/pam_unix/Makefile to enable cracklib and shadow features
+
+ ** BECAUSE OF THIS, I cannot guarantee this code works as it **
+ ** did for Red Hat. Please test and report any problems. **
+
+* the pam_unix of .52 (renamed to pam_pwdb) has been enhanced and made
+ more flexible with by implementing it with respect to the new
+ "Password Database Library" see
+
+ http://parc.power.net/morgan/libpwdb/index.html
+
+ modules included in this release that require this library to
+ function are the following:
+
+ - pam_pwdb (ne pam_unix-0.52 + some enhancements)
+ - pam_wheel
+ - pam_limits
+ - pam_nologin
+
+* Added some optional code for memory debugging. In order to support
+ this you have to enable MEMORY_DEBUG in the top level makefile and
+ also #define MEMORY_DEBUG in your applications when they are compiled.
+ The extra code resides in libpam (compiled if MEMORY_DEBUG is defined)
+ and the macros for malloc etc. are to be found at the end of
+ _pam_types.h
+
+* used above code to locate two memory leaks in pam_unix module and two
+ in libpam (pam_handlers.h)
+
+* pam_get_user() now sets the PAM_USER item. After reading the Sun
+ manual page again, it was clear that it should do this. Various
+ modules have been assuming this and now I have modified most of them
+ to account for this change. Additionally, pam_get_user() is now
+ located in the module include file; modules are supposed to be the
+ ones that use it(!) [Note, this is explicitly contrary to the Sun
+ manual page, but in the spirit of the Linux distribution to date.]
+
+* replaced -D"LINUX" with -D"LINUX_PAM" as this is more explicit and less
+ likely to be confused with -D"linux".
+ Also, modified the libpam #include files to behave more like the Sun
+ ones #ifndef LINUX_PAM.
+
+* removed <bf/ .. / from documentation titles. This was not giving
+ politically correct html..
+
+----- My vvvvvvvvvvvvvvvvvvv was a long time ago ;*] -----
+
+Wed Sep 4 23:57:19 PDT 1996 (Andrew Morgan <morgan@physics.ucla.edu>
+
+0. Before I begin, Linux-PAM has a new primary distribution site (kindly
+donated by Power Net Inc., Los Angeles)
+
+ **PLEASE AMMEND YOUR PERSONAL LINKS**
+
+ -------> http://www.power.net/morgan/Linux-PAM <-------
+
+ **PLEASE AMMEND YOUR PERSONAL LINKS**
+
+1. I'm hoping to make the next release a bug-fix release... So please find
+ all the bugs(! ;^)
+
+2. here are the changes for .52:
+
+* minor changes to module documentation [Incidently, it is now
+ available on-line from the WWW page above]. More changes to follow in
+ the next two releases. PLEASE EMAIL me or the list if there is
+ anything that isn't clear!
+
+* completely changed the unix module. Now a single module for all four
+ management groups (this meant that I could define all functions as
+ static that were not part of the pam_sm_... scheme. AGM)
+
+ - Shadow support added
+PASSWD - Elliot's account management included, and enhanced by Cristian Gafton.
+ - MD5 password support added by Cristian Gafton.
+ - maxtries for authentication now enforced.
+ - Password changing function in pam_unix now works!
+ Although obviously, I'm not going to *guarantee* it ;^) .
+ - stole Marek's locking code from the Red Hat unix module.
+ [ If you like you can #ifdef it in or out ... ]
+
+ You can configure the module more from its Makefile in
+ 0.52/modules/pam_unix/
+
+ If you are nervous that it will destroy your /etc/passwd or shadow
+ files then EDIT the 0.52/modules/pam_unix/pam_unix_pass.-c file.
+ Here is the warning comment from this file...
+
+-------------8<-----------------
+/* <WARNING>
+ *
+ * Uncomment the following #define if you are paranoid, and do not
+ * want to risk losing your /etc/passwd or shadow files.
+ * It works for me (AGM) but there are no guarantees.
+ *
+ * </WARNING>
+ */
+/* #define TMP__FILE */
+------------->8-----------------
+
+ *** If anyone has any trouble, please *say*. Your problem will be
+ fixed in the next release. Also please feel free to scour the
+ code for race conditions etc...
+
+[* The above change requires that you purge your /usr/lib/security
+ directory of the old pam_unix_XXX.so modules: they will NOT be deleted
+ with a 'make remove'.]
+
+* the prototype for the cleanup function supplied to pam_set_data used
+ to return "int". According to Sun it should be "void". CHANGED.
+
+* added some definitions for the 'error_status' mask values that are
+ passed to the cleanup function associated with each
+ module-data-item. These numbers were needed to keep up with changing
+ a data item (see for example the code in pam_unix/support.-c that
+ manages the maximum number of retries so far). Will see what Sun says
+ (current indications are positive); this may be undone before 1.0 is
+ released. Here are the definitions (from pam_modules.h).
+
+#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */
+#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */
+
+* Changed the .../conf/pam.conf file. It now points to the new
+ pam_unix module for 'su' and 'passwd' [can get these as SimpleApps --
+ I use them for testing. A more extensive selection of applications is
+ available from Red Hat...]
+
+* corrected a bug in pam_dispatch. Basically, the problem was that if
+ all the modules were "sufficient" then the return value for this
+ function was never set. The net effect was that _pam_dispatch_aux
+ returned success when all the sufficient modules failed. :^( I think
+ this is the correct fix to a problem that the Red Hat folks had
+ found...
+
+sopwith* Removed advisory locking from libpam (thanks for the POSIX patch
+ goes to Josh Wilmes's, my apologies for not using it in the
+ end.). Advisory locking did not seem sufficiently secure for libpam.
+ Thanks to Werner Almesberger for identifying the corresponding "denial
+ of service attack". :*(
+
+* related to fix, have introduced a lock file /var/lock/subsys/PAM
+ that can be used to indicate the system should pay attention to
+ advisory locking on /etc/pam.conf file. To implement this you need to
+ define PAM_LOCKING though. (see .52/libpam)
+
+* modified pam_fail_delay() function. Couldn't find the "not working"
+ problem indicated by Michael, but modified it to do pseudo-random
+ delays based on the values indicated by pam_fail_delay() -- the
+ function "that may eventually go away"... Although Sun is warming to
+ the idea.
+
+* new modules include:
+
+ pam_shells - authentication for users with a shell listed in
+ /etc/shells. Erik Troan <ewt@redhat.com>
+
+ pam_listfile - authentication based on the contents of files.
+ Set to be more general than the above in the
+ future. UNTESTED. Elliot Lee <@redhat.com>
+ [Note, this module compiles with a non-trivial
+ warning: AGM]
+
+Thu Aug 8 22:32:15 PDT 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* modified makefiles to take more of their installation instructions
+ from the top level makefile. Desired for integration into the Debian
+ distribution, and generally a good idea.
+
+* fixed memory arithmetic in pam_handlers
+ -- still need to track down why failure to load modules can lead to
+ authentication succeding..
+
+* added tags for new modules (smartcards from Alex -- just a promise
+ at this stage) and a new module from Elliot Lee; pam_securetty
+
+* I have not had time to smooth out the wrinkles with it, but Alex's
+ pam_unix modifications are provided in pam_unix-alex (in the modules
+ directory) they will not be compiled by 'make all' and I can't even
+ say if they do compile... I will try to look at them for .52 but, in
+ the mean time please feel free to study/fix/discuss what is there.
+
+* pam_rhosts module. Removed code for manually setting the ruser
+ etc. This was not very secure.
+
+* [remade .ps docs to be in letter format -- my printer complains
+ about a4]
+
+Sunday July, 7 12:45:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* No longer accompanying the Linux-PAM release with apps installed.
+ [Will provide what was here in a separate package.. (soon)
+lib Also see http://www.redhat.com/pam for some more (in .rpm form...)]
+
+* renamed libmisc to libpam_misc. It is currently configured to only compile
+ the static library. For some strange reason (perhaps someone can
+ investigate) my Linux 2.0.0 kernel with RedHat 3.0.3 system
+ segfaults when I compile it to be a dynamic library. The segfault
+ seems to be inside the call to the ** dl_XXX ** function...!?
+
+ There is a simple flag in the libpam_misc/Makefile to turn on dynamic
+ compiles.
+
+* Added a little unofficial code for delay support in libpam (will probably
+ disappear later..) There is some documentation for it in the pam_modules
+ doc now. That will obviously go too.
+
+* rewritten pam_time to use *logic* to specify the stringing together of
+ users/times/terminals etc.. (what was there before was superficially
+ logical but basically un-predictable!)
+
+* added pam_group. Its syntax is almost identical to pam_time but it
+ has another field added; a list of groups to make the user a member
+ of if they pass the previous tests. It seems to not co-exist too well
+ with the groups in the /etc/group but I hope to have that fixed by
+ the next release...
+
+* minor re-formatting of pam_modules documentation
+
+* removed ...// since it wasn't being used and didn't look like it
+ would be!
+
+GCCSunday 23 22:35:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* The major change is the addition of a new module: pam_time for
+ restricting access on terminals at given times for indicated users
+ it comes with its own configuration file /etc/security/time.conf
+ and the sample file simply restricts 'you' from satisfying the blank
+ application if they try to use blank from any tty*
+
+* Small changes include
+- altered pam.conf to demonstrate above new module (try typing username: you)
+- very minor changes to the docs (pam_appl and pam_modules)
+
+Saturday June 2 01:40:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+*** PLEASE READ THE README, it has changed ***
+
+* NOTE, 'su' exhibits a "system error", when static linking is
+ used. This is because the pam_unix_... module currently only has
+ partial static linking support. This is likely to change on Monday
+ June 3, when Alex makes his latest version availible. I will include
+ the updated module in next release.
+
+changes for .42:
+
+* modified the way in which libpam/pam_modules.h defines prototypes for
+ the pam_sm_ functions. Now the module must declare which functions it
+ is to provide *before* the #include <security/pam_modules.h> line.
+ (for contrasting examples, see the pam_deny and pam_rootok modules)
+ This removed the ugly hack of defining functions that are never called
+ to overcome warnings... This seems much tidier.
+insterted* updated the TODO list. (changed mailing list address)
+* updated README in .../modules to reflect modifications to static
+ compliation protocol
+* modified the pam_modules documentation to describe this.
+* corrected last argument of pam_get_item( ... ) in
+ pam_appl/modules.sgml, to "const void **".
+* altered GNU GPL's in the documentation, and various other parts of
+ the distribution. *Please check* that any code you are responsible for
+ is corrected.
+* Added ./Copyright (please check that it is acceptable)
+* updated ./README to make current and indicate the new mailing list
+ address
+* have completely rewritten pam_filter. It now runs modular filter
+ executables (stored in /usr/sbin/pam_filter/) This should make it
+ trivial for others to write their own filters.. If you want yours
+ included in the distribution please email the list/me.
+* changes to libpam; there was a silly bug with multiple arguments on a
+ pam.conf line that was broken with a '\<LF>'.
+* 'su' rearranged code (to make better use of PAM)
+ *Also* now uses POSIX signals--this should help the Alpha port.
+* 'passwd' now uses getlogin() to determine who's passwords to change.
+
+Sunday May 26 9:00:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* fixed module makefiles to create needed dynamic/static subdirectories
+
+Saturday May 25 20:30:27.8 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* LOTS has changed regarding how the modules/libpam are built.
+* Michael's mostly complete changes for static support--see below
+ (Andrew got a little carried away and automated the static linking
+ of modules---bugs are likely mine ;( )
+* Thanks mostly to Michael, libpam now compiles without a single warning :^]
+* made static modules/library optional.
+CFLAGS* added 'make sterile' to top level makefile. This does extraclean and remove
+* added Michael and Joseph to documentation credits (and a subsection for
+ future documentation of static module support in pam_modules.sgml)
+* libpam; many changes to makefiles and also automated the inclusion of
+ static module objects in pam_static.c
+* modified modules for automated static/dynamic support. Added static &
+ dynamic subdirectories, as instructed by Michael
+* removed an annoying syslog message from pam_filter: "parent exited.."
+* updated todo list (anyone know anything about svgalib/X? we probably should
+ have some support for these...)
+
+Friday May 24 16:30:15 EDT 1996 (Michael K. Johnson <johnsonm@redhat.com>)
+
+* Added first (incomplete) cut at static support.
+ This includes:
+ . changes in libpam, including a new file, pam_static.c
+ . changes to modules including exporting struct of function pointers
+ . static and dynamic linking can be combined
+ . right now, the only working combinations are just dynamic
+ linking and dynamic libpam.so with static modules linked
+ into libpam.so. That's on the list of things to fix...
+ . modules are built differently depending on whether they
+ are static or dynamic. Therefore, there are two directories
+ under each module directory, one for static, and one for
+ dynamic modules.
+* Fixed random brokenness in the Makefiles. [ foo -nt bar ] is
+ rather redundant in a makefile, for instance. Also, passing
+ on the command line is broken because it cannot be
+ overridden in any way (even adding important parts) in lower-level
+ makefiles.
+* Unfortunately, fixing some of the brokenness meant that I used
+ GNU-specific stuff. However, I *think* that there was GNU-specific
+ stuff already. And I think that we should just use the GNU
+ extensions, because any platform that GNU make doesn't port to
+ easily will be hard to port to anyway. It also won't be likely
+passwd to handle autoconf, which was Ted's suggestion for getting
+ around limitations in standard make...
+ For now, I suggest that we just use some simple GNU-specific
+ extensions.
+
+Monday May 20 22:00:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* added some text to pam_modules.sgml
+* corrected Marek's name in all documentation
+* made pam_stress conform to chauthtok conventions -- ie can now request
+ old password before proceeding.
+* included Alex's latest unix module
+* included Al's + password strength checking module
+* included pam_rootok module
+* fixed too many bugs in libpam.. all subtly related to the argument lists
+ or use of syslog. Added more debugging lines here too.
+* fixed the pam.conf file
+* deleted pam_test module. It is pretty old and basically superceeded
+ by pam_stress
+
+Friday May 9 1:00:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* updated documentaion, added Al Longyear to credits and corrected the
+ spelling of Jeff's name(!). Most changes to pam.sgml (even added a figure!)
+* new module pam_rhosts_auth (from Al Longyear)
+* new apps rlogind and ftpd (a patch) from Al.
+* modified 'passwd' to not call pam_authenticate (note, none of the
+ modules respect this convention yet!)
+* fixed bug in libpam that caused trouble if the last line of a
+ pam.conf file ends with a module name and no newline character
+* also made more compatable with documentation, in that bad lines in
+ pam.conf are now ignored rather than causing libpam to return an
+ error to the app.
+* libpam now overwrites the AUTHTOKs when returning from
+ pam_authenticate and pam_chauthtok calls (as per Sun/RFC too)
+* libpam is now installed as libpam.so.XXX in a way that ldconfig can
+ handle!
+
+
+Wednesday May 1 22:00:00 PST 1996 (Andrew Morgan <morgan@physics.ucla.edu>)
+
+* removed .../test directory, use .../examples from now on.
+* added .../apps directory for fully functional applications
+ - the apps directory contains directories that actually contain the apps.
+ the idea is to make application compilation conditional on the presence
+ of the directory. Note, there are entries in the Makefile for
+ 'login' and 'ftpd' that are ready for installation... Email me if
+ you want to reserve a directory name for an application you are
+ working on...
+* similar changes to .../modules makefile [entries for pam_skey and
+ pam_kerberos created---awaiting the directories.] Email me if you
+ want to register another module...
+* minor changes to docs.. Not really worth reprinting them quite yet!
+ [save the trees]
+* added misc_conv to libmisc. it is a generic conversation function
+ for text based applications. [would be nice to see someone create
+ an Xlib and/or svgalib version]
+* fixed ctrl-z/c bug with pam_filter module [try xsh with the default
+ pam.conf file]
+* added 'required' argument to 'pam_stress' module.
+* added a TODO list... other suggestions to the list please.
+
+Saturday April 7 00:00:00 PST 1996 ( Andrew Morgan <morgan@physics.ucla.edu> )
+
+* Alex and Marek please note I have altered _pam_auth_unix a little, to
+ make it get the passwords with the "proper method" (and also fixed it
+ to not have as many compiler warnings)
+* updated the conf/pam.conf file
+* added new example application examples/xsh.c (like blank but invokes
+ /bin/sh)
+* Marc's patches for examples/blank.c (and AGM's too)
+* fixed stacking of modules in libpam/pam_handlers.c
+* fixed RESETing in libpam/pam_item.c
+* added new module modules/pam_filter/ to demonstrate the possibility
+ of inserting an arbitrary filter between the terminal and the
+ application that could do customized logging etc... (see use of
+ bin/xsh as defined in conf/pam.conf)
+
+
+Saturday March 16 19:00:00 PST 1996 ( Andrew Morgan <morgan@physics.ucla.edu> )
+
+These notes are for 0.3 I don't think I've left anything important
+out, but I will use emacs 'C-x v a' next time! (Thanks Jeff)
+
+ * not much has changed with the functionality of the Linux-PAM lib
+ .../libpam
+ - pam_password calls module twice with different arguments
+ - added const to some of the function arguments
+ - added PAM_MAX_MES_ to <security/_pam_types.h>
+ - was a lot over zealous about purging old passwords...
+ I have removed much of this from source to make it
+ more compatible with SUN.
+ - moved some PAM_... tokens to pam_modules.h from _pam_types.h
+ (no-one should notice)
+
+ * added three modules: pam_permit pam_deny pam_stress
+ no prizes for guessing what the first two do. The third is
+ a reasonably complete (functional) module. Is intended for testing
+ applications with.
+
+ * fixed a few pieces of examples/blank.c so that it works (with
+ pam_stress)
+
+ * ammended the documentation. Looking better, but suggestions/comments
+ very welcome!
+
+Sunday March 10 10:50:00 PST 1996 ( Andrew Morgan <morgan@physics.ucla.edu> )
+
+These notes are for Linux-PAM release 0.21. They cover what's changed
+since I relased 0.2.
+
+ * am now using RCS
+ * substantially changed ./README
+ * fixed bug reading \\\n in pam.conf file
+ * small changes to documentation
+ * added `blank' application to ./examples (could be viewed as
+ a `Linux-PAM aware' application template.)
+ * oops. now including pam_passwd.o and pam_session.o in pamlib.so
+ * compute md5 checksums for all the source when making a release
+ - added `make check' and `make RCScheck' to compute md5 checksums
+ * create a second tar file with all the RCS files in.
+ * removed the .html and .txt docs, supplying sgml sources instead.
+ - see README for info on where to get .ps files
+
+Thursday March 6 0:44:?? PST 1996 ( Andrew Morgan <morgan@physics.ucla.edu> )
+
+These notes are for Linux-PAM release 0.2. They cover what's changed
+since Marc Ewing relased 0.1.
+
+**** Please note. All of the directories in this release have been modified
+**** slightly to conform to the new pamlib. A couple of new directories have
+**** been added. As well as some documentation. If some of your code
+**** was in the previous release. Feel free to update it, but please
+**** try to conform to the new headers and Makefiles.
+
+* Andrew Morgan (morgan@physics.ucla.edu) is making this release
+ availible, Marc has been busy...!
+
+* Marc's pam-0.1/lib has been (quietly) enhanced and integrated into
+ Alex Yurie's collected tree of library and module code
+ (linux-pam.prop.1.tar.gz). Most of the changes are to do with error
+ checking. Some more robustness in the reading of the pam.conf file
+ and the addition of the pam_get_user() function.
+
+* The pam_*.h files have been reorganized to logically enforce the
+ separation of modules from applications. [Don't panic! Apart from
+ changing references of the form
+
+ #include "pam_appl.h"
+
+ to
+
+ #include <security/pam_appl.h>
+
+ The reorganization should be backwardly compatable (ie. a module
+ written for SUN will be as compatable as it was before with the
+ previous version ;)~ ]
+
+ (All of the source in this tree now conforms to this scheme...)
+
+ The new reorganization means that modules can be compiled with a
+ single header, <security/pam_modules.h>, and applications with
+ <security/pam_appl.h>.
+
+* I have tried to remove all the compiler warnings from the updated
+ "pamlib/*.c" files. On my system, (with a slightly modified <dlfcn.h>
+ email me if it interests you..) there are only two warnings that
+ remain: they are that ansi does not permit void --> fn ptr
+ assignment. K&Rv2 doesn't mention this....? As a matter of principle,
+ if anyone knows how to get rid of that warning... please
+ tell. Thanks! "-pedantic"
+
+* you can "make all" as a plain user, but
+
+* to "make install" you must be root. The include files are placed in
+ /usr/include/security. The libpam.so library is installed in /usr/lib
+ and the modules in /usr/lib/security. The two test binaries
+ are installed in the Linux-PAM-0.2/bin directory and a chance is given to
+ replace your /etc/pam.conf file with the one in Linux-PAM-0.2/conf.
+
+* I have included some documentation (pretty preliminary at the
+moment) which I have been working on in .../doc .
+
+I have had a little trouble with the modules, but atleast there are no
+segfaults! Please try it out and discuss your results... I actually
+hope it all works for you. But, Email any bugs/suggestions to the
+Linux-PAM list: linux-pam@mit.edu .....
+
+Regards,
+
+Andrew Morgan
+(morgan@physics.ucla.edu)
+
+
+Sat Feb 17 17:30:24 EST 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu)
+
+ * conf directory created with example of pam_conf
+ * stable code from pam_unix is added to modules/pam_unix
+ * test/test.c now requests username and password and attempts
+ to perform authentication
+
diff --git a/contrib/libpam/Copyright b/contrib/libpam/Copyright
new file mode 100644
index 000000000000..2f27a2ee0efd
--- /dev/null
+++ b/contrib/libpam/Copyright
@@ -0,0 +1,41 @@
+Unless otherwise *explicitly* stated the following text describes the
+licensed conditions under which the contents of this Linux-PAM release
+may be distributed:
+
+-------------------------------------------------------------------------
+Redistribution and use in source and binary forms of Linux-PAM, with
+or without modification, are permitted provided that the following
+conditions are met:
+
+1. Redistributions of source code must retain any existing copyright
+ notice, and this entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+2. Redistributions in binary form must reproduce all prior and current
+ copyright notices, this list of conditions, and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+3. The name of any author may not be used to endorse or promote
+ products derived from this software without their specific prior
+ written permission.
+
+ALTERNATIVELY, this product may be distributed under the terms of the
+GNU General Public License, in which case the provisions of the GNU
+GPL are required INSTEAD OF the above restrictions. (This clause is
+necessary due to a potential conflict between the GNU GPL and the
+restrictions contained in a BSD-style copyright.)
+
+THIS SOFTWARE IS PROVIDED ``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(S) 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.
+-------------------------------------------------------------------------
+
diff --git a/contrib/libpam/Makefile b/contrib/libpam/Makefile
new file mode 100644
index 000000000000..d25f58bb570e
--- /dev/null
+++ b/contrib/libpam/Makefile
@@ -0,0 +1,282 @@
+##
+## $Id: Makefile,v 1.31 1997/04/05 07:04:25 morgan Exp morgan $
+##
+## $Log: Makefile,v $
+##
+##
+
+# major and minor numbers of this release
+MAJOR_REL=0
+MINOR_REL=65
+DEBUG_REL=no
+#DEBUG_REL=yes
+
+# this should be the name of this directory
+RELNAME = Linux-PAM-$(MAJOR_REL).$(MINOR_REL)
+
+# this is the name of the archive file
+DISTFILE = $(RELNAME).tar.gz
+
+# define this to indicate to subdirectories that they are part of the
+# full source tree.
+FULL_LINUX_PAM_SOURCE_TREE=yes
+export FULL_LINUX_PAM_SOURCE_TREE
+
+DYNLOAD="dl"
+DYNTYPE="so"
+
+# Comment out either line to disable that type of linking for *modules only*
+# Both at once is a legal configuration!
+DYNAMIC=-DPAM_DYNAMIC
+#STATIC=-DPAM_STATIC
+
+# Comment out these lines to disable building dynamic/static libpam.*
+DYNAMIC_LIBPAM=yes
+#STATIC_LIBPAM=yes
+
+# All combinations of the above four variable definitions are legal,
+# however, not defining either dynamic or static modules and yet
+# creating a some flavor of LIBPAM will make an authentication library
+# that always fails!
+
+# Here we indicate which libraries are present on the local system
+# they control the building of some modules in this distribution
+# Note, these definitions are all "export"ed below...
+
+HAVE_PWDBLIB=no
+HAVE_CRACKLIB=no
+HAVE_AFSLIBS=no
+HAVE_KRBLIBS=no
+
+# NB. The following is the generic defines for compilation.
+# They can be overridden in the default.defs file below
+#
+WARNINGS = -ansi -D_POSIX_SOURCE -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align \
+ -Wtraditional -Wstrict-prototypes -Wmissing-prototypes \
+ -Wnested-externs -Winline -Wshadow -pedantic
+PIC=-fPIC
+
+# Mode to install shared libraries with
+SHLIBMODE=644
+
+#
+# Conditional defines..
+#
+
+ifdef DYNAMIC
+# need the dynamic library functions
+LIBDL=-l$(DYNLOAD)
+ifdef STATIC_LIBPAM
+# needed because pam_xxx() fn's are now in statically linked library
+RDYNAMIC = -rdynamic
+endif
+endif
+
+# Here we include the defines for the preferred operating system
+# these include things like CC, CFLAGS and destination directories
+# etc.. By default, this is a symbolic link to one of the .defs files
+# the .../defs/ directory. Please take a moment to check that you are
+# using the correct one.
+
+include default.defs
+
+# to turn on the fprintf(stderr, ..) debugging lines throughout the
+# distribution uncomment this line
+#EXTRAS += -DDEBUG
+
+# For serious memory allocation tracing uncomment the following
+#MEMORY_DEBUG=-DMEMORY_DEBUG
+
+#######################################################################
+# The pam_unix module in this file will not work on NIS based systems.#
+#######################################################################
+
+# ////////////////////////////////////////////////////
+# // You should not modify anything below this line //
+# ////////////////////////////////////////////////////
+
+# the sub-directories to make things in
+
+DIRS = modules libpam conf libpam_misc examples
+
+#
+# basic defines
+#
+
+INCLUDEDIR=-I$(shell pwd)/include
+PAMLIB=-L$(shell pwd)/libpam
+PAMMISCLIB=-L$(shell pwd)/libpam_misc
+ifeq ($(DEBUG_REL),yes)
+ PAMLIB += -lpamd
+ PAMMISCLIB += -lpamd_misc
+else
+ PAMLIB += -lpam
+ PAMMISCLIB += -lpam_misc
+endif
+
+
+# This is Linux-PAM and not a version from Sun etc..
+# [Note, this does not describe the operating system you are using
+# only that you are compiling the "Linux" (read FREE) implementation
+# of Pluggable Authentication Modules.
+EXTRAS += -DLINUX_PAM
+
+#
+# build composite defines
+#
+
+LOADLIBES = $(PAMLIB) $(RDYNAMIC) $(PAMMISCLIB) $(LIBDL) $(ULIBS)
+
+CFLAGS += $(EXTRAS) $(MEMORY_DEBUG) $(WARNINGS) $(INCLUDEDIR) $(PIC)
+ifneq ($(strip $(OS)),)
+CFLAGS += -D$(OS)
+endif
+ifneq ($(strip $(ARCH)),)
+CFLAGS += -D$(ARCH)
+endif
+
+#
+# export the libraries-available info; the modules should know how
+# to deal with this...
+#
+export HAVE_PWDBLIB
+export HAVE_CRACKLIB
+export HAVE_AFSLIBS
+export HAVE_KRBLIBS
+
+#
+# generic exports
+#
+export MAJOR_REL # the major release of this distribution
+export MINOR_REL # the minor release of this distribution
+export DEBUG_REL # for installing a debugging version of PAM
+export OS # operating system
+export ARCH # architecture
+export CC # the C compiler
+export INSTALL # to do instalations with
+export MKDIR # to ensure directories exist
+export CFLAGS # CC flags used to compile everything
+export LD_D # build a shared object file (module)
+export LD_L # build a shared library (e.g. libpam)
+export USESONAME # does shlib link command require soname option
+export SOSWITCH # shlib lib soname switch name
+export NEEDSONAME # does shared library link need versioned lib
+export LD # build a generic library
+export LDCONFIG # rebuild the shared libraries
+export AR # build a static library
+export RANLIB # reorder a static library
+export LOADLIBES # libraries needed for application linking
+export PAMLIB # where to find the local libpam.xx file
+export DYNTYPE # which suffix is used for libraries
+export SHLIBMODE # file mode for shared objects
+#
+# where to install things
+#
+export FAKEROOT # for package maintainers
+#
+export PREFIX # basic prefix for all other directories
+export SUPLEMENTED # where to store module helper binaries
+export LIBDIR # where libpam and libpam_misc go
+export SECUREDIR # where the modules will be placed
+export INCLUDED # where to store pam---.h files
+export CONFIGED # where pam.conf and pam.d/ go
+export SCONFIGED # where modules' config files go
+
+#
+# Conditional exporting ( ... these go on for a while... )
+#
+ifdef DYNAMIC
+export DYNAMIC
+endif
+ifdef STATIC
+export STATIC
+endif
+ifdef DYNAMIC_LIBPAM
+export DYNAMIC_LIBPAM
+endif
+ifdef STATIC_LIBPAM
+export STATIC_LIBPAM
+endif
+ifdef MEMORY_DEBUG
+export MEMORY_DEBUG
+endif
+
+##
+## the rules
+##
+
+all: .freezemake
+ @for i in $(DIRS) ; do \
+ $(MAKE) -C $$i all ; \
+ if [ $$? -ne 0 ]; then break ; fi ; \
+ done
+
+.freezemake:
+# Do nothing
+
+.old_freezemake: Makefile
+ @touch .freezemake
+ @echo "*WARNING*: If you are running a system that is dependent"
+ @echo " on PAM to work. DO NOT make sterile NOR make remove."
+ @echo " These options will delete the PAM files on your system"
+ @echo " and make it unusable!"
+ @echo ""
+ @echo "If you are in any doubt, just do 'make all' (or just"
+ @echo "'make'). It is likely that this is the SAFEST thing to do...."
+ @exit 1
+
+install:
+ @for i in $(DIRS) ; do \
+ $(MAKE) -C $$i install ; \
+ if [ $$? -ne 0 ]; then break ; fi ; \
+ done
+ install ./doc/man/*.3 $(PREFIX)/man/man3/
+ install ./doc/man/*.8 $(PREFIX)/man/man8/
+
+sterile: .freezemake
+ @$(MAKE) remove
+ @$(MAKE) extraclean
+
+remove: .freezemake
+ @for i in $(DIRS) ; do \
+ $(MAKE) -C $$i remove ; \
+ done
+
+clean:
+ @rm -f *~ core
+ @for i in $(DIRS) ; do \
+ $(MAKE) -C $$i clean ; \
+ done
+
+extraclean:
+ @for i in $(DIRS) doc; do \
+ $(MAKE) -C $$i extraclean ; \
+ done
+
+check:
+ @$(MAKE) -C conf check
+
+RCScheck:
+ @$(MAKE) -C conf RCScheck
+
+# this can be used to see what hasn't been check'd into RCS
+
+open:
+ @find . \( -type f -a -perm 644 \) -print
+
+release:
+ @egrep '^DEBUG\_REL\=yes' Makefile|grep -v grep > /dev/null ;\
+ if [ $$? -eq 0 ]; then \
+ echo "You should first set DEBUG_REL to no" ; exit 1 ; fi
+ $(MAKE) extraclean
+ rm -f .freezemake
+ touch .filelist .RCSlist
+ chmod 600 .filelist .RCSlist
+ cd .. ; find $(RELNAME) \! -type d -print | fgrep -v RCS | fgrep -v 'conf/.md5sum' > $(RELNAME)/.filelist
+ cd .. ; find $(RELNAME) -type f -print | fgrep RCS | fgrep -v 'conf/.RCSsum' > $(RELNAME)/.RCSlist
+ chmod 400 .filelist .RCSlist
+ $(MAKE) check
+ $(MAKE) RCScheck
+ (cat .filelist ; echo $(RELNAME)/conf/.md5sum) | (cd .. ; tar -cz -f$(DISTFILE) -T-)
+ (cat .RCSlist ; echo $(RELNAME)/conf/.RCSsum) | (cd .. ; tar -cz -fRCS+$(DISTFILE) -T-)
diff --git a/contrib/libpam/README b/contrib/libpam/README
new file mode 100644
index 000000000000..78a428ef46d3
--- /dev/null
+++ b/contrib/libpam/README
@@ -0,0 +1,167 @@
+#
+# $Id: README,v 1.14 1997/04/05 07:04:46 morgan Exp $
+#
+
+Hello!
+
+Thanks for downloading Linux-PAM-0.65.
+
+--------------------------------------------------------------------
+Before you begin:
+
+ * This distribution requires GNU's Make
+ * It requires GNU's C-compiler: gcc (and 'ld')
+ * it also requires the GNU shell: bash
+ * some of the modules require the presence of libpwdb see redhat
+ * two modules have some need for libcrack too..
+
+--------------------------------------------------------------------
+[
+Zeroth (optional) thing to do: check the detatched "pgp" signature for
+this distribution file, it should be signed by
+
+Type Bits/KeyID Date User ID
+pub 1024/2A398175 1996/11/17 Andrew G. Morgan <morgan@linux.kernel.org>
+]
+
+First thing to do (I assume you have successfully unpacked it!) is to
+run:
+
+ make check [ requires md5sum to be present ]
+
+This will also check that the distribution has arrived intact. [
+Later, If you change some things, running this command from this
+directory will show you what files you have altered. ]
+
+If you choose to get and install the RCS files that accompany this
+release, you may also run
+
+ make RCScheck
+
+from this directory.
+
+Next, you should check the symbolic link
+
+ .../Linux-PAM-X.YY/default.defs
+
+points to the file that best describes your system. The various *.defs
+files that are included in this distribution are to be found in the
+directory:
+
+ .../Linux-PAM-X.YY/defs/
+
+This should configure the distribution to compile on your system. The
+default is the version I use for maintaining the distribution. [If you
+don't find one that suits your needs, please try to create one, email
+it to me and I will include it in a future release.]
+
+If you are running an ELF based Linux system you should be able to
+compile the distribution straight from the box. If you are running an
+a.out based system, then some of the functionality of Linux-PAM will
+be unavailable to you. Instead, you must switch the DYNAMIC variables
+*off* in your "defs" file: comment out the DYNAMIC and DYNAMIC_LIBPAM
+defines and uncomment the STATIC and STATIC_LIBPAM defines. NOTE, for
+ELF based systems, almost any combination of these four definitions is
+legal... If you have ELF, I recommend the default however.
+
+Second, try to compile it. Use the following command in *this*
+directory:
+
+ make
+
+[ or 'make all' if you prefer ]. The first time you type make, it is
+likely to complain. This is to remind you to remove any libraries from
+previous versions of the distribution that are likely to confuse this
+make... Type 'make' again.
+
+Before you do the third thing. You should think about whether you want
+the default configuration scripts to be installed or not. If you have
+a working PAM based system you probably do *not* want this.. Whatever,
+before Linux-PAM installs the default scripts you will be prompted as
+to whether it is a good idea. Be sure to say NO if you are worried!
+** You have been warned. **
+
+Third, to install the stuff you need to be root. Do the following:
+
+ su -c "make install"
+
+If everything has worked as intended there should now be
+
+ some executables in ./bin/
+ some filters for pam_filter in /usr/sbin/pam_filter/
+ some configuration files:
+ /etc/pam.conf
+ /etc/security/*.conf
+ libpam_misc.a (static library) in /usr/lib/
+
+In addition:
+
+ if dynamically linked:
+
+ libpam.so.XXX (shared library) in /usr/lib/
+ libpam_misc.so.XXX (shared library) in /usr/lib/
+ pam_*.so (modules) in /usr/lib/security/
+
+ if statically linked:
+
+ libpam.a (static library) in /usr/lib/
+
+[These are the default directories that I use. Your own system may
+differ as specified in your XXX.defs file.]
+
+NOTES:
+
+* The documentation, what there is of it, is in ./doc. I am only
+including the sgml format source-files. But try to make .ps files
+available from the above http address. To locally use these sgml files
+you should have linuxdoc-sgml installed. Sorry, but I'm conserving net
+bandwidth by only including sources!
+
+* The source for each module is to be found in ./modules/XXX. If you
+want to add a new one, make a directory like XXX for it. Add the name
+(XXX) to MODDIRS in ./modules/Makefile and hopefully it will become
+part of the overall make. Note, the Makefile in ./modules/ is now
+smart enough to check if the directory is there before it changes into
+it; If you want to start working on a module, send me its name and I
+will add it to the "official" Makefile.. This way, you should be able
+to insert your developing module into any new release, and not have to
+worry at first about letting it out to the public. This may also give
+other people some idea about whether a module is currently being
+worked on or not.
+
+* Currently, you have to 'make' binaries from this directory. 'make
+clean', however, works in any directory that has a Makefile.
+
+* Also, you can 'make remove' (as root) from *this* directory and it
+will delete the various installed files dotted around the system. THIS
+IS A VERY BAD IDEA IF YOUR SYSTEM DEPENDS ON PAM TO WORK!!!
+
+* 'make sterile' does 'make remove' and then 'make extraclean', this
+might be required if you are alternating your choice of
+STATIC(_LIBPAM) and DYNAMIC(_LIBPAM) compilation. SEE COMMENT IN
+UPPERCASE IN PARAGRAPH ABOVE!!!!
+
+Best wishes
+
+Andrew Morgan
+
+Email bugs/comments to: the Linux-PAM list <pam-list@redhat.com>
+or me <morgan@linux.kernel.org>
+
+To see about joining the mailing list, send the following email:
+--------------------------------
+To: pam-list-request@redhat.com
+Subject: help
+<empty text>
+--------------------------------
+
+Additionally, some Linux-PAM files have been known to be found at one
+or more of the following places (they are not always the most up to
+date...):
+
+http://www.redhat.com/linux-info/pam/
+
+ftp://bach.cis.temple.edu/pub/People/Alex/private/PAM
+ftp://ftp.redhat.com/pub/misc/
+ftp://linux.nrao.edu/pub/linux/ALPHA/PAM/
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/PAM/
diff --git a/contrib/libpam/TODO b/contrib/libpam/TODO
new file mode 100644
index 000000000000..5ed6acb7a26d
--- /dev/null
+++ b/contrib/libpam/TODO
@@ -0,0 +1,59 @@
+$Id: TODO,v 1.10 1997/02/15 19:30:51 morgan Exp morgan $
+
+Here are some things to think about if you are interested in
+contributing to the Linux-PAM effort.
+
+1. If you have a suggestion mail the pam-list!
+
+2. TODO: Comments
+ ----- --------
+
+ [modules]
+
+pam_time should log an error if it denies access.
+
+pam_smartcard?? It has already started to happen. (Alex Yuriev has a
+ smart-card module...)
+
+pam_floppy?? A alternative login mechanism might involve
+ authenticating with a personal specially
+ formatted floppy!? (got to make some use of
+ all those strange Linux incompatible floppies
+ I keep getting from ISPs ;^)
+
+pam_??? If you are interested in another type of
+ authentication method--just make a module!
+ If you want it registered/some help, email the
+ list.
+
+ [misc]
+
+SVGA & X-conv Currently, libpam-misc contains a text-only
+ conversation function. A graphical one,
+ for X or SVGA would be very welcome,
+ [Ben Buxton is working on an X one (as of
+ 1996/12/1)] applications like xlock
+ etc.. would benefit from this.
+
+
+Issues that need to be resolved:
+--------------------------------
+
+- can we support the use_mapped_pass flag without running into problems
+ with ITAR rules? [this problem is likely to mutate. The DCE-RFC
+ people are considering the addition of a mapping module type - one
+ that other modules can use to safely store passwords...]
+
+ - anyone know where someone to email for FREE legal advice/support?
+
+-----------
+Comments to <pam-list@redhat.com>
+(administrative requests to <pam-list-request@redhat.com> use
+
+ Subject: help
+ <empty_message>
+
+)
+-----------
+Andrew Morgan <morgan@linux.kernel.org>.
+http://linux.kernel.org/pub/linux/libs/pam/index.html
diff --git a/contrib/libpam/bin/README b/contrib/libpam/bin/README
new file mode 100644
index 000000000000..92ab5253faa9
--- /dev/null
+++ b/contrib/libpam/bin/README
@@ -0,0 +1,39 @@
+##
+# $Id: README,v 1.6 1997/02/15 19:21:08 morgan Exp $
+##
+# $Log: README,v $
+# Revision 1.6 1997/02/15 19:21:08 morgan
+# fixed email
+#
+# Revision 1.5 1996/08/09 05:29:43 morgan
+# trimmed in line with the removal of applications from the distribution
+#
+#
+##
+
+(now we are getting networked apps, be careful to try and test on a
+securely isolated system!)
+
+N=2 <-- blank xsh
+
+Following a 'make install' (which should be done as root) in the
+parent directory this directory will contain $N binaries. The source
+for these programs is in ../examples. They are various short programs
+to use and otherwise test-drive the Linux-PAM libraries/modules with.
+
+These programs grant no privileges, but they give an idea of how well
+the modules are working.
+
+blank is new as of Linux-PAM-0.21. If you are writing/modifying an
+application it might be a place to start...
+
+xsh is new as of Linux-PAM-0.31, it is identical to blank, but invokes
+/bin/sh if the user is authenticated.
+
+[other apps are to be found in SimplePAMApps and many more on Red
+Hat's server.. http://www.redhat.com/]
+
+Best wishes
+
+Andrew
+(morgan@parc.power.net)
diff --git a/contrib/libpam/conf/Makefile b/contrib/libpam/conf/Makefile
new file mode 100644
index 000000000000..4fb9f7c40c60
--- /dev/null
+++ b/contrib/libpam/conf/Makefile
@@ -0,0 +1,60 @@
+#
+# $Id: Makefile,v 1.8 1997/04/05 06:59:33 morgan Exp $
+#
+# $Log: Makefile,v $
+# Revision 1.8 1997/04/05 06:59:33 morgan
+# fakeroot and $(MAKE)
+#
+# Revision 1.7 1997/02/15 15:53:51 morgan
+# added lines to make pam_conv1
+#
+# Revision 1.6 1996/11/10 19:48:09 morgan
+# fix for systems that have not installed bash in /bin/
+#
+# Revision 1.5 1996/03/16 22:21:26 morgan
+# added 'make remove' option
+#
+# Revision 1.4 1996/03/10 21:01:47 morgan
+# added .ignore_age flag file
+#
+# Revision 1.3 1996/03/10 17:41:28 morgan
+# make RCScheck check for the presence of the executable before running
+# it!
+#
+# Revision 1.2 1996/03/10 17:16:42 morgan
+# added md5RCS/ RCScheck entry
+#
+#
+
+dummy:
+ @echo "*** This is not a top level Makefile!"
+
+##########################################################
+
+all:
+ $(MAKE) -C pam_conv1 all
+
+install: $(FAKEROOT)$(CONFIGED)/pam.conf
+ $(MAKE) -C pam_conv1 install
+
+$(FAKEROOT)$(CONFIGED)/pam.conf: ./pam.conf
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(CONFIGED)/pam.conf
+ $(MAKE) -C pam_conv1 remove
+
+check:
+ bash -f ./md5itall
+
+RCScheck:
+ if [ -x ./md5RCS ]; then bash -f ./md5RCS ; fi
+
+lclean:
+ rm -f core *~ .ignore_age
+
+clean: lclean
+ $(MAKE) -C pam_conv1 clean
+
+extraclean: lclean
+ $(MAKE) -C pam_conv1 extraclean
diff --git a/contrib/libpam/conf/install b/contrib/libpam/conf/install
new file mode 100755
index 000000000000..2eae36715b70
--- /dev/null
+++ b/contrib/libpam/conf/install
@@ -0,0 +1,178 @@
+#!/bin/sh
+#
+# [This file was lifted from an X distribution. There was no explicit
+# copyright in the file, but the following text was associated with it.
+# should anyone from the X Consortium wish to alter the following
+# text. Please email <morgan@parc.power.net> Thanks. ]
+#
+# --------------------------
+# The X Consortium maintains and distributes the X Window System and
+# related software and documentation in coordinated releases. A release
+# consists of two distinct parts:
+#
+# 1) Specifications and Sample implementations of X Consortium
+# standards, and
+#
+# 2) software and documentation contributed by the general X Consortium
+# community.
+#
+# The timing and contents of a release are determined by the Consortium
+# staff based on the needs and desires of the Members and the advice of
+# the Advisory Board, tempered by the resource constraints of the
+# Consortium.
+#
+# Members have access to all X Consortium produced software and
+# documentation prior to release to the public. Each Member can receive
+# pre-releases and public releases at no charge. In addition, Members
+# have access to software and documentation while it is under
+# development, and can periodically request snapshots of the development
+# system at no charge.
+#
+# The X Consortium also maintains an electronic mail system for
+# reporting problems with X Consortium produced software and
+# documentation. Members have access to all bug reports, as well as all
+# software patches as they are incrementally developed by the Consortium
+# staff between releases.
+#
+# In general, all materials included in X Consortium releases are
+# copyrighted and contain permission notices granting unrestricted use,
+# sales and redistribution rights provided that the copyrights and the
+# permission notices are left intact. All materials are provided "as
+# is," without express or implied warranty.
+# --------------------------
+#
+# This accepts bsd-style install arguments and makes the appropriate calls
+# to the System V install.
+#
+
+flags=""
+dst=""
+src=""
+dostrip=""
+owner=""
+mode=""
+
+while [ x$1 != x ]; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -m) flags="$flags $1 $2 "
+ mode="$2"
+ shift
+ shift
+ continue;;
+
+ -o) flags="$flags -u $2 "
+ owner="$2"
+ shift
+ shift
+ continue;;
+
+ -g) flags="$flags $1 $2 "
+ shift
+ shift
+ continue;;
+
+ -s) dostrip="strip"
+ shift
+ continue;;
+
+ *) if [ x$src = x ]
+ then
+ src=$1
+ else
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+case "$mode" in
+"")
+ ;;
+*)
+ case "$owner" in
+ "")
+ flags="$flags -u root"
+ ;;
+ esac
+ ;;
+esac
+
+if [ x$src = x ]
+then
+ echo "$0: no input file specified"
+ exit 1
+fi
+
+if [ x$dst = x ]
+then
+ echo "$0: no destination specified"
+ exit 1
+fi
+
+
+# set up some variable to be used later
+
+rmcmd=""
+srcdir="."
+
+# if the destination isn't a directory we'll need to copy it first
+
+if [ ! -d $dst ]
+then
+ dstbase=`basename $dst`
+ cp $src /tmp/$dstbase
+ rmcmd="rm -f /tmp/$dstbase"
+ src=$dstbase
+ srcdir=/tmp
+ dst="`echo $dst | sed 's,^\(.*\)/.*$,\1,'`"
+ if [ x$dst = x ]
+ then
+ dst="."
+ fi
+fi
+
+
+# If the src file has a directory, copy it to /tmp to make install happy
+
+srcbase=`basename $src`
+
+if [ "$src" != "$srcbase" -a "$src" != "./$srcbase" ]
+then
+ cp $src /tmp/$srcbase
+ src=$srcbase
+ srcdir=/tmp
+ rmcmd="rm -f /tmp/$srcbase"
+fi
+
+# do the actual install
+
+if [ -f /usr/sbin/install ]
+then
+ installcmd=/usr/sbin/install
+elif [ -f /etc/install ]
+then
+ installcmd=/etc/install
+else
+ installcmd=install
+fi
+
+# This rm is commented out because some people want to be able to
+# install through symbolic links. Uncomment it if it offends you.
+rm -f $dst/$srcbase
+(cd $srcdir ; $installcmd -f $dst $flags $src)
+
+if [ x$dostrip = xstrip ]
+then
+ strip $dst/$srcbase
+fi
+
+# and clean up
+
+$rmcmd
+
+exit
+
diff --git a/contrib/libpam/conf/install_conf b/contrib/libpam/conf/install_conf
new file mode 100755
index 000000000000..db650a05cfd2
--- /dev/null
+++ b/contrib/libpam/conf/install_conf
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+CONFILE="$FAKEROOT"$CONFIGED/pam.conf
+IGNORE_AGE=./.ignore_age
+CONF=./pam.conf
+
+echo
+
+if [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "\
+An older Linux-PAM configuration file already exists ($CONFILE)"
+ WRITE=overwrite
+ fi
+ echo -n "\
+Do you wish to copy the $CONF file in this distribution
+to $CONFILE ? (y/n) [n] "
+ read yes
+else
+ yes=n
+fi
+
+if [ "$yes" = "y" ]; then
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ touch "$IGNORE_AGE"
+ echo " Skipping $CONF installation"
+fi
+
+echo
+
+exit 0
diff --git a/contrib/libpam/conf/md5itall b/contrib/libpam/conf/md5itall
new file mode 100755
index 000000000000..6328a4f6fc5a
--- /dev/null
+++ b/contrib/libpam/conf/md5itall
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# $Id$
+#
+# $Log$
+#
+# Created by Andrew G. Morgan (morgan@parc.power.net)
+#
+
+MD5SUM=md5sum
+CHKFILE1=./.md5sum
+CHKFILE2=./.md5sum-new
+
+which $MD5SUM > /dev/null
+result=$?
+
+if [ -x "$MD5SUM" ] || [ $result -eq 0 ]; then
+ rm -f $CHKFILE2
+ echo -n "computing md5 checksums."
+ for x in `cat ../.filelist` ; do
+ (cd ../.. ; $MD5SUM $x) >> $CHKFILE2
+ echo -n "."
+ done
+ echo
+ if [ -f "$CHKFILE1" ]; then
+ echo "\
+---> Note, since the last \`make check', the following file(s) have changed:
+==========================================================================="
+ diff $CHKFILE1 $CHKFILE2
+ if [ $? -eq 0 ]; then
+ echo "\
+--------------------------- Nothing has changed ---------------------------"
+ fi
+ echo "\
+==========================================================================="
+ fi
+ rm -f "$CHKFILE1"
+ mv "$CHKFILE2" "$CHKFILE1"
+ chmod 400 "$CHKFILE1"
+else
+ echo "\
+Please install \`$MD5SUM'.
+[It is used to check the integrity of this distribution]
+---> no check done."
+fi
diff --git a/contrib/libpam/conf/mkdirp b/contrib/libpam/conf/mkdirp
new file mode 100755
index 000000000000..b0e04b05d042
--- /dev/null
+++ b/contrib/libpam/conf/mkdirp
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# this is a wrapper for difficult mkdir programs...
+#
+
+for d in $*
+do
+ if [ ! -d $d ]; then
+ mkdir -p $d
+ if [ $? -ne 0 ]; then exit $? ; fi
+ fi
+done
+
+exit 0
+
+##########################################################################
+# if your mkdir does not support the -p option delete the above lines and
+# use what follows:
+--------------------
+#!/bin/sh
+
+#VERBOSE=yes
+Cwd=`pwd`
+
+for d in $*
+do
+ if [ "`echo $d|cut -c1`" != "/" ]; then
+ x=`pwd`/$d
+ else
+ x=$d
+ fi
+ x="`echo $x|sed -e 'yX/X X'`"
+ cd /
+ for s in $x
+ do
+ if [ -d $s ]; then
+ if [ -n "$VERBOSE" ]; then echo -n "[$s/]"; fi
+ cd $s
+ else
+ mkdir $s
+ if [ $? -ne 0 ]; then exit $? ; fi
+ if [ -n "$VERBOSE" ]; then echo -n "$s/"; fi
+ cd $s
+ fi
+ done
+ if [ -n "$VERBOSE" ]; then echo ; fi
+ cd $Cwd
+done
+
+exit 0
diff --git a/contrib/libpam/conf/pam.conf b/contrib/libpam/conf/pam.conf
new file mode 100644
index 000000000000..2e4f0342189a
--- /dev/null
+++ b/contrib/libpam/conf/pam.conf
@@ -0,0 +1,126 @@
+# ---------------------------------------------------------------------------#
+# /etc/pam.conf #
+# #
+# Last modified by Andrew G. Morgan <morgan@parc.power.net> #
+# ---------------------------------------------------------------------------#
+# $Id: pam.conf,v 1.18 1997/02/15 20:20:20 morgan Exp morgan $
+# ---------------------------------------------------------------------------#
+# serv. module ctrl module [path] ...[args..] #
+# name type flag #
+# ---------------------------------------------------------------------------#
+#
+# The PAM configuration file for the `chfn' service
+#
+chfn auth required pam_pwdb.so
+chfn account required pam_pwdb.so
+chfn password required pam_cracklib.so retry=3
+chfn password required pam_pwdb.so shadow md5 use_authtok
+#
+# The PAM configuration file for the `chsh' service
+#
+chsh auth required pam_pwdb.so
+chsh account required pam_pwdb.so
+chsh password required pam_cracklib.so retry=3
+chsh password required pam_pwdb.so shadow md5 use_authtok
+#
+# The PAM configuration file for the `ftp' service
+#
+ftp auth requisite pam_listfile.so \
+ item=user sense=deny file=/etc/ftpusers onerr=succeed
+ftp auth requisite pam_shells.so
+ftp auth required pam_pwdb.so
+ftp account required pam_pwdb.so
+#
+# The PAM configuration file for the `imap' service
+#
+imap auth required pam_pwdb.so
+imap account required pam_pwdb.so
+#
+# The PAM configuration file for the `login' service
+#
+login auth requisite pam_securetty.so
+login auth required pam_pwdb.so
+login auth optional pam_group.so
+login account requisite pam_time.so
+login account required pam_pwdb.so
+login password required pam_cracklib.so retry=3
+login password required pam_pwdb.so shadow md5 use_authtok
+login session required pam_pwdb.so
+#
+# The PAM configuration file for the `netatalk' service
+#
+netatalk auth required pam_pwdb.so
+netatalk account required pam_pwdb.so
+#
+# The PAM configuration file for the `other' service
+#
+other auth required pam_deny.so
+other auth required pam_warn.so
+other account required pam_deny.so
+other password required pam_deny.so
+other password required pam_warn.so
+other session required pam_deny.so
+#
+# The PAM configuration file for the `passwd' service
+#
+passwd password requisite pam_cracklib.so retry=3
+passwd password required pam_pwdb.so shadow md5 use_authtok
+#
+# The PAM configuration file for the `rexec' service
+#
+rexec auth requisite pam_securetty.so
+rexec auth requisite pam_nologin.so
+rexec auth sufficient pam_rhosts_auth.so
+rexec auth required pam_pwdb.so
+rexec account required pam_pwdb.so
+rexec session required pam_pwdb.so
+rexec session required pam_limits.so
+#
+# The PAM configuration file for the `rlogin' service
+# this application passes control to `login' if it fails
+#
+rlogin auth requisite pam_securetty.so
+rlogin auth requisite pam_nologin.so
+rlogin auth required pam_rhosts_auth.so
+rlogin account required pam_pwdb.so
+rlogin password required pam_cracklib.so retry=3
+rlogin password required pam_pwdb.so shadow md5 use_authtok
+rlogin session required pam_pwdb.so
+rlogin session required pam_limits.so
+#
+# The PAM configuration file for the `rsh' service
+#
+rsh auth requisite pam_securetty.so
+rsh auth requisite pam_nologin.so
+rsh auth sufficient pam_rhosts_auth.so
+rsh auth required pam_pwdb.so
+rsh account required pam_pwdb.so
+rsh session required pam_pwdb.so
+rsh session required pam_limits.so
+#
+# The PAM configuration file for the `samba' service
+#
+samba auth required pam_pwdb.so
+samba account required pam_pwdb.so
+#
+# The PAM configuration file for the `su' service
+#
+su auth required pam_wheel.so
+su auth sufficient pam_rootok.so
+su auth required pam_pwdb.so
+su account required pam_pwdb.so
+su session required pam_pwdb.so
+#
+# The PAM configuration file for the `vlock' service
+#
+vlock auth required pam_pwdb.so
+#
+# The PAM configuration file for the `xdm' service
+#
+xdm auth required pam_pwdb.so
+xdm account required pam_pwdb.so
+#
+# The PAM configuration file for the `xlock' service
+#
+xlock auth required pam_pwdb.so
+
diff --git a/contrib/libpam/conf/pam_conv1/Makefile b/contrib/libpam/conf/pam_conv1/Makefile
new file mode 100644
index 000000000000..7691dc31222d
--- /dev/null
+++ b/contrib/libpam/conf/pam_conv1/Makefile
@@ -0,0 +1,41 @@
+#
+#
+ifeq ($(OS),solaris)
+
+clean:
+ @echo not available in Solaris
+
+all:
+ @echo not available in Solaris
+
+install:
+ @echo not available in Solaris
+
+else
+
+all: pam_conv1
+
+pam_conv1: pam_conv.tab.c lex.yy.c
+ $(CC) -o pam_conv1 pam_conv.tab.c -lfl
+
+pam_conv.tab.c: pam_conv.y lex.yy.c
+ bison pam_conv.y
+
+lex.yy.c: pam_conv.lex
+ flex pam_conv.lex
+
+lclean:
+ rm -f core pam_conv1 lex.yy.c pam_conv.tab.c *.o *~
+ rm -rf ./pam.d pam_conv.output
+
+clean: lclean
+
+install: pam_conv1
+ cp -f ./pam_conv1 ../../bin
+
+endif
+
+remove:
+ rm -f ../../bin/pam_conv1
+
+extraclean: remove clean
diff --git a/contrib/libpam/conf/pam_conv1/README b/contrib/libpam/conf/pam_conv1/README
new file mode 100644
index 000000000000..d3344bb34ff0
--- /dev/null
+++ b/contrib/libpam/conf/pam_conv1/README
@@ -0,0 +1,10 @@
+$Id: README,v 1.1 1997/02/15 15:50:50 morgan Exp $
+
+This directory contains a untility to convert pam.conf files to a pam.d/
+tree. The conversion program takes pam.conf from the standard input and
+creates the pam.d/ directory in the current directory.
+
+The program will fail if ./pam.d/ already exists.
+
+Andrew Morgan, February 1997
+
diff --git a/contrib/libpam/conf/pam_conv1/lex.yy.c b/contrib/libpam/conf/pam_conv1/lex.yy.c
new file mode 100644
index 000000000000..5843e58d6c96
--- /dev/null
+++ b/contrib/libpam/conf/pam_conv1/lex.yy.c
@@ -0,0 +1,1553 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 6
+#define YY_END_OF_BUFFER 7
+static yyconst short int yy_accept[21] =
+ { 0,
+ 0, 0, 7, 3, 4, 5, 1, 3, 3, 3,
+ 4, 1, 1, 1, 3, 2, 3, 1, 1, 0
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 4, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 5, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[6] =
+ { 0,
+ 1, 2, 3, 1, 1
+ } ;
+
+static yyconst short int yy_base[24] =
+ { 0,
+ 0, 0, 26, 20, 0, 27, 5, 10, 19, 20,
+ 0, 0, 0, 15, 0, 27, 0, 0, 0, 27,
+ 17, 6, 20
+ } ;
+
+static yyconst short int yy_def[24] =
+ { 0,
+ 20, 1, 20, 21, 22, 20, 20, 20, 21, 8,
+ 22, 7, 23, 20, 9, 20, 10, 7, 14, 0,
+ 20, 20, 20
+ } ;
+
+static yyconst short int yy_nxt[33] =
+ { 0,
+ 4, 5, 6, 7, 8, 12, 13, 11, 12, 14,
+ 15, 9, 16, 15, 17, 18, 12, 9, 18, 19,
+ 13, 13, 20, 10, 10, 20, 3, 20, 20, 20,
+ 20, 20
+ } ;
+
+static yyconst short int yy_chk[33] =
+ { 0,
+ 1, 1, 1, 1, 1, 7, 7, 22, 7, 7,
+ 8, 8, 8, 8, 8, 14, 14, 21, 14, 14,
+ 23, 23, 10, 9, 4, 3, 20, 20, 20, 20,
+ 20, 20
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "pam_conv.lex"
+#define INITIAL 0
+#line 3 "pam_conv.lex"
+/*
+ * $Id: pam_conv.lex,v 1.1 1997/01/23 05:35:50 morgan Exp $
+ *
+ * Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+ *
+ * This file is covered by the Linux-PAM License (which should be
+ * distributed with this file.)
+ */
+
+ const static char lexid[]=
+ "$Id: pam_conv.lex,v 1.1 1997/01/23 05:35:50 morgan Exp $\n"
+ "Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>\n";
+
+ extern int current_line;
+#line 389 "lex.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 19 "pam_conv.lex"
+
+
+#line 543 "lex.yy.c"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 21 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 27 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 21 "pam_conv.lex"
+; /* skip comments (sorry) */
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 23 "pam_conv.lex"
+{
+ ++current_line;
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 27 "pam_conv.lex"
+{
+ return TOK;
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 31 "pam_conv.lex"
+; /* Ignore */
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 33 "pam_conv.lex"
+{
+ return EOFILE;
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 37 "pam_conv.lex"
+{
+ ++current_line;
+ return NL;
+}
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 42 "pam_conv.lex"
+ECHO;
+ YY_BREAK
+#line 669 "lex.yy.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 21 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 21 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 20);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 42 "pam_conv.lex"
+
diff --git a/contrib/libpam/conf/pam_conv1/pam_conv.lex b/contrib/libpam/conf/pam_conv1/pam_conv.lex
new file mode 100644
index 000000000000..d5f618ef4518
--- /dev/null
+++ b/contrib/libpam/conf/pam_conv1/pam_conv.lex
@@ -0,0 +1,42 @@
+
+%{
+/*
+ * $Id: pam_conv.lex,v 1.1 1997/01/23 05:35:50 morgan Exp $
+ *
+ * Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+ *
+ * This file is covered by the Linux-PAM License (which should be
+ * distributed with this file.)
+ */
+
+ const static char lexid[]=
+ "$Id: pam_conv.lex,v 1.1 1997/01/23 05:35:50 morgan Exp $\n"
+ "Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>\n";
+
+ extern int current_line;
+%}
+
+%%
+
+"#"[^\n]* ; /* skip comments (sorry) */
+
+"\\\n" {
+ ++current_line;
+}
+
+([^\n\t ]|[\\][^\n])+ {
+ return TOK;
+}
+
+[ \t]+ ; /* Ignore */
+
+<<EOF>> {
+ return EOFILE;
+}
+
+[\n] {
+ ++current_line;
+ return NL;
+}
+
+%%
diff --git a/contrib/libpam/conf/pam_conv1/pam_conv.tab.c b/contrib/libpam/conf/pam_conv1/pam_conv.tab.c
new file mode 100644
index 000000000000..6ca566cfb948
--- /dev/null
+++ b/contrib/libpam/conf/pam_conv1/pam_conv.tab.c
@@ -0,0 +1,1019 @@
+
+/* A Bison parser, made from pam_conv.y
+ by GNU Bison version 1.25
+ */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define NL 258
+#define EOFILE 259
+#define TOK 260
+
+#line 1 "pam_conv.y"
+
+
+/*
+ * $Id: pam_conv.y,v 1.3 1997/02/15 15:50:50 morgan Exp morgan $
+ *
+ * Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+ *
+ * This file is covered by the Linux-PAM License (which should be
+ * distributed with this file.)
+ */
+
+ const static char bisonid[]=
+ "$Id: pam_conv.y,v 1.3 1997/02/15 15:50:50 morgan Exp morgan $\n"
+ "Copyright (c) Andrew G. Morgan 1997-8 <morgan@linux.kernel.org>\n";
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+ int current_line=1;
+ extern char *yytext;
+
+/* XXX - later we'll change this to be the specific conf file(s) */
+#define newpamf stderr
+
+#define PAM_D "./pam.d"
+#define PAM_D_MODE 0755
+#define PAM_D_MAGIC_HEADER \
+ "#%PAM-1.0\n" \
+ "#[For version 1.0 syntax, the above header is optional]\n"
+
+#define PAM_D_FILE_FMT PAM_D "/%s"
+
+ const char *old_to_new_ctrl_flag(const char *old);
+ void yyerror(const char *format, ...);
+
+#line 39 "pam_conv.y"
+typedef union {
+ int def;
+ char *string;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 17
+#define YYFLAG -32768
+#define YYNTBASE 6
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 260 ? yytranslate[x] : 11)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 2, 3, 4, 5
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 1, 4, 7, 10, 17, 20, 21, 24, 26
+};
+
+static const short yyrhs[] = { -1,
+ 6, 3, 0, 6, 7, 0, 6, 4, 0, 10,
+ 10, 10, 9, 8, 3, 0, 1, 3, 0, 0,
+ 8, 10, 0, 5, 0, 5, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 53, 54, 55, 56, 62, 126, 132, 135, 151, 157
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","NL","EOFILE",
+"TOK","complete","line","tokenls","path","tok", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 6, 6, 6, 6, 7, 7, 8, 8, 9, 10
+};
+
+static const short yyr2[] = { 0,
+ 0, 2, 2, 2, 6, 2, 0, 2, 1, 1
+};
+
+static const short yydefact[] = { 1,
+ 0, 0, 2, 4, 10, 3, 0, 6, 0, 0,
+ 9, 7, 0, 5, 8, 0, 0
+};
+
+static const short yydefgoto[] = { 1,
+ 6, 13, 12, 7
+};
+
+static const short yypact[] = {-32768,
+ 4, 7,-32768,-32768,-32768,-32768, 6,-32768, 6, 8,
+-32768,-32768, -2,-32768,-32768, 12,-32768
+};
+
+static const short yypgoto[] = {-32768,
+-32768,-32768,-32768, -7
+};
+
+
+#define YYLAST 13
+
+
+static const short yytable[] = { 9,
+ 14, 10, 5, 16, 2, 15, 3, 4, 5, 8,
+ 5, 17, 11
+};
+
+static const short yycheck[] = { 7,
+ 3, 9, 5, 0, 1, 13, 3, 4, 5, 3,
+ 5, 0, 5
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "/usr/share/bison.simple"
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include <alloca.h>
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include <malloc.h>
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include <malloc.h>
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#ifdef __cplusplus
+extern "C" {
+void *alloca (unsigned int);
+};
+#else /* not __cplusplus */
+void *alloca ();
+#endif /* not __cplusplus */
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc. */
+#endif /* not GNU C. */
+#endif /* alloca not defined. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+int yyparse (void);
+#endif
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, int count)
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 196 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss - 1;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *++yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+ yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp));
+ yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size - 1;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 4:
+#line 56 "pam_conv.y"
+{
+ return 0;
+;
+ break;}
+case 5:
+#line 62 "pam_conv.y"
+{
+ char *filename;
+ FILE *conf;
+ int i;
+
+ /* make sure we have lower case */
+ for (i=0; yyvsp[-5].string[i]; ++i) {
+ yyvsp[-5].string[i] = tolower(yyvsp[-5].string[i]);
+ }
+
+ /* $1 = service-name */
+ yyerror("Appending to " PAM_D "/%s", yyvsp[-5].string);
+
+ filename = malloc(strlen(yyvsp[-5].string) + sizeof(PAM_D) + 6);
+ sprintf(filename, PAM_D_FILE_FMT, yyvsp[-5].string);
+ conf = fopen(filename, "r");
+ if (conf == NULL) {
+ /* new file */
+ conf = fopen(filename, "w");
+ if (conf != NULL) {
+ fprintf(conf, PAM_D_MAGIC_HEADER);
+ fprintf(conf,
+ "#\n"
+ "# The PAM configuration file for the `%s' service\n"
+ "#\n", yyvsp[-5].string);
+ }
+ } else {
+ fclose(conf);
+ conf = fopen(filename, "a");
+ }
+ if (conf == NULL) {
+ yyerror("trouble opening %s - aborting", filename);
+ exit(1);
+ }
+ free(filename);
+
+ /* $2 = module-type */
+ fprintf(conf, "%-10s", yyvsp[-4].string);
+ free(yyvsp[-4].string);
+
+ /* $3 = required etc. */
+ {
+ const char *trans;
+
+ trans = old_to_new_ctrl_flag(yyvsp[-3].string);
+ free(yyvsp[-3].string);
+ fprintf(conf, " %-10s", trans);
+ }
+
+ /* $4 = module-path */
+ fprintf(conf, " %s", yyvsp[-2].string);
+ free(yyvsp[-2].string);
+
+ /* $5 = arguments */
+ if (yyvsp[-1].string != NULL) {
+ fprintf(conf, " \\\n\t\t%s", yyvsp[-1].string);
+ free(yyvsp[-1].string);
+ }
+
+ /* end line */
+ fprintf(conf, "\n");
+
+ fclose(conf);
+;
+ break;}
+case 6:
+#line 126 "pam_conv.y"
+{
+ yyerror("malformed line");
+;
+ break;}
+case 7:
+#line 132 "pam_conv.y"
+{
+ yyval.string=NULL;
+;
+ break;}
+case 8:
+#line 135 "pam_conv.y"
+{
+ int len;
+
+ if (yyvsp[-1].string) {
+ len = strlen(yyvsp[-1].string) + strlen(yyvsp[0].string) + 2;
+ yyval.string = malloc(len);
+ sprintf(yyval.string,"%s %s",yyvsp[-1].string,yyvsp[0].string);
+ free(yyvsp[-1].string);
+ free(yyvsp[0].string);
+ } else {
+ yyval.string = yyvsp[0].string;
+ }
+;
+ break;}
+case 9:
+#line 151 "pam_conv.y"
+{
+ /* XXX - this could be used to check if file present */
+ yyval.string = strdup(yytext);
+;
+ break;}
+case 10:
+#line 157 "pam_conv.y"
+{
+ yyval.string = strdup(yytext);
+;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+#line 498 "/usr/share/bison.simple"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp == yyss) YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+}
+#line 161 "pam_conv.y"
+
+
+#include "lex.yy.c"
+
+const char *old_to_new_ctrl_flag(const char *old)
+{
+ static const char *clist[] = {
+ "requisite",
+ "required",
+ "sufficient",
+ "optional",
+ NULL,
+ };
+ int i;
+
+ for (i=0; clist[i]; ++i) {
+ if (strcasecmp(clist[i], old) == 0) {
+ break;
+ }
+ }
+
+ return clist[i];
+}
+
+void yyerror(const char *format, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "line %d: ", current_line);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+void main()
+{
+ if (mkdir(PAM_D, PAM_D_MODE) != 0) {
+ yyerror(PAM_D " already exists.. aborting");
+ exit(1);
+ }
+ yyparse();
+}
diff --git a/contrib/libpam/conf/pam_conv1/pam_conv.y b/contrib/libpam/conf/pam_conv1/pam_conv.y
new file mode 100644
index 000000000000..8ce5ab08f023
--- /dev/null
+++ b/contrib/libpam/conf/pam_conv1/pam_conv.y
@@ -0,0 +1,203 @@
+%{
+
+/*
+ * $Id: pam_conv.y,v 1.3 1997/02/15 15:50:50 morgan Exp morgan $
+ *
+ * Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+ *
+ * This file is covered by the Linux-PAM License (which should be
+ * distributed with this file.)
+ */
+
+ const static char bisonid[]=
+ "$Id: pam_conv.y,v 1.3 1997/02/15 15:50:50 morgan Exp morgan $\n"
+ "Copyright (c) Andrew G. Morgan 1997-8 <morgan@linux.kernel.org>\n";
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+ int current_line=1;
+ extern char *yytext;
+
+/* XXX - later we'll change this to be the specific conf file(s) */
+#define newpamf stderr
+
+#define PAM_D "./pam.d"
+#define PAM_D_MODE 0755
+#define PAM_D_MAGIC_HEADER \
+ "#%PAM-1.0\n" \
+ "#[For version 1.0 syntax, the above header is optional]\n"
+
+#define PAM_D_FILE_FMT PAM_D "/%s"
+
+ const char *old_to_new_ctrl_flag(const char *old);
+ void yyerror(const char *format, ...);
+%}
+
+%union {
+ int def;
+ char *string;
+}
+
+%token NL EOFILE TOK
+
+%type <string> tok path tokenls
+
+%start complete
+
+%%
+
+complete
+:
+| complete NL
+| complete line
+| complete EOFILE {
+ return 0;
+}
+;
+
+line
+: tok tok tok path tokenls NL {
+ char *filename;
+ FILE *conf;
+ int i;
+
+ /* make sure we have lower case */
+ for (i=0; $1[i]; ++i) {
+ $1[i] = tolower($1[i]);
+ }
+
+ /* $1 = service-name */
+ yyerror("Appending to " PAM_D "/%s", $1);
+
+ filename = malloc(strlen($1) + sizeof(PAM_D) + 6);
+ sprintf(filename, PAM_D_FILE_FMT, $1);
+ conf = fopen(filename, "r");
+ if (conf == NULL) {
+ /* new file */
+ conf = fopen(filename, "w");
+ if (conf != NULL) {
+ fprintf(conf, PAM_D_MAGIC_HEADER);
+ fprintf(conf,
+ "#\n"
+ "# The PAM configuration file for the `%s' service\n"
+ "#\n", $1);
+ }
+ } else {
+ fclose(conf);
+ conf = fopen(filename, "a");
+ }
+ if (conf == NULL) {
+ yyerror("trouble opening %s - aborting", filename);
+ exit(1);
+ }
+ free(filename);
+
+ /* $2 = module-type */
+ fprintf(conf, "%-10s", $2);
+ free($2);
+
+ /* $3 = required etc. */
+ {
+ const char *trans;
+
+ trans = old_to_new_ctrl_flag($3);
+ free($3);
+ fprintf(conf, " %-10s", trans);
+ }
+
+ /* $4 = module-path */
+ fprintf(conf, " %s", $4);
+ free($4);
+
+ /* $5 = arguments */
+ if ($5 != NULL) {
+ fprintf(conf, " \\\n\t\t%s", $5);
+ free($5);
+ }
+
+ /* end line */
+ fprintf(conf, "\n");
+
+ fclose(conf);
+}
+| error NL {
+ yyerror("malformed line");
+}
+;
+
+tokenls
+: {
+ $$=NULL;
+}
+| tokenls tok {
+ int len;
+
+ if ($1) {
+ len = strlen($1) + strlen($2) + 2;
+ $$ = malloc(len);
+ sprintf($$,"%s %s",$1,$2);
+ free($1);
+ free($2);
+ } else {
+ $$ = $2;
+ }
+}
+;
+
+path
+: TOK {
+ /* XXX - this could be used to check if file present */
+ $$ = strdup(yytext);
+}
+
+tok
+: TOK {
+ $$ = strdup(yytext);
+}
+
+%%
+
+#include "lex.yy.c"
+
+const char *old_to_new_ctrl_flag(const char *old)
+{
+ static const char *clist[] = {
+ "requisite",
+ "required",
+ "sufficient",
+ "optional",
+ NULL,
+ };
+ int i;
+
+ for (i=0; clist[i]; ++i) {
+ if (strcasecmp(clist[i], old) == 0) {
+ break;
+ }
+ }
+
+ return clist[i];
+}
+
+void yyerror(const char *format, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "line %d: ", current_line);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+void main()
+{
+ if (mkdir(PAM_D, PAM_D_MODE) != 0) {
+ yyerror(PAM_D " already exists.. aborting");
+ exit(1);
+ }
+ yyparse();
+}
diff --git a/contrib/libpam/defs/hpux.defs b/contrib/libpam/defs/hpux.defs
new file mode 100644
index 000000000000..d834198369e3
--- /dev/null
+++ b/contrib/libpam/defs/hpux.defs
@@ -0,0 +1,36 @@
+##
+# HPUX defs contributed by Derrick J Brashear <shadow@dementia.org>
+##
+# this file indicates the compiler and the various hardware/OS dependent
+# flags for installation. It also defines the various destinations of
+# installed files on the system.
+#
+# This file is the default version. Please look in .../defs/ for your
+# preferred OS/vendor.
+
+OS=hpux9
+ARCH=hpux
+CC=gcc
+INSTALL=install
+MKDIR=mkdir -p
+CFLAGS=-g -DPAM_SHL -DHAVE_UTMP_H
+ULIBS=
+LD=ld
+LD_D=$(LD) -b
+LD_L=$(LD) -b
+USESONAME=no
+NEEDSONAME=no
+LDCONFIG=:
+AR=ar -cr
+RANLIB=ranlib
+FAKEROOT=
+PREFIX=/usr
+SUPLEMENTED=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+SECUREDIR=$(LIBDIR)/security
+INCLUDED=/usr/include/security
+CONFIGED=/etc
+SCONFIGED=/etc/security
+DYNLOAD="dld"
+DYNTYPE="sl"
+SHLIBMODE=755
diff --git a/contrib/libpam/defs/linux.defs b/contrib/libpam/defs/linux.defs
new file mode 100644
index 000000000000..94e9968c6b25
--- /dev/null
+++ b/contrib/libpam/defs/linux.defs
@@ -0,0 +1,32 @@
+# this file indicates the compiler and the various hardware/OS dependent
+# flags for installation. It also defines the various destinations of
+# installed files on the system.
+#
+# This file is the default version. Please look in .../defs/ for your
+# preferred OS/vendor.
+
+OS=linux
+ARCH=`uname -m | sed 's/^i?86/i386/'`
+CC=gcc
+INSTALL=install
+MKDIR=mkdir -p
+CFLAGS=-O7 -pipe -g
+ULIBS=#-lefence
+LD=ld
+LD_D=gcc -shared -Xlinker -x
+LD_L=$(LD) -x -shared
+USESONAME=yes
+SOSWITCH=-soname
+NEEDSONAME=no
+LDCONFIG=/sbin/ldconfig
+AR=ar -cr
+RANLIB=ranlib
+FAKEROOT=
+PREFIX=/usr
+SUPLEMENTED=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+SECUREDIR=$(LIBDIR)/security
+INCLUDED=/usr/include/security
+CONFIGED=/etc
+SCONFIGED=/etc/security
+NSLLIB=-lnsl
diff --git a/contrib/libpam/defs/morgan.defs b/contrib/libpam/defs/morgan.defs
new file mode 100644
index 000000000000..178de28d21a8
--- /dev/null
+++ b/contrib/libpam/defs/morgan.defs
@@ -0,0 +1,35 @@
+##
+# defs for Andrew's debugging version (which is a modified Red Hat
+# box)
+##
+# this file indicates the compiler and the various hardware/OS dependent
+# flags for installation. It also defines the various destinations of
+# installed files on the system.
+#
+# This file is the version used for Red Hat Linux.
+
+OS=linux
+ARCH=i386
+CC=gcc
+INSTALL=install
+MKDIR=mkdir -p
+CFLAGS=$(RPM_OPT_FLAGS) -pipe -g
+ULIBS=
+#-lefence
+LD=ld
+LD_D=gcc -shared -Xlinker -x
+LD_L=$(LD) -x -shared
+USESONAME=yes
+SOSWITCH=-soname
+NEEDSONAME=no
+LDCONFIG=/sbin/ldconfig
+AR=ar -cr
+RANLIB=ranlib
+FAKEROOT=$(RPM_BUILD_ROOT)
+PREFIX=
+SUPLEMENTED=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+SECUREDIR=$(LIBDIR)/security.d
+INCLUDED=/usr/include/security
+CONFIGED=/etc
+SCONFIGED=/etc/security
diff --git a/contrib/libpam/defs/redhat.defs b/contrib/libpam/defs/redhat.defs
new file mode 100644
index 000000000000..8c7e1e17f75a
--- /dev/null
+++ b/contrib/libpam/defs/redhat.defs
@@ -0,0 +1,34 @@
+##
+# defs for Red Hat Linux
+# Michael K. Johnson <johnsonm@redhat.com>
+##
+# this file indicates the compiler and the various hardware/OS dependent
+# flags for installation. It also defines the various destinations of
+# installed files on the system.
+#
+# This file is the version used for Red Hat Linux.
+
+OS=linux
+ARCH=$(shell rpm --showrc | grep 'build arch' | sed 's/^.*: //g')
+CC=gcc
+INSTALL=install
+MKDIR=mkdir -p
+CFLAGS=$(RPM_OPT_FLAGS) -pipe -g
+ULIBS=#-lefence
+LD=ld
+LD_D=gcc -shared -Xlinker -x
+LD_L=$(LD) -x -shared
+USESONAME=yes
+SOSWITCH=-soname
+NEEDSONAME=no
+LDCONFIG=/sbin/ldconfig
+AR=ar -cr
+RANLIB=ranlib
+FAKEROOT=$(RPM_BUILD_ROOT)
+PREFIX=
+SUPLEMENTED=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+SECUREDIR=$(LIBDIR)/security
+INCLUDED=/usr/include/security
+CONFIGED=/etc
+SCONFIGED=/etc/security
diff --git a/contrib/libpam/defs/solaris.defs b/contrib/libpam/defs/solaris.defs
new file mode 100644
index 000000000000..f9f265297dd5
--- /dev/null
+++ b/contrib/libpam/defs/solaris.defs
@@ -0,0 +1,48 @@
+##
+# Solaris defs contributed by Josh Wilmes <josh@makita.jpl.nasa.gov>
+##
+# this file indicates the compiler and the various hardware/OS dependent
+# flags for installation. It also defines the various destinations of
+# installed files on the system.
+#
+# This file is the default version. Please look in .../defs/ for your
+# preferred OS/vendor.
+
+# Please note that the linker used must be the GNU ld, not the native Sun
+# linker. It is fairly common for the gnu linker (/usr/ccs/bin/ld) to be
+# configured as the default linker for gcc. To tell gcc to use the
+# gnu linker, you need to set the GCC_EXEC_PREFIX environment variable
+# to point at the directory where the gnu linker is installed. Here's
+# what I do:
+# $ mkdir /tmp/foo
+# $ ln -s /path/to/gnu/ld /tmp/foo/ld
+# $ export GCC_EXEC_PREFIX=/tmp/foo/
+# $ export PATH=/tmp/foo:$PATH
+
+OS=solaris
+ARCH=sun
+CC=cc
+INSTALL=install
+MKDIR=mkdir -p
+WARNINGS = -D_POSIX_SOURCE
+PIC=-KPIC
+CFLAGS=-g -D__EXTENSIONS__ -Dsolaris
+ULIBS=
+LD=ld
+LD_L=$(LD) -G
+LD_D=$(LD_L)
+RDYNAMIC=
+USESONAME=yes
+SOSWITCH=-h
+NEEDSONAME=no
+LDCONFIG=echo
+AR=ar -cr
+RANLIB=ranlib
+FAKEROOT=
+PREFIX=/usr
+SUPLEMENTED=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+SECUREDIR=$(LIBDIR)/security
+INCLUDED=/usr/include/security
+CONFIGED=/etc
+SCONFIGED=/etc/security
diff --git a/contrib/libpam/defs/sunos.defs b/contrib/libpam/defs/sunos.defs
new file mode 100644
index 000000000000..158accc53474
--- /dev/null
+++ b/contrib/libpam/defs/sunos.defs
@@ -0,0 +1,37 @@
+##
+# SunOS defs contributed by Derrick J Brashear <shadow@dementia.org>
+##
+# this file indicates the compiler and the various hardware/OS dependent
+# flags for installation. It also defines the various destinations of
+# installed files on the system.
+#
+# This file is the SunOS version. Please look in .../defs/ for your
+# preferred OS/vendor.
+
+OS=sunos
+ARCH=sun
+CC=gcc
+INSTALL=install
+MKDIR=mkdir -p
+CFLAGS=-O2 -pipe -g -D__EXTENSIONS__
+ULIBS=
+LD_D=gcc -shared -Xlinker -x
+LD=ld
+LD_L=$(LD)
+USESONAME=no
+NEEDSONAME=yes
+LDCONFIG=/usr/etc/ldconfig
+AR=ar cr
+RANLIB=ranlib
+FAKEROOT=
+PREFIX=/usr
+SUPLEMENTED=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+SECUREDIR=$(LIBDIR)/security
+INCLUDED=/usr/include/security
+CONFIGED=/etc
+SCONFIGED=/etc/security
+WARNINGS= -ansi -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align \
+ -Wtraditional -Wstrict-prototypes -Wmissing-prototypes \
+ -Wnested-externs -Winline -Wshadow
diff --git a/contrib/libpam/doc/CREDITS b/contrib/libpam/doc/CREDITS
new file mode 100644
index 000000000000..95ca2ab36e02
--- /dev/null
+++ b/contrib/libpam/doc/CREDITS
@@ -0,0 +1,37 @@
+<!--
+ an sgml list of people to credit for their contributions to Linux-PAM
+ $Id: CREDITS,v 1.4 1997/04/05 06:47:26 morgan Exp morgan $
+ -->
+Peter Allgeyer,
+Tim Baverstock,
+Craig S. Bell,
+Derrick J. Brashear,
+Ben Buxton,
+Oliver Crow,
+Chris Dent,
+Marc Ewing,
+Cristian Gafton,
+Eric Hester,
+Roger Hu,
+Eric Jacksch,
+Michael K. Johnson,
+David Kinchlea,
+Nicolai Langfeldt,
+Elliot Lee,
+Al Longyear,
+Ingo Luetkebohle,
+Marek Michalkiewicz,
+Aleph One,
+Martin Pool,
+Sean Reifschneider,
+Erik Troan,
+Theodore Ts'o,
+Jeff Uphoff,
+Myles Uyema,
+Savochkin Andrey Vladimirovich,
+Ronald Wahl,
+David Wood,
+John Wilmes,
+Joseph S. D. Yao
+and
+Alex O. Yuriev.
diff --git a/contrib/libpam/doc/Makefile b/contrib/libpam/doc/Makefile
new file mode 100644
index 000000000000..866b408512df
--- /dev/null
+++ b/contrib/libpam/doc/Makefile
@@ -0,0 +1,77 @@
+
+### $Id: Makefile,v 1.9 1997/01/04 21:55:52 morgan Exp $
+
+TXTER=sgml2txt
+HTMLER=sgml2html
+# older distributions use, sgml2ps
+PSER=sgml2latex -p
+
+FILES=pam pam_appl pam_modules
+FSRCS=pam.sgml pam_appl.sgml pam_modules.sgml
+
+TEXTS=txts/pam.txt txts/pam_appl.txt txts/pam_modules.txt
+HTMLS=html/pam.html html/pam_appl.html html/pam_modules.html
+PSFILES=ps/pam.ps ps/pam_appl.ps ps/pam_modules.ps
+
+MODULES=$(shell ls modules/*.sgml)
+
+#######################################################
+
+dummy:
+ @echo "Making the documentation..."
+ @make all
+
+all: htmls texts postscript
+
+htmls: $(HTMLS)
+
+$(HTMLS) : $(FSRCS)
+ @for i in $(FILES) ; do \
+ if [ ! -f "html/$$i.html" ] || [ "$$i.sgml" -nt "html/$$i.html" ]; \
+ then \
+ cd html ; $(HTMLER) ../$$i ; \
+ if [ $$? -ne 0 ]; then exit 1 ; fi ; \
+ cd .. ; \
+ fi ; \
+ done
+
+texts: $(TEXTS)
+
+$(TEXTS) : $(FSRCS)
+ @for i in $(FILES) ; do \
+ if [ ! -f "txts/$$i.txt" ] \
+ || [ "$$i.sgml" -nt "txts/$$i.txt" ]; then \
+ cd txts ; $(TXTER) ../$$i ; cd .. ; \
+ fi ; \
+ done
+
+postscript: $(PSFILES)
+
+$(PSFILES): $(FSRCS)
+ @for i in $(FILES) ; do \
+ if [ ! -f "ps/$$i.ps" ] || [ "$$i.sgml" -nt "ps/$$i.ps" ]; then \
+ cd ps ; $(PSER) ../$$i ; cd .. ; \
+ fi ; \
+ done
+
+pam.sgml: pam_source.sgml MODULES-SGML
+ @sed -e '/^<!\-\- insert\-file MODULES\-SGML \-\->/r MODULES-SGML' pam_source.sgml > pam.sgml
+
+MODULES-SGML: $(MODULES)
+ @echo 'Building module text from files in modules/*.sgml'
+ @rm -f MODULES-SGML
+ @echo '<!-- modules included:' > MODULES-SGML
+ @ls modules/*.sgml >> MODULES-SGML
+ @echo ' and that is all -->' >> MODULES-SGML
+ @cat modules/*.sgml >> MODULES-SGML
+
+extraclean: clean
+
+clean:
+ rm -f *~ *.bak
+ rm -f html/pam*.html
+ rm -f man/*~
+ rm -f $(TEXTS)
+ rm -f $(PSFILES)
+ rm -f MODULES-SGML pam.sgml
+
diff --git a/contrib/libpam/doc/NOTES b/contrib/libpam/doc/NOTES
new file mode 100644
index 000000000000..b0f40d47d59f
--- /dev/null
+++ b/contrib/libpam/doc/NOTES
@@ -0,0 +1,16 @@
+Things to be added:
+
+@ modules:
+@ application:
+
+ use of
+ 'user' = user to become,
+ 'uid' = user requesting service
+ 'euid' = privilege of current process.
+
+@ sysadmin:
+
+ included modules:
+ behavior
+ non-included modules:
+ behavior/pointers.
diff --git a/contrib/libpam/doc/figs/pam_orient.txt b/contrib/libpam/doc/figs/pam_orient.txt
new file mode 100644
index 000000000000..a8b745a1628b
--- /dev/null
+++ b/contrib/libpam/doc/figs/pam_orient.txt
@@ -0,0 +1,23 @@
+
+
+
+ +----------------+
+ | application: X |
+ +----------------+ / +----------+ +================+
+ | authentication-[---->--\--] Linux- |--<--| /etc/pam.conf |
+ | + [----<--/--] PAM | |================|
+ |[conversation()][--+ \ | | | X auth .. a.so |
+ +----------------+ | / +-n--n-----+ | X auth .. b.so |
+ | | | __| | | _____/
+ | service user | A | | |____,-----'
+ | | | V A
+ +----------------+ +------|-----|---------+ -----+------+
+ +---u-----u----+ | | |
+ | auth.... |--[ a ]--[ b ]--[ c ]
+ +--------------+
+ | acct.... |--[ b ]--[ d ]
+ +--------------+
+ | password |--[ b ]--[ c ]
+ +--------------+
+ | session |--[ e ]--[ c ]
+ +--------------+ \ No newline at end of file
diff --git a/contrib/libpam/doc/html/index.html b/contrib/libpam/doc/html/index.html
new file mode 100644
index 000000000000..91f990fc01e0
--- /dev/null
+++ b/contrib/libpam/doc/html/index.html
@@ -0,0 +1,21 @@
+
+<HTML>
+<HEAD>
+<TITLE>Linux-PAM - Pluggable Authentication Modules for Linux</TITLE>
+</HEAD>
+<BODY>
+
+<p>
+Here is the documentation for Linux-PAM. As you will see it is
+currently not complete. However, in order of decreasing length:
+
+<ul>
+<li> <a href="pam.html">The System Administrators' Guide</a>
+<li> <a href="pam_modules.html">The Module Writers' Manual</a>
+<li> <a href="pam_appl.html">The Application developers' Manual</a>
+</ul>
+
+<hr>
+<p>
+REVISION: <tt>$Id: index.html,v 1.4 1996/11/21 06:51:01 morgan Exp $</tt>
+</BODY>
diff --git a/contrib/libpam/doc/man/pam.8 b/contrib/libpam/doc/man/pam.8
new file mode 100644
index 000000000000..75384416f2cf
--- /dev/null
+++ b/contrib/libpam/doc/man/pam.8
@@ -0,0 +1,279 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam.8,v 1.2 1997/02/15 18:37:27 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1996-7 <morgan@linux.kernel.org>
+.TH PAM 8 "1997 Feb 9" "Linux-PAM 0.56" "Linux-PAM Manual"
+.SH NAME
+
+Linux-PAM \- Pluggable Authentication Modules for Linux
+
+.SH SYNOPSIS
+.B /etc/pam.conf
+.sp 2
+.SH DESCRIPTION
+
+This manual is intended to offer a quick introduction to
+.BR Linux-PAM ". "
+For more information the reader is directed to the
+.BR "Linux-PAM system administrators' guide".
+
+.sp
+.BR Linux-PAM
+Is a system of libraries that handle the authentication tasks of
+applications (services) on the system. The library provides a stable
+general interface (Application Programming Interface - API) that
+privilege granting programs (such as
+.BR login "(1) "
+and
+.BR su "(1)) "
+defer to to perform standard authentication tasks.
+
+.sp
+The principal feature of the PAM approach is that the nature of the
+authentication is dynamically configurable. In other words, the
+system administrator is free to choose how individual
+service-providing applications will authenticate users. This dynamic
+configuration is set by the contents of the single
+.BR Linux-PAM
+configuration file
+.BR /etc/pam.conf "."
+Alternatively, the configuration can be set by individual
+configuration files located in the
+.B /etc/pam.d/
+directory.
+.IB "The presence of this directory will cause " Linux-PAM " to ignore"
+.BI /etc/pam.conf "."
+
+.sp
+From the point of view of the system administrator, for whom this
+manual is provided, it is not of primary importance to understand the
+internal behavior of the
+.BR Linux-PAM
+library. The important point to recognize is that the configuration
+file(s)
+.I define
+the connection between applications
+.BR "" "(" services ")"
+and the pluggable authentication modules
+.BR "" "(" PAM "s)"
+that perform the actual authentication tasks.
+
+.sp
+.BR Linux-PAM
+separates the tasks of
+.I authentication
+into four independent management groups:
+.BR "account" " management; "
+.BR "auth" "entication management; "
+.BR "password" " management; "
+and
+.BR "session" " management."
+(We highlight the abbreviations used for these groups in the
+configuration file.)
+
+.sp
+Simply put, these groups take care of different aspects of a typical
+user's request for a restricted service:
+
+.sp
+.BR account " - "
+provide account verification types of service: has the user's password
+expired?; is this user permitted access to the requested service?
+
+.br
+.BR auth "entication - "
+establish the user is who they claim to be. Typically this is via some
+challenge-response request that the user must satisfy: if you are who
+you claim to be please enter your password. Not all authentications
+are of this type, there exist hardware based authentication schemes
+(such as the use of smart-cards and biometric devices), with suitable
+modules, these may be substituted seamlessly for more standard
+approaches to authentication - such is the flexibility of
+.BR Linux-PAM "."
+
+.br
+.BR password " - "
+this group's responsibility is the task of updating authentication
+mechanisms. Typically, such services are strongly coupled to those of
+the
+.BR auth
+group. Some authentication mechanisms lend themselves well to being
+updated with such a function. Standard UN*X password-based access is
+the obvious example: please enter a replacement password.
+
+.br
+.BR session " - "
+this group of tasks cover things that should be done prior to a
+service being given and after it is withdrawn. Such tasks include the
+maintenance of audit trails and the mounting of the user's home
+directory. The
+.BR session
+management group is important as it provides both an opening and
+closing hook for modules to affect the services available to a user.
+
+.SH The configuration file(s)
+
+When a
+.BR Linux-PAM
+aware privilege granting application is started, it activates its
+attachment to the PAM-API. This activation performs a number of
+tasks, the most important being the reading of the configuration file(s):
+.BR /etc/pam.conf "."
+Alternatively, this may be the contents of the
+.BR /etc/pam.d/
+directory.
+
+These files list the
+.BR PAM "s"
+that will do the authentication tasks required by this service, and
+the appropriate behavior of the PAM-API in the event that individual
+.BR PAM "s "
+fail.
+
+.sp
+The syntax of the
+.B /etc/pam.conf
+configuration file is as follows. The file is made
+up of a list of rules, each rule is typically placed on a single line,
+but may be extended with an escaped end of line: `\\<LF>'. Comments
+are preceded with `#' marks and extend to the next end of line.
+
+.sp
+The format of each rule is a space separated collection of tokens, the
+first three being case-insensitive:
+
+.sp
+.br
+.BR " service type control module-path module-arguments"
+
+.sp
+The syntax of files contained in the
+.B /etc/pam.d/
+directory, are identical except for the absence of any
+.I service
+field. In this case, the
+.I service
+is the name of the file in the
+.B /etc/pam.d/
+directory. This filename must be in lower case.
+
+.sp
+An important feature of
+.BR Linux-PAM ", "
+is that a number of rules may be
+.I stacked
+to combine the services of a number of PAMs for a given authentication
+task.
+
+.sp
+The
+.BR service
+is typically the familiar name of the corresponding application:
+.BR login
+and
+.BR su
+are good examples. The
+.BR service "-name, " other ", "
+is reserved for giving
+.I default
+rules. Only lines that mention the current service (or in the absence
+of such, the
+.BR other
+entries) will be associated with the given service-application.
+
+.sp
+The
+.BR type
+is the management group that the rule corresponds to. It is used to
+specify which of the management groups the subsequent module is to
+be associated with. Valid entries are:
+.BR account "; "
+.BR auth "; "
+.BR password "; "
+and
+.BR session "."
+The meaning of each of these tokens was explained above.
+
+.sp
+The third field,
+.BR control ", "
+indicates the behavior of the PAM-API should the module fail to
+succeed in its authentication task. Valid
+.BR control
+values are:
+.BR requisite
+- failure of such a PAM results in the immediate termination of the
+authentication process;
+.BR required
+- failure of such a PAM will ultimately lead to the PAM-API returning
+failure but only after the remaining
+.I stacked
+modules (for this
+.BR service
+and
+.BR type ")"
+have been invoked;
+.BR sufficient
+- success of such a module is enough to satisfy the authentication
+requirements of the stack of modules (if a prior
+.BR required
+module has failed the success of this one is
+.IR ignored "); "
+.BR optional
+- the success or failure of this module is only important if it is the
+only module in the stack associated with this
+.BR service "+" type "."
+
+.sp
+.BR module-path
+- this is the full filename of the PAM to be used by the application
+
+.sp
+.BR module-arguments
+- these are a space separated list of tokens that can be used to
+modify the specific behavior of the given PAM. Such arguments will be
+documented for each individual module.
+
+.SH "FILES"
+.BR /etc/pam.conf " - the configuration file"
+.br
+.BR /etc/pam.d/ " - the"
+.BR Linux-PAM
+configuration directory. If this directory is present, the
+.B /etc/pam.conf
+file is ignored.
+.br
+.BR /usr/lib/libpam.so.X " - the dynamic library"
+.br
+.BR /usr/lib/security/*.so " - the PAMs
+
+.sp
+Note, to conform to the Linux File-system standard, the libraries and
+modules in your system may be located in
+.BR /lib " and " /lib/security
+respectively.
+
+.SH ERRORS
+Typically errors generated by the
+.BR Linux-PAM
+system of libraries, will be written to
+.BR syslog "(3)."
+
+.SH "CONFORMING TO"
+DCE-RFC 86.0, October 1995.
+.br
+Contains additional features, currently under consideration by the
+DCE-RFC committee.
+
+.SH BUGS
+.sp 2
+None known.
+
+.SH "SEE ALSO"
+
+The three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam.conf.8 b/contrib/libpam/doc/man/pam.conf.8
new file mode 100644
index 000000000000..ea2dd98bfc9f
--- /dev/null
+++ b/contrib/libpam/doc/man/pam.conf.8
@@ -0,0 +1 @@
+.so man8/pam.8
diff --git a/contrib/libpam/doc/man/pam.d.8 b/contrib/libpam/doc/man/pam.d.8
new file mode 100644
index 000000000000..ea2dd98bfc9f
--- /dev/null
+++ b/contrib/libpam/doc/man/pam.d.8
@@ -0,0 +1 @@
+.so man8/pam.8
diff --git a/contrib/libpam/doc/man/pam_authenticate.3 b/contrib/libpam/doc/man/pam_authenticate.3
new file mode 100644
index 000000000000..f631c47286be
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_authenticate.3
@@ -0,0 +1,91 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam_authenticate.3,v 1.2 1997/02/15 18:39:59 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1996-7 <morgan@parc.power.net>
+.TH PAM_AUTHENTICATE 3 "1996 Dec 9" "Linux-PAM 0.55" "App. Programmers' Manual"
+.SH NAME
+
+pam_authenticate \- authenticate a user
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.sp
+.BI "int pam_authenticate(pam_handle_t " *pamh ", int " flags ");"
+.sp 2
+.SH DESCRIPTION
+.B pam_authenticate
+
+.br
+Use this function to authenticate an applicant user. It is linked
+.I dynamically
+to the authentication modules by
+.BR Linux-PAM ". "
+It is the task of these module to perform such an authentication. The
+specific nature of the authentication is not the concern of the
+application.
+
+.br
+Following successful completion, the
+.BR name
+of the authenticated user will be present in the
+.BR Linux-PAM
+item
+.BR PAM_USER ". "
+This item may be recovered with a call to
+.BR pam_get_item "(3)."
+
+.br
+The application developer should note that the modules may request
+that the user enter their username via the conversation mechanism (see
+.BR pam_start "(3))."
+Should this be the case, the user-prompt string can be set via
+the
+.BR PAM_USER_PROMPT
+item (see
+.BR pam_set_item "(3))."
+
+.SH "RETURN VALUE"
+On success
+.BR PAM_SUCCESS
+is returned. All other returns should be considered
+authentication failures and will be
+.I delayed
+by an amount specified with prior calls to
+.BR pam_fail_delay "(3). "
+Specific failures that demand special attention are the following:
+.TP
+.B PAM_ABORT
+the application should exit immediately. Of course,
+.BR pam_end "(3)"
+should be called first.
+
+.TP
+.B PAM_MAXTRIES
+the application has tried too many times to authenticate the
+user, authentication should not be attempted again.
+
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(3). "
+
+.SH "CONFORMING TO"
+DCE-RFC 86.0, October 1995.
+
+.SH BUGS
+.sp 2
+none known.
+
+.SH "SEE ALSO"
+
+.BR pam_start "(3), "
+.BR pam_get_item "(3) "
+.BR pam_fail_delay "(3) "
+and
+.BR pam_strerror "(3). "
+
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam_chauthtok.3 b/contrib/libpam/doc/man/pam_chauthtok.3
new file mode 100644
index 000000000000..b0997d592893
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_chauthtok.3
@@ -0,0 +1,101 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam_chauthtok.3,v 1.2 1997/02/15 18:42:23 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+.TH PAM_CHAUTHTOK 3 "1997 Jan 4" "Linux-PAM 0.55" "App. Programmers' Manual"
+.SH NAME
+
+pam_chauthtok \- updating authentication tokens
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.sp
+.BI "int pam_chauthtok(pam_handle_t " *pamh ", int " flags ");"
+.sp 2
+.SH DESCRIPTION
+.B pam_chauthtok
+
+.br
+Use this function to rejuvenate the authentication tokens (passwords
+etc.) of an applicant user.
+
+.br
+Note, the application should not pre-authenticate the user, as this is
+performed (if required) by the
+.BR Linux-PAM
+framework.
+
+.br
+The
+.I flags
+argument can
+.I optionally
+take the value,
+.BR PAM_CHANGE_EXPIRED_AUTHTOK "."
+In such cases the framework is only required to update those
+authentication tokens that have expired. Without this argument, the
+framework will attempt to obtain new tokens for all configured
+authentication mechanisms. The details of the types and number of such
+schemes should not concern the calling application.
+
+.SH RETURN VALUE
+A successful return from this function will be indicated with
+.BR PAM_SUCCESS "."
+
+.br
+Specific errors of special interest when calling this function are
+
+.br
+.BR PAM_AUTHTOK_ERROR
+- a valid new token was not obtained
+
+.br
+.BR PAM_AUTHTOK_RECOVERY_ERR
+- old authentication token was not available
+
+.br
+.BR PAM_AUTHTOK_LOCK_BUSY
+- a resource needed to update the token was locked (try again later)
+
+.br
+.BR PAM_AUTHTOK_DISABLE_AGING
+- one or more of the authentication modules does not honor
+authentication token aging
+
+.br
+.BR PAM_TRY_AGAIN
+- one or more authentication mechanism is not prepared to update a
+token at this time
+
+.br
+In general other return values may be returned. They should be treated
+as indicating failure.
+
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(3). "
+
+.SH "CONFORMING TO"
+DCE-RFC 86.0, October 1995.
+
+.SH BUGS
+.sp 2
+none known.
+
+.SH "SEE ALSO"
+
+.BR pam_start "(3), "
+.BR pam_authenticate "(3), "
+.BR pam_setcred "(3), "
+.BR pam_get_item "(3), "
+.BR pam_strerror "(3) "
+and
+.BR pam "(8)."
+
+.br
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam_close_session.3 b/contrib/libpam/doc/man/pam_close_session.3
new file mode 100644
index 000000000000..c809a0e4f0d8
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_close_session.3
@@ -0,0 +1 @@
+.so man3/pam_open_session.3
diff --git a/contrib/libpam/doc/man/pam_end.3 b/contrib/libpam/doc/man/pam_end.3
new file mode 100644
index 000000000000..06fdabb9c462
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_end.3
@@ -0,0 +1 @@
+.so man3/pam_start.3
diff --git a/contrib/libpam/doc/man/pam_fail_delay.3 b/contrib/libpam/doc/man/pam_fail_delay.3
new file mode 100644
index 000000000000..42bccd6b9258
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_fail_delay.3
@@ -0,0 +1,130 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam_fail_delay.3,v 1.2 1997/02/15 18:47:46 morgan Exp morgan $
+.\" Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+.TH PAM_FAIL_DELAY 3 "1997 Jan 12" "Linux-PAM 0.56" "Programmers' Manual"
+.SH NAME
+
+pam_fail_delay \- request a delay on failure
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.br
+or,
+.br
+.B #include <security/pam_modules.h>
+.sp
+.BI "int pam_fail_delay(pam_handle_t " "*pamh" ", unsigned int " "usec" ");"
+.sp 2
+.SH DESCRIPTION
+.br
+It is often possible to attack an authentication scheme by exploiting
+the time it takes the scheme to deny access to an applicant user. In
+cases of
+.I short
+timeouts, it may prove possible to attempt a
+.I brute force
+dictionary attack -- with an automated process, the attacker tries all
+possible passwords to gain access to the system. In other cases,
+where individual failures can take measurable amounts of time
+(indicating the nature of the failure), an attacker can obtain useful
+information about the authentication process. These latter attacks
+make use of procedural delays that constitute a
+.I covert channel
+of useful information.
+
+.br
+To minimize the effectiveness of such attacks, it is desirable to
+introduce a random delay in a failed authentication process.
+.B Linux-PAM
+provides such a facility. The delay occurs upon failure of the
+.BR pam_authenticate "(3) "
+and
+.BR pam_chauthtok "(3) "
+functions. It occurs
+.I after
+all authentication modules have been called, but
+.I before
+control is returned to the service application.
+
+.br
+The function,
+.BR pam_fail_delay "(3),"
+is used to specify a required minimum for the length of the
+failure-delay; the
+.I usec
+argument. This function can be called by the service application
+and/or the authentication modules, both may have an interest in
+delaying a reapplication for service by the user. The length of the
+delay is computed at the time it is required. Its length is
+pseudo-gausianly distributed about the
+.I maximum
+requested value; the resultant delay will differ by as much as 25% of
+this maximum requested value (both up and down).
+
+.br
+On return from
+.BR pam_authenticate "(3) or " pam_chauthtok "(3),"
+independent of success or failure, the new requested delay is reset to
+its default value: zero.
+
+.SH EXAMPLE
+.br
+For example, a
+.B login
+application may require a failure delay of roughly 3 seconds. It will
+contain the following code:
+.sp
+.br
+.B " pam_fail_delay(pamh, 3000000 /* micro-seconds */ );"
+.br
+.B " pam_authenticate(pamh, 0);"
+.sp
+.br
+if the modules do not request a delay, the failure delay will be
+between 2.25 and 3.75 seconds.
+
+.br
+However, the modules, invoked in the authentication process, may
+also request delays:
+.sp
+.br
+.RB " (module #1) " "pam_fail_delay(pamh, 2000000);"
+.sp
+.br
+.RB " (module #2) " "pam_fail_delay(pamh, 4000000);"
+.sp
+.br
+in this case, it is the largest requested value that is used to
+compute the actual failed delay: here between 3 and 5 seconds.
+
+.SH "RETURN VALUE"
+Following a successful call to
+.BR pam_fail_delay "(3), " PAM_SUCCESS
+is returned. All other returns should be considered serious failures.
+
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(3). "
+
+.SH "CONFORMING TO"
+Under consideration by the X/Open group for future inclusion in the
+PAM RFC. 1996/1/10
+
+.SH BUGS
+.sp 2
+none known.
+
+.SH "SEE ALSO"
+
+.BR pam_start "(3), "
+.BR pam_get_item "(3) "
+and
+.BR pam_strerror "(3). "
+
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam_open_session.3 b/contrib/libpam/doc/man/pam_open_session.3
new file mode 100644
index 000000000000..1b2dcf980bdb
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_open_session.3
@@ -0,0 +1,99 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam_open_session.3,v 1.2 1997/02/15 18:49:02 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+.TH PAM_OPEN_SESSION 3 "1997 Jan 4" "Linux-PAM 0.55" "App. Programmers' Manual"
+.SH NAME
+
+pam_open/close_session \- PAM session management
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.sp
+.BI "int pam_open_session(pam_handle_t " *pamh ", int " flags ");"
+.sp
+.BI "int pam_close_session(pam_handle_t " *pamh ", int " flags ");"
+.sp 2
+.SH DESCRIPTION
+
+PAM provides management-hooks for the initialization and termination
+of a session.
+
+.TP
+.B pam_open_session
+.br
+Use this function to signal that an authenticated user session has
+begun. It should be called only after the user is properly identified
+and (where necessary) has been granted their credentials with
+.BR pam_authenticate "(3)"
+and
+.BR pam_setcred "(3)"
+respectively.
+
+.br
+Some types of functions associated with session
+initialization are logging for the purposes of system-audit and
+mounting directories (the user's home directory for example). These
+should not concern the application. It should be noted that the
+.I effective
+uid,
+.BR geteuid "(2),"
+of the application should be of sufficient privilege to perform such
+tasks.
+
+.TP
+.B pam_close_session
+.br
+Use this function to signal that a user session has
+terminated. In general this function may not need to be located in the
+same application as the initialization function,
+.BR pam_open_session "."
+
+.br
+Typically, this function will undo the actions of
+.BR pam_open_session "."
+That is, log audit information concerning the end of the user session
+or unmount the user's home directory. Apart from having sufficient
+privilege the details of the session termination should not concern
+the calling application. It is good programming practice, however, to
+cease acting on behalf of the user on returning from this call.
+
+.SH RETURN VALUE
+A successful return from the session management functions will be
+indicated with
+.BR PAM_SUCCESS "."
+
+.br
+The specific error indicating a failure to open or close a session is
+.BR PAM_SESSION_ERR "."
+In general other return values may be returned. They should be treated
+as indicating failure.
+
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(3). "
+
+.SH "CONFORMING TO"
+OSF-RFC 86.0, October 1995.
+
+.SH BUGS
+.sp 2
+none known.
+
+.SH "SEE ALSO"
+
+.BR pam_start "(3), "
+.BR pam_authenticate "(3), "
+.BR pam_setcred "(3), "
+.BR pam_get_item "(3), "
+.BR pam_strerror "(3) "
+and
+.BR pam "(3)."
+
+.br
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam_setcred.3 b/contrib/libpam/doc/man/pam_setcred.3
new file mode 100644
index 000000000000..388a5d766703
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_setcred.3
@@ -0,0 +1,79 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam_setcred.3,v 1.2 1997/02/15 18:50:49 morgan Exp morgan $
+.\" Copyright (c) Andrew G. Morgan 1996,1997 <morgan@parc.power.net>
+.TH PAM_SETCRED 3 "1997 July 6" "Linux-PAM 0.58" "App. Programmers' Manual"
+.SH NAME
+
+pam_setcred \- set the credentials for the user
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.sp
+.BI "int pam_setcred(pam_handle_t " *pamh ", int " flags ");"
+.sp 2
+.SH DESCRIPTION
+.B pam_setcred
+
+This function is used to establish, maintain and delete the
+credentials of a user. It should be called after a user has been
+authenticated and before a session is opened for the user (with
+.BR pam_open_session "(3))."
+
+It should be noted that credentials come in many forms. Examples
+include: group memberships; ticket-files; and Linux-PAM environment
+variables. For this reason, it is important that the basic identity
+of the user is established, by the application, prior to a call to
+this function. For example, the default
+.BR Linux-PAM
+environment variables should be set and also
+.BR initgroups "(2) "
+(or equivalent) should have been performed.
+
+.SH "VALID FLAGS"
+.TP
+.BR PAM_ESTABLISH_CRED
+initialize the credentials for the user.
+
+.TP
+.BR PAM_DELETE_CRED
+delete the user's credentials.
+
+.TP
+.BR PAM_REINITIALIZE_CRED
+delete and then initialize the user's credentials.
+
+.TP
+.BR PAM_REFRESH_CRED
+extend the lifetime of the existing credentials.
+
+.SH "RETURN VALUE"
+
+On success
+.BR PAM_SUCCESS
+is returned, all other return values should be treated as errors.
+
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(3). "
+
+.SH "CONFORMING TO"
+DCE-RFC 86.0, October 1995.
+
+.SH BUGS
+.sp 2
+none known.
+
+.SH "SEE ALSO"
+
+.BR pam_authenticate "(3), "
+.BR pam_strerror "(3)"
+and
+.BR pam_open_session "(3). "
+
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam_start.3 b/contrib/libpam/doc/man/pam_start.3
new file mode 100644
index 000000000000..0299533b4f5e
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_start.3
@@ -0,0 +1,98 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: pam_start.3,v 1.2 1997/02/15 18:51:54 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1996-7 <morgan@parc.power.net>
+.TH PAM_START 3 "1997 Feb 15" "Linux-PAM 0.56" "Application Programmers' Manual"
+.SH NAME
+
+pam_start, pam_end \- activating Linux-PAM
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.sp
+.BI "int pam_start(const char " *service ", const char " *user ", const struct pam_conv " *conv ", pam_handle_t " **pamh_p ");"
+.sp
+.BI "int pam_end(pam_handle_t " *pamh ", int " pam_status ");"
+.sp 2
+.SH DESCRIPTION
+.TP
+.B pam_start
+Initialize the
+.I Linux-PAM
+library. Identifying the application with a particular
+.IR service
+name. The
+.IR user "name"
+can take the value
+.IR NULL ", "
+if not known at the time the interface is initialized. The
+conversation structure is passed to the library via the
+.IR conv
+argument. (For a complete description of this and other structures
+the reader is directed to the more verbose
+.IR Linux-PAM
+application developers' guide). Upon successful initialization, an
+opaque pointer-handle for future access to the library is returned
+through the contents of the
+.IR pamh_p
+pointer.
+
+.TP
+.B pam_end
+Terminate the
+.B Linux-PAM
+library. The service application associated with the
+.IR pamh
+handle, is terminated. The argument,
+.IR pam_status ", "
+passes the value most recently returned to the application from the
+library; it indicates the manner in which the library should be
+shutdown. Besides carrying a return value, this argument may be
+logically OR'd with
+.IR PAM_DATA_SILENT
+to indicate that the module should not treat the call too
+seriously. It is generally used to indicate that the current closing
+of the library is in a
+.IR fork "(2)ed"
+process, and that the parent will take care of cleaning up things that
+exist outside of the current process space (files etc.).
+
+.SH "RETURN VALUE"
+.TP
+.B pam_start
+.TP
+.B pam_end
+On success,
+.BR PAM_SUCCESS
+is returned
+
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(3). "
+
+.SH "CONFORMING TO"
+DCE-RFC 86.0, October 1995.
+.sp
+Note, the
+.BR PAM_DATA_SILENT
+flag is pending acceptance with the DCE (as of 1996/12/4).
+
+.SH BUGS
+.sp 2
+None known.
+
+.SH "SEE ALSO"
+
+.BR fork "(2), "
+.BR pam_authenticate "(3), "
+.BR pam_acct_mgmt "(3), "
+.BR pam_open_session "(3), "
+and
+.BR pam_chauthtok "(3)."
+
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/pam_strerror.3 b/contrib/libpam/doc/man/pam_strerror.3
new file mode 100644
index 000000000000..33b4fda4c31e
--- /dev/null
+++ b/contrib/libpam/doc/man/pam_strerror.3
@@ -0,0 +1,49 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" ripped off from Rick Faith's getgroups man page
+.\" $Id: pam_strerror.3,v 1.2 1997/02/15 18:53:04 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1996-7 <morgan@parc.power.net>
+.TH PAM_STRERROR 3 "1997 Feb 15" "Linux-PAM 0.56" "Programmers' Manual"
+.SH NAME
+
+pam_strerror \- return a textual description of a Linux-PAM error
+
+.SH SYNOPSIS
+.B #include <security/pam_appl.h>
+.br
+or,
+.br
+.B #include <security/pam_modules.h>
+.sp
+.BI "const char *pam_strerror(" int " pam_error);
+.sp 2
+.SH DESCRIPTION
+.B pam_strerror
+
+This function returns a pointer to a line of text describing the
+.BR Linux-PAM
+error passed as its sole argument.
+
+.SH "RETURN VALUE"
+
+On success this function returns a description of the indicated
+error. Should the function not recognize the error, ``Unknown
+Linux-PAM error'' is returned.
+
+.SH "CONFORMING TO"
+DCE-RFC 86.0, October 1995.
+
+.SH BUGS
+.sp 2
+This function should be internationalized.
+
+.SH "SEE ALSO"
+
+.BR pam "(8). "
+
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/man/template-man b/contrib/libpam/doc/man/template-man
new file mode 100644
index 000000000000..a635c8bd8024
--- /dev/null
+++ b/contrib/libpam/doc/man/template-man
@@ -0,0 +1,52 @@
+.\" Hey Emacs! This file is -*- nroff -*- source.
+.\" $Id: template-man,v 1.1 1997/01/04 18:25:13 morgan Exp $
+.\" Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>
+.TH PAM_???? 2 "1997 Jan 4" "Linux-PAM 0.55" "Application Programmers' Manual"
+.SH NAME
+
+function names \- brief summary of function
+
+.SH SYNOPSIS
+.B #include <security/pam_????.h>
+.sp
+.BI "int pam_???(pam_handle_t " pamh ", int " flags);
+.sp 2
+.SH DESCRIPTION
+.TP
+.B pam_???
+Here goes the
+.I explanation
+it may be quite
+.IR long .
+.TP
+.SH "RETURN VALUE"
+.B pam_???
+On success...
+.BR PAM_SUCCESS
+is returned
+.TP
+.SH ERRORS
+May be translated to text with
+.BR pam_strerror "(2). "
+
+.SH "CONFORMING TO"
+.B pam_???
+DCE-RFC 86.0, October 1995.
+
+.SH BUGS
+.sp 2
+none known.
+
+.SH "SEE ALSO"
+
+.BR pam_??? "(2), "
+and
+.BR pam_??? "(2). "
+
+Also, see the three
+.BR Linux-PAM
+Guides, for
+.BR "System administrators" ", "
+.BR "module developers" ", "
+and
+.BR "application developers" ". "
diff --git a/contrib/libpam/doc/modules/README b/contrib/libpam/doc/modules/README
new file mode 100644
index 000000000000..b97b2cd501b9
--- /dev/null
+++ b/contrib/libpam/doc/modules/README
@@ -0,0 +1,13 @@
+$Id: README,v 1.2 1996/11/17 17:20:28 morgan Exp $
+
+This directory contains a number of sgml sub-files. One for each
+documented module. They contain a description of each module and give
+some indication of its reliability.
+
+Additionally, there is a 'module.sgml-template' file which should be
+used as a blank form for new module descriptions.
+
+Please feel free to submit amendments/comments etc. regarding these
+files to:
+
+ Andrew G. Morgan <morgan@parc.power.net>
diff --git a/contrib/libpam/doc/modules/module.sgml-template b/contrib/libpam/doc/modules/module.sgml-template
new file mode 100644
index 000000000000..53cd809f338d
--- /dev/null
+++ b/contrib/libpam/doc/modules/module.sgml-template
@@ -0,0 +1,170 @@
+<!--
+
+ $Id: module.sgml-template,v 1.1 1996/11/30 20:59:32 morgan Exp $
+
+ This template file was written by Andrew G. Morgan
+ <morgan@parc.power.net>
+
+[
+ Text that should be deleted/replaced, is enclosed within
+ '[' .. ']'
+ marks. For example, this text should be deleted!
+]
+
+-->
+
+<sect1> [*Familiar full name of module*, eg. The "allow all" module.]
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+[
+ insert the name of the module
+
+ Blank is not permitted.
+]
+
+<tag><bf>Author[s]:</bf></tag>
+
+[
+ Insert author names here
+
+ Blank is not permitted. If in doubt, put "unknown" if the
+ author wishes to remain anonymous, put "anonymous".
+]
+
+<tag><bf>Maintainer:</bf></tag>
+
+[
+ Insert names and date-begun of most recent maintainer.
+]
+
+<tag><bf>Management groups provided:</bf></tag>
+
+[
+ list the subset of four management groups supported by the
+ module. Choose from: account; authentication; password;
+ session.
+
+ Blank entries are not permitted. Explicitly list all of the
+ management groups. In the future more may be added to libpam!
+]
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+[
+ Indicate whether this module contains code that can perform
+ reversible (strong) encryption. This field is primarily to
+ ensure that people redistributing it are not unwittingly
+ breaking laws...
+
+ Modules may also require the presence of some local library
+ that performs the necessary encryption via some standard API.
+ In this case "uses API" can be included in this field. The
+ library in question should be added to the system requirements
+ below.
+
+ Blank = no cryptography is used by module.
+]
+
+<tag><bf>Security rating:</bf></tag>
+
+[
+ Initially, this field should be left blank. If someone takes
+ it upon themselves to test the strength of the module, it can
+ later be filled.
+
+ Blank = unknown.
+]
+
+<tag><bf>Clean code base:</bf></tag>
+
+[
+ This will probably be filled by the libpam maintainer.
+ It can be considered to be a public humiliation list. :*)
+
+ I am of the opinion that "gcc -with_all_those_flags" is
+ trying to tell us something about whether the program
+ works as intended. Since there is currently no Security
+ evaluation procedure for modules IMHO this is not a
+ completely unreasonable indication (a lower bound anyway)
+ of the reliability of a module.
+
+ This field would indicate the number and flavor of
+ warnings that gcc barfs up when trying to compile the
+ module as part of the tree. Is this too tyrannical?
+
+ Blank = Linux-PAM maintainer has not tested it :)
+]
+
+<tag><bf>System dependencies:</bf></tag>
+
+[
+ here we list config files, dynamic libraries needed, system
+ resources, kernel options.. etc.
+
+ Blank = nothing more than libc required.
+]
+
+<tag><bf>Network aware:</bf></tag>
+
+[
+ Does the module base its behavior on probing a network
+ connection? Does it expect to be protected by the
+ application?
+
+ Blank = Ignorance of network.
+]
+
+</descrip>
+
+<sect2>Overview of module
+
+[
+ some text describing the intended actions of the module
+ general comments mainly (specifics in sections
+ below).
+]
+
+[
+
+ [ now we have a <sect2> level subsection for each of the
+ management groups. Include as many as there are groups
+ listed above in the synopsis ]
+
+<sect2>[ Account | Authentication | Password | Session ] component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+[
+ List the supported arguments (leave their description for the
+ description below.
+
+ Blank = no arguments are read and nothing is logged to syslog
+ about any arguments that are passed. Note, this
+ behavior is contrary to the RFC!
+]
+
+<tag><bf>Description:</bf></tag>
+
+[
+ This component of the module performs the task of ...
+]
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+[
+ Here we list some doos and don'ts for this module.
+]
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_chroot.sgml b/contrib/libpam/doc/modules/pam_chroot.sgml
new file mode 100644
index 000000000000..7f8c4a39b642
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_chroot.sgml
@@ -0,0 +1,86 @@
+<!--
+ $Id: pam_chroot.sgml,v 1.1 1996/11/30 20:59:32 morgan Exp $
+
+ This file was written by Bruce Campbell <brucec@humbug.org.au>
+-->
+
+<sect1>Chroot
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_chroot/
+
+<tag><bf>Author:</bf></tag>
+Bruce Campbell &lt;brucec@humbug.org.au&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author; proposed on 20/11/96 - email for status
+
+<tag><bf>Management groups provided:</bf></tag>
+account; session; authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+Unwritten.
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+Expects localhost.
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module is intended to provide a transparent wrapper around the
+average user, one that puts them in a fake file-system (eg, their
+'<tt>/</tt>' is really <tt>/some/where/else</tt>).
+
+<p>
+Useful if you have several classes of users, and are slightly paranoid
+about security. Can be used to limit who else users can see on the
+system, and to limit the selection of programs they can run.
+
+<sect2>Account component:
+
+<p>
+<em/Need more info here./
+
+<sect2>Authentication component:
+
+<p>
+<em/Need more info here./
+
+<sect2>Session component:
+
+<p>
+<em/Need more info here./
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+Arguments and logging levels for the PAM version are being worked on.
+
+<tag><bf>Description:</bf></tag>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+Do provide a reasonable list of programs - just tossing 'cat', 'ls', 'rm',
+'cp' and 'ed' in there is a bit...
+<p>
+Don't take it to extremes (eg, you can set up a separate environment for
+each user, but its a big waste of your disk space.)
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_cracklib.sgml b/contrib/libpam/doc/modules/pam_cracklib.sgml
new file mode 100644
index 000000000000..4700c2a04f03
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_cracklib.sgml
@@ -0,0 +1,254 @@
+<!--
+ $Id: pam_cracklib.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp morgan $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+ long password amendments are from Philip W. Dalrymple III <pwd@mdtsoft.com>
+-->
+
+<sect1>Cracklib pluggable password strength-checker
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+
+pam_cracklib
+
+<tag><bf>Author:</bf></tag>
+
+Cristian Gafton &lt;gafton@redhat.com&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+
+password
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+
+Requires the system library <tt/libcrack/ and a system dictionary:
+<tt>/usr/lib/cracklib_dict</tt>.
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module can be plugged into the <tt/password/ stack of a given
+application to provide some plug-in strength-checking for passwords.
+(XXX - note this does not necessarily work with the pam_unix module,
+although it is known to work with the pam_pwdb replacement for the
+unix module -- see example and pam_pwdb write up for more
+information).
+
+<p>
+This module works in the following manner: it first calls the
+<em>Cracklib</em> routine to check the strength of the password; if
+crack likes the password, the module does an additional set of
+strength checks. These checks are:
+<itemize>
+
+<item> <bf/Palindrome/ -
+
+Is the new password a palindrome of the old one?
+
+<item> <bf/Case Change Only/ -
+
+Is the new password the the old one with only a change of case?
+
+<item> <bf/Similar/ -
+
+Is the new password too much like the old one? This is controlled
+by one argument, <tt/difok/ which is a number of characters that if
+different between the old and new are enough to accept the new
+password, this defaults to 10 or 1/2 the size of the new password
+whichever is smaller.
+
+<item <bf/Simple/ -
+
+Is the new password too small? This is controlled by 5 arguments
+<tt/minlen/, <tt/dcredit/, <tt/ucredit/, <tt/lcredit/, and
+<tt/ocredit/. See the section on the arguments for the details of how
+these work and there defaults.
+
+<item <bf/Rotated/ -
+
+Is the new password a rotated version of the old password?
+
+</itemize>
+
+<p>
+This module with no arguments will work well for standard unix
+password encryption. With md5 encryption, passwords can be longer
+than 8 characters and the default settings for this module can make it
+hard for the user to choose a satisfactory new password. Notably, the
+requirement that the new password contain no more than 1/2 of the
+characters in the old password becomes a non-trivial constraint. For
+example, an old password of the form "the quick brown fox jumped over
+the lazy dogs" would be difficult to change... In addition, the
+default action is to allow passwords as small as 5 characters in
+length. For a md5 systems it can be a good idea to increase the
+required minimum size of a password. One can then allow more credit
+for different kinds of characters but accept that the new password may
+share most of these characters with the old password.
+
+<sect2>Password component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tt/debug/; <tt/type=XXX/; <tt/retry=N/; <tt/difok=N/; <tt/minlen=N/;
+<tt/dcredit=N/; <tt/ucredit=N/; <tt/lcredit=N/; <tt/ocredit=N/;
+
+<tag><bf>Description:</bf></tag>
+
+The action of this module is to prompt the user for a password and
+check its strength against a system dictionary and a set of rules for
+identifying poor choices.
+
+<p>
+The default action is to prompt for a single password, check its
+strength and then, if it is considered strong, prompt for the password
+a second time (to verify that it was typed correctly on the first
+occasion). All being well, the password is passed on to subsequent
+modules to be installed as the new authentication token.
+
+<p>
+The default action may be modified in a number of ways using the
+arguments recognized by the module:
+<itemize>
+
+<item> <tt/debug/ -
+
+this option makes the module write information to syslog(3) indicating
+the behavior of the module (this option does <bf/not/ write password
+information to the log file).
+
+<item> <tt/type=XXX/ -
+
+the default action is for the module to use the following prompts when
+requesting passwords: ``New UNIX password: '' and ``Retype UNIX
+password: ''. Using this option you can replace the word UNIX with
+<tt/XXX/.
+
+<item> <tt/retry=N/ -
+
+the default number of times this module will request a new password
+(for strength-checking) from the user is 1. Using this argument this
+can be increased to <tt/N/.
+
+<item> <tt/difok=N/ -
+
+This argument will change the default of 10 for the number of
+characters in the new password that must not be present in the old
+password. In addition, if 1/2 of the characters in the new password
+are different then the new password will be accepted anyway.
+
+<item> <tt/minlen=N/ -
+
+The minimum acceptable size for the new password plus one. In
+addition to the number of characters in the new password, credit (of
++1 in length) is given for each different kind of character (<em>other,
+upper, lower</em> and <em/digit/). The default for this parameter is
+9 which is good for a old style UNIX password all of the same type of
+character but may be too low to exploit the added security of a md5
+system. Note that there is a pair of length limits in
+<em>Cracklib</em> itself, a "way too short" limit of 4 which is hard
+coded in and a defined limit (6) that will be checked without
+reference to <tt>minlen</tt>. If you want to allow passwords as short
+as 5 characters you should either not use this module or recompile
+the crack library and then recompile this module.
+
+<item> <tt/dcredit=N/ -
+
+This is the maximum credit for having digits in the new password. If
+you have less than or <tt/N/ digits, each digit will count +1 towards
+meeting the current <tt/minlen/ value. The default for <tt/dcredit/
+is 1 which is the recommended value for <tt/minlen/ less than 10.
+
+<item> <tt/ucredit=N/ -
+
+This is the maximum credit for having upper case letters in the new
+password. If you have less than or <tt/N/ upper case letters each
+letter will count +1 towards meeting the current <tt/minlen/ value.
+The default for <tt/ucredit/ is 1 which is the recommended value for
+<tt/minlen/ less than 10.
+
+<item> <tt/lcredit=N/ -
+
+This is the maximum credit for having lower case letters in the new
+password. If you have less than or <tt/N/ lower case letters, each
+letter will count +1 towards meeting the current <tt/minlen/ value.
+The default for <tt/lcredit/ is 1 which is the recommended value for
+<tt/minlen/ less than 10.
+
+<item> <tt/ocredit=N/ -
+
+This is the maximum credit for having other characters in the new
+password. If you have less than or <tt/N/ other characters, each
+character will count +1 towards meeting the current <tt/minlen/ value.
+The default for <tt/ocredit/ is 1 which is the recommended value for
+<tt/minlen/ less than 10.
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+(At the time of writing, this module can only be stacked before the
+<tt/pam_pwdb/ module. Cracklib strength checking may be compiled by
+default into the <tt/pam_unix/ module.)
+
+<p>
+For an example of the use of this module, we show how it may be
+stacked with the password component of <tt/pam_pwdb/:
+<tscreen>
+<verb>
+#
+# These lines stack two password type modules. In this example the
+# user is given 3 opportunities to enter a strong password. The
+# "use_authtok" argument ensures that the pam_pwdb module does not
+# prompt for a password, but instead uses the one provided by
+# pam_cracklib.
+#
+passwd password required pam_cracklib.so retry=3
+passwd password required pam_pwdb.so use_authtok
+</verb>
+</tscreen>
+
+<p>
+Another example (in the <tt>/etc/pam.d/passwd</tt> format) is for the
+case that you want to use md5 password encryption:
+<tscreen>
+<verb>
+#%PAM-1.0
+#
+# These lines allow a md5 systems to support passwords of at least 14
+# bytes with extra credit of 2 for digits and 2 for others the new
+# password must have at least three bytes that are not present in the
+# old password
+#
+password required pam_cracklib.so \
+ difok=3 minlen=15 dcredit= 2 ocredit=2
+password required pam_pwdb.so use_authtok nullok md5
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_deny.sgml b/contrib/libpam/doc/modules/pam_deny.sgml
new file mode 100644
index 000000000000..99f367156fe5
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_deny.sgml
@@ -0,0 +1,179 @@
+<!--
+ $Id: pam_deny.sgml,v 1.3 1997/02/15 18:25:44 morgan Exp morgan $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The locking-out module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+pam_deny
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+current <bf/Linux-PAM/ maintainer
+
+<tag><bf>Management groups provided:</bf></tag>
+account; authentication; password; session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+clean.
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module can be used to deny access. It always indicates a failure
+to the application through the PAM framework. As is commented in the
+overview section <ref id="overview-section" name="above">, this module
+might be suitable for using for default (the <tt/OTHER/) entries.
+
+<sect2>Account component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This component does nothing other than return a failure. The
+failure type is <tt/PAM_ACCT_EXPIRED/.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+Stacking this module with type <tt/account/ will prevent the user from
+gaining access to the system via applications that refer to
+<bf/Linux-PAM/'s account management function <tt/pam_acct_mgmt()/.
+
+<p>
+The following example would make it impossible to login:
+<tscreen>
+<verb>
+#
+# add this line to your other login entries to disable all accounts
+#
+login account required pam_deny.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This component does nothing other than return a failure. The failure
+type is <tt/PAM_AUTH_ERR/ in the case that <tt/pam_authenticate()/ is
+called (when the application tries to authenticate the user), and is
+<tt/PAM_CRED_UNAVAIL/ when the application calls <tt/pam_setcred()/
+(to establish and set the credentials of the user -- it is unlikely
+that this function will ever be called in practice).
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+To deny access to default applications with this component of the
+<tt/pam_deny/ module, you might include the following line in your
+<bf/Linux-PAM/ configuration file:
+<tscreen>
+<verb>
+#
+# add this line to your existing OTHER entries to prevent
+# authentication succeeding with default applications.
+#
+OTHER auth required pam_deny.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<sect2>Password component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This component of the module denies the user the opportunity to change
+their password. It always responds with <tt/PAM_AUTHTOK_ERR/ when
+invoked.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+This module should be used to prevent an application from updating the
+applicant user's password. For example, to prevent <tt/login/ from
+automatically prompting for a new password when the old one has
+expired you should include the following line in your configuration
+file:
+<tscreen>
+<verb>
+#
+# add this line to your other login entries to prevent the login
+# application from being able to change the user's password.
+#
+login password required pam_deny.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<sect2>Session component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This aspect of the module prevents an application from starting a
+session on the host computer.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+Together with another session module, that displays a message of the
+day perhaps (XXX - such a module needs to be written),
+this module can be used to block a user from starting a shell. Given
+the presence of a <tt/pam_motd/ module, we might use the following
+entries in the configuration file to inform the user it is system
+time:
+<tscreen>
+<verb>
+#
+# An example to see how to configure login to refuse the user a
+# session (politely)
+#
+login session required pam_motd.so \
+ file=/etc/system_time
+login session required pam_deny.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_env.sgml b/contrib/libpam/doc/modules/pam_env.sgml
new file mode 100644
index 000000000000..a62f4576f132
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_env.sgml
@@ -0,0 +1,125 @@
+<!--
+ $Id: pam_env.sgml,v 1.1 1997/04/05 06:50:42 morgan Exp $
+
+ This file was written by Dave Kinchlea <kinch@kinch.ark.com>
+ Ed. AGM
+-->
+
+<sect1>Set/unset environment variables
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_env/
+
+<tag><bf>Author:</bf></tag>
+Dave Kinchlea &lt;kinch@kinch.ark.com&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author
+
+<tag><bf>Management groups provided:</bf></tag>
+Authentication (setcred)
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+<tt>/etc/security/pam_env.conf</tt>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module allows the (un)setting of environment variables. Supported
+is the use of previously set environment variables as well as
+<em>PAM_ITEM</em>s such as <tt>PAM_RHOST</tt>.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/; <tt/conffile=/<em/configuration-file-name/
+
+<tag><bf>Description:</bf></tag>
+This module allows you to (un)set arbitrary environment variables
+using fixed strings, the value of previously set environment variables
+and/or <em/PAM_ITEM/s.
+
+<p>
+All is controlled via a configuration file (by default,
+<tt>/etc/security/pam_env.conf</tt> but can be overriden with
+<tt>connfile</tt> argument). Each line starts with the variable name,
+there are then two possible options for each variable <bf>DEFAULT</bf>
+and <bf>OVERRIDE</bf>. <bf>DEFAULT</bf> allows and administrator to
+set the value of the variable to some default value, if none is
+supplied then the empty string is assumed. The <bf>OVERRIDE</bf>
+option tells pam_env that it should enter in its value (overriding the
+default value) if there is one to use. <bf>OVERRIDE</bf> is not used,
+<tt>""</tt> is assumed and no override will be done.
+
+<p>
+<tscreen>
+<verb>
+VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]]
+</verb>
+</tscreen>
+
+<p>
+(Possibly non-existent) environment variables may be used in values
+using the <tt>&dollar;&lcub;string&rcub;</tt> syntax and (possibly
+non-existent) <em/PAM_ITEM/s may be used in values using the
+<tt>&commat;&lcub;string&rcub;</tt> syntax. Both the <tt>&dollar;</tt>
+and <tt>&commat;</tt> characters can be backslash-escaped to be used
+as literal values (as in <tt>&bsol;&dollar;</tt>. Double quotes may
+be used in values (but not environment variable names) when white
+space is needed <bf>the full value must be delimited by the quotes and
+embedded or escaped quotes are not supported</bf>.
+
+<p>
+The behavior of this module can be modified with one of the following
+flags:
+
+<p>
+<itemize>
+
+<item><tt/debug/
+- write more information to <tt/syslog(3)/.
+
+<item><tt/conffile=/<em/filename/
+- by default the file <tt>/etc/security/pam_env.conf</tt> is used as
+the configuration file. This option overrides the default. You must
+supply a complete path + file name.
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+See sample <tt>pam_env.conf</tt> for more information and examples.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/libpam/doc/modules/pam_filter.sgml b/contrib/libpam/doc/modules/pam_filter.sgml
new file mode 100644
index 000000000000..99f06ef01b64
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_filter.sgml
@@ -0,0 +1,150 @@
+<!--
+ $Id: pam_filter.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The filter module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+
+pam_filter
+
+<tag><bf>Author:</bf></tag>
+
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+
+account; authentication; password; session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+Not yet.
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+This module compiles cleanly on Linux based systems.
+
+<tag><bf>System dependencies:</bf></tag>
+
+To function it requires <em/filters/ to be installed on the system.
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module was written to offer a plug-in alternative to programs
+like ttysnoop (XXX - need a reference). Since writing a filter that
+performs this function has not occurred, it is currently only a toy.
+The single filter provided with the module simply transposes upper and
+lower case letters in the input and output streams. (This can be very
+annoying and is not kind to termcap based editors).
+
+<sect2>Account+Authentication+Password+Session components
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tt/debug/; <tt/new_term/; <tt/non_term/; <tt/runX/
+
+<tag><bf>Description:</bf></tag>
+
+Each component of the module has the potential to invoke the desired
+filter. The filter is always <tt/execv(2)/d with the privilege of the
+calling application and <bf/not/ that of the user. For this reason it
+cannot usually be killed by the user without closing their session.
+
+<p>
+The behavior of the module can be significantly altered by the
+arguments passed to it in the <bf/Linux-PAM/ configuration file:
+<itemize>
+<item><tt/debug/ -
+
+this option increases the amount of information logged to
+<tt/syslog(3)/ as the module is executed.
+
+<item><tt/new_term/ -
+
+the default action of the filter is to set the <tt/PAM_TTY/ item to
+indicate the terminal that the user is using to connect to the
+application. This argument indicates that the filter should set
+<tt/PAM_TTY/ to the filtered pseudo-terminal.
+
+<item><tt/non_term/ -
+don't try to set the <tt/PAM_TTY/ item.
+
+<item><tt/runX/ -
+
+in order that the module can invoke a filter it should know when to
+invoke it. This argument is required to tell the filter when to do
+this. The arguments that follow this one are respectively the full
+pathname of the filter to be run and any command line arguments that
+the filter might expect.
+
+<p>
+Permitted values for <tt/X/ are <tt/1/ and <tt/2/. These indicate the
+precise time the that filter is to be run. To explain this concept it
+will be useful to have read the Linux-PAM Module developer's
+guide. Basically, for each management group there are up to two ways
+of calling the module's functions.
+
+In the case of the <em/authentication/ and <em/session/ components
+there are actually two separate functions. For the case of
+authentication, these functions are <tt/_authenticate/ and
+<tt/_setcred/ -- here <tt/run1/ means run the filter from the
+<tt/_authenticate/ function and <tt/run2/ means run the filter from
+<tt/_setcred/. In the case of the session modules, <tt/run1/ implies
+that the filter is invoked at the <tt/_open_session/ stage, and
+<tt/run2/ for <tt/_close_session/.
+
+<p>
+For the case of the account component. Either <tt/run1/ or <tt/run2/
+may be used.
+
+<p>
+For the case of the password component, <tt/run1/ is used to indicate
+that the filter is run on the first occasion <tt/_chauthtok/ is run
+(the <tt/PAM_PRELIM_CHECK/ phase) and <tt/run2/ is used to indicate
+that the filter is run on the second occasion (the
+<tt/PAM_UPDATE_AUTHTOK/ phase).
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+At the time of writing there is little real use to be made of this
+module. For fun you might try adding the following line to your
+login's configuration entries
+<tscreen>
+<verb>
+#
+# An example to see how to configure login to transpose upper and
+# lower case letters once the user has logged in(!)
+#
+login session required pam_filter.so \
+ run1 /usr/sbin/pam_filter/upperLOWER
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_ftp.sgml b/contrib/libpam/doc/modules/pam_ftp.sgml
new file mode 100644
index 000000000000..ca2e065d0122
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_ftp.sgml
@@ -0,0 +1,93 @@
+<!--
+ $Id: pam_ftp.sgml,v 1.1 1996/11/30 20:59:32 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>Anonymous access module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_ftp.so/
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+prompts for email address of user; easily spoofed (XXX - needs work)
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+The purpose of this module is to provide a pluggable anonymous ftp
+mode of access.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/;
+<tt/users=XXX,YYY,.../;
+<tt/ignore/
+
+<tag><bf>Description:</bf></tag>
+
+This module intercepts the user's name and password. If the name is
+``<tt/ftp/'' or ``<tt/anonymous/'', the user's password is broken up
+at the `<tt/@/' delimiter into a <tt/PAM_RUSER/ and a <tt/PAM_RHOST/
+part; these pam-items being set accordingly. The username is set to
+``<tt/ftp/''. In this case the module succeeds. Alternatively, the
+module sets the <tt/PAM_AUTHTOK/ item with the entered password and
+fails.
+
+<p>
+The behavior of the module can be modified with the following flags:
+<itemize>
+<item><tt/debug/ -
+log more information to with <tt/syslog(3)/.
+
+<item><tt/users=XXX,YYY,.../ -
+instead of ``<tt/ftp/'' or ``<tt/anonymous/'', provide anonymous login
+to the comma separated list of users; ``<tt/XXX,YYY,.../''. Should the
+applicant enter one of these usernames the returned username is set to
+the first in the list; ``<tt/XXX/''.
+
+<item><tt/ignore/ -
+pay no attention to the email address of the user (if supplied).
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+An example of the use of this module is provided in the configuration
+file section <ref id="configuration" name="above">. With care, this
+module could be used to provide new/temporary account anonymous
+login.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_group.sgml b/contrib/libpam/doc/modules/pam_group.sgml
new file mode 100644
index 000000000000..360edee06afb
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_group.sgml
@@ -0,0 +1,108 @@
+<!--
+ $Id: pam_group.sgml,v 1.2 1997/01/04 20:50:10 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The group access module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_group/
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+Sensitive to <em/setgid/ status of file-systems accessible to users.
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+Requires an <tt>/etc/security/group.conf</tt> file. Can be compiled
+with or without <tt/libpwdb/.
+
+<tag><bf>Network aware:</bf></tag>
+Only through correctly set <tt/PAM_TTY/ item.
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module provides group-settings based on the user's name and the
+terminal they are requesting a given service from. It takes note of
+the time of day.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This module does not authenticate the user, but instead it grants
+group memberships (in the credential setting phase of the
+authentication module) to the user. Such memberships are based on the
+service they are applying for. The group memberships are listed in
+text form in the <tt>/etc/security/group.conf</tt> file.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+For this module to function correctly there must be a correctly
+formatted <tt>/etc/security/groups.conf</tt> file present. The format
+of this file is as follows. Group memberships are given based on the
+service application satisfying any combination of lines in the
+configuration file. Each line (barring comments which are preceded by
+`<tt/#/' marks) has the following
+syntax:
+<tscreen>
+<verb>
+services ; ttys ; users ; times ; groups
+</verb>
+</tscreen>
+Here the first four fields share the syntax of the <tt>pam_time</tt>
+configuration file; <tt>/etc/security/pam_time.conf</tt>, and the last
+field, the <tt/groups/ field, is a comma (or space) separated list of
+the text-names of a selection of groups. If the users application for
+service satisfies the first four fields, the user is granted membership
+of the listed groups.
+
+<p>
+As stated in above this module's usefulness relies on the file-systems
+accessible to the user. The point being that once granted the
+membership of a group, the user may attempt to create a <em/setgid/
+binary with a restricted group ownership. Later, when the user is not
+given membership to this group, they can recover group membership with
+the precompiled binary. The reason that the file-systems that the user
+has access to are so significant, is the fact that when a system is
+mounted <em/nosuid/ the user is unable to create or execute such a
+binary file. For this module to provide any level of security, all
+file-systems that the user has write access to should be mounted
+<em/nosuid/.
+
+<p>
+The <tt>pam_group</tt> module fuctions in parallel with the
+<tt>/etc/group</tt> file. If the user is granted any groups based on
+the behavior of this module, they are granted <em>in addition</em> to
+those entries <tt>/etc/group</tt> (or equivalent).
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_krb4.sgml b/contrib/libpam/doc/modules/pam_krb4.sgml
new file mode 100644
index 000000000000..edb87d1a0584
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_krb4.sgml
@@ -0,0 +1,126 @@
+<!--
+ $Id: pam_krb4.sgml,v 1.1 1996/11/30 20:59:32 morgan Exp $
+
+ This file was written by Derrick J. Brashear <shadow@DEMENTIA.ORG>
+-->
+
+<sect1>The Kerberos 4 module.
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_krb4/
+
+<tag><bf>Author:</bf></tag>
+Derrick J. Brashear &lt;shadow@dementia.org&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication; password; session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+uses API
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+libraries - <tt/libkrb/, <tt/libdes/, <tt/libcom_err/, <tt/libkadm/;
+and a set of Kerberos include files.
+
+<tag><bf>Network aware:</bf></tag>
+Gets Kerberos ticket granting ticket via a Kerberos key distribution
+center reached via the network.
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module provides an interface for doing Kerberos verification of a
+user's password, getting the user a Kerberos ticket granting ticket
+for use with the Kerberos ticket granting service, destroying the
+user's tickets at logout time, and changing a Kerberos password.
+
+<sect2> Session component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This component of the module currently sets the user's <tt/KRBTKFILE/
+environment variable (although there is currently no way to export
+this), as well as deleting the user's ticket file upon logout (until
+<tt/PAM_CRED_DELETE/ is supported by <em/login/).
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+This part of the module won't be terribly useful until we can change
+the environment from within a <tt/Linux-PAM/ module.
+
+</descrip>
+
+<sect2> Password component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/use_first_pass/; <tt/try_first_pass/
+
+<tag><bf>Description:</bf></tag>
+
+This component of the module changes a user's Kerberos password
+by first getting and using the user's old password to get
+a session key for the password changing service, then sending
+a new password to that service.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+This should only be used with a real Kerberos v4 <tt/kadmind/. It
+cannot be used with an AFS kaserver unless special provisions are
+made. Contact the module author for more information.
+
+</descrip>
+
+<sect2> Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/use_first_pass/; <tt/try_first_pass/
+
+<tag><bf>Description:</bf></tag>
+
+This component of the module verifies a user's Kerberos password
+by requesting a ticket granting ticket from the Kerberos server
+and optionally using it to attempt to retrieve the local computer's
+host key and verifying using the key file on the local machine if
+one exists.
+
+It also writes out a ticket file for the user to use later, and
+deletes the ticket file upon logout (not until <tt/PAM_CRED_DELETE/
+is called from <em/login/).
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+This module can be used with a real Kerberos server using MIT
+v4 Kerberos keys. The module or the system Kerberos libraries
+may be modified to support AFS style Kerberos keys. Currently
+this is not supported to avoid cryptography constraints.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_lastlog.sgml b/contrib/libpam/doc/modules/pam_lastlog.sgml
new file mode 100644
index 000000000000..8c0e662c3cf9
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_lastlog.sgml
@@ -0,0 +1,119 @@
+<!--
+ $Id: pam_mail.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The last login module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_lastlog/
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author
+
+<tag><bf>Management groups provided:</bf></tag>
+auth
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+uses information contained in the <tt>/var/log/wtmp</tt> file.
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This session module maintains the <tt>/var/log/wtmp</tt> file. Adding
+an open entry when called via the <tt>pam_open_seesion()</tt> function
+and completing it when <tt>pam_close_session()</tt> is called. This
+module can also display a line of information about the last login of
+the user. If an application already performs these tasks, it is not
+necessary to use this module.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/; <tt/nodate/; <tt/noterm/; <tt/nohost/; <tt/silent/;
+<tt/never/
+
+<tag><bf>Description:</bf></tag>
+
+<p>
+This module can be used to provide a ``Last login on ...''
+message. when the user logs into the system from what ever application
+uses the PAM libraries. In addition, the module maintains the
+<tt>/var/log/wtmp</tt> file.
+
+<p>
+The behavior of this module can be modified with one of the following
+flags:
+
+<p>
+<itemize>
+<item><tt/debug/
+- write more information to <tt/syslog(3)/.
+
+<item><tt/nodate/
+- neglect to give the date of the last login when displaying
+information about the last login on the system.
+
+<item><tt/noterm/
+- neglect to diplay the terminal name on which the last login was
+attempt.
+
+<item><tt/nohost/
+- neglect to indicate from which host the last login was attempted.
+
+<item><tt/silent/
+- neglect to inform the user about any previous login: just update
+the <tt>/var/log/wtmp</tt> file.
+
+<item><tt/never/
+- if the <tt>/var/log/wtmp</tt> file does not contain any old entries
+for the user, indicate that the user has never previously logged in
+with a ``welcome..." message.
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+This module can be used to indicate that the user has new mail when
+they <em/login/ to the system. Here is a sample entry for your
+<tt>/etc/pam.conf</tt> file:
+<tscreen>
+<verb>
+#
+# do we have any mail?
+#
+login session optional pam_lastlog.so
+</verb>
+</tscreen>
+
+<p>
+Note, some applications may perform this function themselves. In such
+cases, this module is not necessary.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_limits.sgml b/contrib/libpam/doc/modules/pam_limits.sgml
new file mode 100644
index 000000000000..6b98ea64fcbd
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_limits.sgml
@@ -0,0 +1,196 @@
+<!--
+ $Id: pam_limits.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+ from information compiled by Cristian Gafton (author of module)
+-->
+
+<sect1>The resource limits module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_limits/
+
+<tag><bf>Authors:</bf></tag>
+Cristian Gafton &lt;gafton@redhat.com&gt; <newline>
+Thanks are also due to Elliot Lee &lt;sopwith@redhat.com&gt;
+for his comments on improving this module.
+
+<tag><bf>Maintainer:</bf></tag>
+Cristian Gafton - 1996/11/20
+
+<tag><bf>Management groups provided:</bf></tag>
+session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+requires an <tt>/etc/security/limits.conf</tt> file and kernel support
+for resource limits. Also uses the library, <tt/libpwdb/.
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module, through the <bf/Linux-PAM/ <em/open/-session hook, sets
+limits on the system resources that can be obtained in a
+user-session. Its actions are dictated more explicitly through the
+configuration file discussed below.
+
+<sect2>Session component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/; <tt>conf=/path/to/file.conf</tt>
+
+<tag><bf>Description:</bf></tag>
+
+Through the contents of the configuration file,
+<tt>/etc/security/limits.conf</tt>, resource limits are placed on
+users' sessions. Users of <tt/uid=0/ are not affected by this
+restriction.
+
+<p>
+The behavior of this module can be modified with the following
+arguments:
+<itemize>
+
+<item><tt/debug/ -
+verbose logging to <tt/syslog(3)/.
+
+<item><tt>conf=/path/to/file.conf</tt> -
+indicate an alternative <em/limits/ configuration file to the default.
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+In order to use this module the system administrator must first create
+a <em/root-only-readable/ file (default is
+<tt>/etc/security/limits.conf</tt>). This file describes the resource
+limits the superuser wishes to impose on users and groups. No limits
+are imposed on <tt/uid=0/ accounts.
+
+<p>
+Each line of the configuration file describes a limit for a user in
+the form:
+<tscreen>
+<verb>
+<domain> <type> <item> <value>
+</verb>
+</tscreen>
+
+<p>
+The fields listed above should be filled as follows...<newline>
+<tt>&lt;domain&gt;</tt> can be:
+<itemize>
+<item> a username
+<item> a groupname, with <tt>@group</tt> syntax
+<item> the wild-card <tt/*/, for default entry
+</itemize>
+
+<p>
+<tt>&lt;type&gt;</tt> can have the two values:
+<itemize>
+
+<item> <tt/hard/ for enforcing <em/hard/ resource limits. These limits
+are set by the superuser and enforced by the Linux Kernel. The user
+cannot raise his requirement of system resources above such values.
+
+<item> <tt/soft/ for enforcing <em/soft/ resource limits. These limits
+are ones that the user can move up or down within the permitted range
+by any pre-exisiting <em/hard/ limits. The values specified with this
+token can be thought of as <em/default/ values, for normal system
+usage.
+
+</itemize>
+
+<p>
+<tt>&lt;item&gt;</tt> can be one of the following:
+<itemize>
+<item><tt/core/ - limits the core file size (KB)
+<item><tt/data/ - max data size (KB)
+<item><tt/fsize/ - maximum filesize (KB)
+<item><tt/memlock/ - max locked-in-memory address space (KB)
+<item><tt/nofile/ - max number of open files
+<item><tt/rss/ - max resident set size (KB)
+<item><tt/stack/ - max stack size (KB)
+<item><tt/cpu/ - max CPU time (MIN)
+<item><tt/nproc/ - max number of processes
+<item><tt/as/ - address space limit
+<item><tt/maxlogins/ - max number of logins for this user.
+</itemize>
+
+<p>
+To completely disable limits for a user (or a group), a single dash
+(-) will do (Example: ``<tt/bin -/'', ``<tt/@admin -/''). Please
+remember that individual limits have priority over group limits, so if
+you impose no limits for <tt/admin/ group, but one of the members in this
+group have a limits line, the user will have its limits set according
+to this line.
+
+<p>
+Also, please note that all limit settings are set <em/per login/.
+They are not global, nor are they permanent; existing only for the
+duration of the session.
+
+<p>
+In the <em/limits/ configuration file, the ``<tt/#/'' character
+introduces a comment - after which the rest of the line is ignored.
+
+<p>
+The <tt/pam_limits/ module does its best to report configuration
+problems found in its configuration file via <tt/syslog(3)/.
+
+<p>
+The following is an example configuration file:
+<tscreen>
+<verb>
+# EXAMPLE /etc/security/limits.conf file:
+# =======================================
+# <domain> <type> <item> <value>
+* soft core 0
+* hard rss 10000
+@student hard nproc 20
+@faculty soft nproc 20
+@faculty hard nproc 50
+ftp hard nproc 0
+@student - maxlogins 4
+</verb>
+</tscreen>
+Note, the use of <tt/soft/ and <tt/hard/ limits for the same resource
+(see <tt/@faculty/) -- this establishes the <em/default/ and permitted
+<em/extreme/ level of resources that the user can can obtain in a
+given service-session.
+
+<p>
+For the services that need resources limits (login for example) put a
+the following line in <tt>/etc/pam.conf</tt> as the last line for that
+service (usually after the pam_unix session line:
+<tscreen>
+<verb>
+#
+# Resource limits imposed on login sessions via pam_limits
+#
+login session required pam_limits.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_listfile.sgml b/contrib/libpam/doc/modules/pam_listfile.sgml
new file mode 100644
index 000000000000..fe4a0d27cc2e
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_listfile.sgml
@@ -0,0 +1,138 @@
+<!--
+ $Id: pam_listfile.sgml,v 1.3 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Michael K. Johnson <johnsonm@redhat.com>
+-->
+
+<sect1>The list-file module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_listfile/
+
+<tag><bf>Author:</bf></tag>
+Elliot Lee <tt>&lt;sopwith@cuc.edu&gt;</tt>
+
+<tag><bf>Maintainer:</bf></tag>
+Red Hat Software:<newline>
+Michael K. Johnson &lt;johnsonm@redhat.com&gt; 1996/11/18<newline>
+(if unavailable, contact Elliot Lee &lt;sopwith@cuc.edu&gt;).
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+clean
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+The list-file module provides a way to deny or allow services based on
+an arbitrary file.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tt>onerr=succeed|fail</tt>;
+<tt>sense=allow|deny</tt>;
+<tt>file=</tt><it>filename</it>;
+<tt>item=user|tty|rhost|ruser|group|shell</tt>
+<tt>apply=user|@group</tt>
+
+<tag><bf>Description:</bf></tag>
+
+The module gets the item of the type specified -- <tt>user</tt> specifies
+the username, <tt>PAM_USER</tt>; tty specifies the name of the terminal
+over which the request has been made, <tt>PAM_TTY</tt>; rhost specifies
+the name of the remote host (if any) from which the request was made,
+<tt>PAM_RHOST</tt>; and ruser specifies the name of the remote user
+(if available) who made the request, <tt>PAM_RUSER</tt> -- and looks for
+an instance of that item in the file <it>filename</it>. <it>filename</it>
+contains one line per item listed. If the item is found, then if
+<tt>sense=allow</tt>, <tt>PAM_SUCCESS</tt> is returned, causing the
+authorization request to succeed; else if <tt>sense=deny</tt>,
+<tt>PAM_AUTH_ERR</tt> is returned, causing the authorization
+request to fail.
+
+<p>
+If an error is encountered (for instance, if <it>filename</it>
+does not exist, or a poorly-constructed argument is encountered),
+then if <tt>onerr=succeed</tt>, <tt>PAM_SUCCESS</tt> is returned,
+otherwise if <tt>onerr=fail</tt>, <tt>PAM_AUTH_ERR</tt> or
+<tt>PAM_SERVICE_ERR</tt> (as appropriate) will be returned.
+
+<p>
+An additional argument, <tt>apply=</tt>, can be used to restrict the
+application of the above to a specific user
+(<tt>apply=</tt><em>username</em>) or a given group
+(<tt>apply=@</tt><em>groupname</em>). This added restriction is only
+meaningful when used with the <tt/tty/, <tt/rhost/ and <tt/shell/
+<em/items/.
+
+<p>
+Besides this last one, all arguments should be specified; do not count
+on any default behavior, as it is subject to change.
+
+<p>
+No credentials are awarded by this module.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+Classic ``ftpusers'' authentication can be implemented with this entry
+in <tt>/etc/pam.conf</tt>:
+<tscreen>
+<verb>
+#
+# deny ftp-access to users listed in the /etc/ftpusers file
+#
+ftp auth required pam_listfile.so \
+ onerr=succeed item=user sense=deny file=/etc/ftpusers
+</verb>
+</tscreen>
+Note, users listed in <tt>/etc/ftpusers</tt> file are
+(counterintuitively) <bf/not/ allowed access to the ftp service.
+
+<p>
+To allow login access only for certain users, you can use an
+pam.conf entry like this:
+<tscreen>
+<verb>
+#
+# permit login to users listed in /etc/loginusers
+#
+login auth required pam_listfile.so \
+ onerr=fail item=user sense=allow file=/etc/loginusers
+</verb>
+</tscreen>
+
+<p>
+For this example to work, all users who are allowed to use the login
+service should be listed in the file <tt>/etc/loginusers</tt>. Unless
+you are explicitly trying to lock out root, make sure that when you do
+this, you leave a way for root to log in, either by listing root in
+<tt>/etc/loginusers</tt>, or by listing a user who is able to <em/su/
+to the root account.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_mail.sgml b/contrib/libpam/doc/modules/pam_mail.sgml
new file mode 100644
index 000000000000..9a99f2064c36
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_mail.sgml
@@ -0,0 +1,124 @@
+<!--
+ $Id: pam_mail.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The mail module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_mail/
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author
+
+<tag><bf>Management groups provided:</bf></tag>
+auth
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+Default mail directory <tt>/var/spool/mail/</tt>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module looks at the user's mail directory and indicates
+whether the user has any mail in it.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/; <tt/dir=/<em/direcory-name/; <tt/nopen/; <tt/close/;
+<tt/noenv/; <tt/empty/
+
+<tag><bf>Description:</bf></tag>
+
+This module provides the ``you have new mail'' service to the user. It
+can be plugged into any application that has credential hooks. It gives a
+single message indicating the <em/newness/ of any mail it finds in the
+user's mail folder. This module also sets the <bf/Linux-PAM/
+environment variable, <tt/MAIL/, to the user's mail directory.
+
+<p>
+Although the module supplies functions for the authentication
+management group of functions, it cannot be used to authenticate a
+user; its authentication function instructs <tt/libpam/ to simply
+ignore it when authenticating the user.
+
+<p>
+The behavior of this module can be modified with one of the following
+flags:
+
+<p>
+<itemize>
+<item><tt/debug/
+- write more information to <tt/syslog(3)/.
+
+<item><tt/dir=/<em/pathname/
+- look for the users' mail in an alternative directory given by
+<em/pathname/. The default location for mail is
+<tt>/var/spool/mail</tt>. Note, if the supplied <em/pathname/ is
+prefixed by a `<tt/&tilde;/', the directory is interpreted as
+indicating a file in the user's home directory.
+
+<item><tt/nopen/
+- instruct the module to <em/not/ print any mail information when the
+user's credentials are acquired. This flag is useful to get the <tt/MAIL/
+environment variable set, but to not display any information about it.
+
+<item><tt/close/
+- instruct the module to indicate if the user has any mail at the as
+the user's credentials are revoked.
+
+<item><tt/noenv/
+- do not set the <tt/MAIL/ environment variable.
+
+<item><tt/empty/
+- indicate that the user's mail directory is empty if this is found to
+be the case.
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+This module can be used to indicate that the user has new mail when
+they <em/login/ to the system. Here is a sample entry for your
+<tt>/etc/pam.conf</tt> file:
+<tscreen>
+<verb>
+#
+# do we have any mail?
+#
+login auth optional pam_mail.so
+</verb>
+</tscreen>
+
+<p>
+Note, some applications may perform this function themselves. In such
+cases, this module is not necessary.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_nologin.sgml b/contrib/libpam/doc/modules/pam_nologin.sgml
new file mode 100644
index 000000000000..de4b32a8efbd
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_nologin.sgml
@@ -0,0 +1,75 @@
+<!--
+ $Id: pam_nologin.sgml,v 1.2 1997/01/04 21:56:55 morgan Exp $
+
+ This file was written by Michael K. Johnson <johnsonm@redhat.com>
+-->
+
+<sect1>The no-login module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_nologin/
+
+<tag><bf>Author:</bf></tag>
+Written by Michael K. Johnson &lt;johnsonm@redhat.com&gt;<newline>
+(based on code taken from a module written by Andrew G. Morgan
+&lt;morgan@parc.power.net&gt;).
+
+<tag><bf>Maintainer:</bf></tag>
+Michael K. Johnson &lt;johnsonm@redhat.com&gt;
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+1 warning about dropping const
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+Provides standard Unix <em/nologin/ authentication.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+Provides standard Unix <em/nologin/ authentication. If the file
+<tt>/etc/nologin</tt> exists, only root is allowed to log in; other
+users are turned away with an error message. All users (root or
+otherwise) are shown the contents of <tt>/etc/nologin</tt>.
+
+<p>
+If the file <tt>/etc/nologin</tt> does not exist, this module succeeds
+silently.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+In order to make this module effective, all login methods should
+be secured by it. It should be used as a <tt>required</tt>
+method listed before any <tt>sufficient</tt> methods in order to
+get standard Unix nologin semantics.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_permit.sgml b/contrib/libpam/doc/modules/pam_permit.sgml
new file mode 100644
index 000000000000..84df9fc1754f
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_permit.sgml
@@ -0,0 +1,83 @@
+<!--
+ $Id: pam_permit.sgml,v 1.2 1997/02/15 18:20:12 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The promiscuous module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+pam_permit
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan, &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Linux-PAM maintainer.
+
+<tag><bf>Management groups provided:</bf></tag>
+account; authentication; password; session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+VERY LOW. Use with extreme caution.
+
+<tag><bf>Clean code base:</bf></tag>
+Clean.
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module is very dangerous. It should be used with extreme
+caution. Its action is always to permit access. It does nothing else.
+
+<sect2>Account+Authentication+Password+Session components
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+No matter what management group, the action of this module is to
+simply return <tt/PAM_SUCCESS/ -- operation successful.
+
+<p>
+In the case of authentication, the user's name will be acquired. Many
+applications become confused if this name is unknown.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+It is seldom a good idea to use this module. However, it does have
+some legitimate uses. For example, if the system-administrator wishes
+to turn off the account management on a workstation, and at the same
+time continue to allow logins, then she might use the following
+configuration file entry for login:
+<tscreen>
+<verb>
+#
+# add this line to your other login entries to disable account
+# management, but continue to permit users to log in...
+#
+login account required pam_permit.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_pwdb.sgml b/contrib/libpam/doc/modules/pam_pwdb.sgml
new file mode 100644
index 000000000000..c9f7bff1124a
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_pwdb.sgml
@@ -0,0 +1,245 @@
+<!--
+ $Id: pam_pwdb.sgml,v 1.3 1997/04/05 06:50:42 morgan Exp morgan $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The Password-Database module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+pam_pwdb
+
+<tag><bf>Author:</bf></tag>
+Cristian Gafton &lt;gafton@redhat.com&gt; <newline>
+and Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Authors.
+
+<tag><bf>Management groups provided:</bf></tag>
+account; authentication; password; session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+Requires properly configured <tt/libpwdb/
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module is a pluggable replacement for the <tt/pam_unix_../
+modules. It uses the generic interface of the <em/Password Database/
+library
+<tt><htmlurl
+url="http://parc.power.net/morgan/libpwdb/index.html"
+name="http://parc.power.net/morgan/libpwdb/index.html"></tt>.
+
+<sect2>Account component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/
+
+<tag><bf>Description:</bf></tag>
+
+The <tt/debug/ argument makes the accounting functions of this module
+<tt/syslog(3)/ more information on its actions. (Remaining arguments
+supported by the other functions of this module are silently ignored,
+but others are logged as errors through <tt/syslog(3)/).
+
+Based on the following <tt/pwdb_element/s:
+<tt/expire/;
+<tt/last_change/;
+<tt/max_change/;
+<tt/defer_change/;
+<tt/warn_change/,
+this module performs the task of establishing the status of the user's
+account and password. In the case of the latter, it may offer advice
+to the user on changing their password or, through the
+<tt/PAM_AUTHTOKEN_REQD/ return, delay giving service to the user until
+they have established a new password. The entries listed above are
+documented in the <em/Password Database Library Guide/ (see pointer
+above). Should the user's record not contain one or more of these
+entries, the corresponding <em/shadow/ check is not performed.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+In its accounting mode, this module can be inserted as follows:
+<tscreen>
+<verb>
+#
+# Ensure users account and password are still active
+#
+login account required pam_pwdb.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/;
+<tt/use_first_pass/;
+<tt/try_first_pass/;
+<tt/nullok/;
+<tt/nodelay/
+
+<tag><bf>Description:</bf></tag>
+
+The <tt/debug/ argument makes the authentication functions of this
+module <tt/syslog(3)/ more information on its actions.
+
+<p>
+The default action of this module is to not permit the user access to
+a service if their <em/official/ password is blank. The <tt/nullok/
+argument overrides this default.
+
+<p>
+When given the argument <tt/try_first_pass/, before prompting the user
+for their password, the module first tries the previous stacked
+<tt/auth/-module's password in case that satisfies this module as
+well. The argument <tt/use_first_pass/ forces the module to use such a
+recalled password and will never prompt the user - if no password is
+available or the password is not appropriate, the user will be denied
+access.
+
+<p>
+The argument, <tt>nodelay</tt>, can be used to discourage the
+authentication component from requesting a delay should the
+authentication as a whole fail. The default action is for the module
+to request a delay-on-failure of the order of one second.
+
+<p>
+Remaining arguments, supported by the other functions of this module,
+are silently ignored. Other arguments are logged as errors through
+<tt/syslog(3)/.
+
+<p>
+A helper binary, <tt>pwdb_chkpwd</tt>, is provided to check the user's
+password when it is stored in a read protected database. This binary
+is very simple and will only check the password of the user invoking
+it. It is called transparently on behalf of the user by the
+authenticating component of this module. In this way it is possible
+for applications like <em>xlock</em> to work without being setuid-root.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+The correct functionality of this module is dictated by having an
+appropriate <tt>/etc/pwdb.conf</tt> file, the user
+databases specified there dictate the source of the authenticated
+user's record.
+
+</descrip>
+
+<sect2>Password component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/; <tt/nullok/; <tt/not_set_pass/; <tt/use_authtok/;
+<tt/try_first_pass/; <tt/use_first_pass/; <tt/md5/; <tt/bigcrypt/;
+<tt/shadow/; <tt/radius/; <tt/unix/
+
+<tag><bf>Description:</bf></tag>
+
+This part of the <tt/pam_pwdb/ module performs the task of updating
+the user's password. Thanks to the flexibility of <tt/libpwdb/ this
+module is able to move the user's password from one database to
+another, perhaps securing the user's database entry in a dynamic
+manner (<em/this is very ALPHA code at the moment!/) - this is the
+purpose of the <tt/shadow/, <tt/radius/ and <tt/unix/ arguments.
+
+<p>
+In the case of conventional unix databases (which store the password
+encrypted) the <tt/md5/ argument is used to do the encryption with the
+MD5 function as opposed to the <em/conventional/ <tt/crypt(3)/ call.
+As an alternative to this, the <tt/bigcrypt/ argument can be used to
+encrypt more than the first 8 characters of a password with DEC's
+(Digital Equipment Cooperation) `C2' extension to the standard UNIX
+<tt/crypt()/ algorithm.
+
+<p>
+The <tt/nullok/ module is used to permit the changing of a password
+<em/from/ an empty one. Without this argument, empty passwords are
+treated as account-locking ones.
+
+<p>
+The argument <tt/use_first_pass/ is used to lock the choice of old and
+new passwords to that dictated by the previously stacked <tt/password/
+module. The <tt/try_first_pass/ argument is used to avoid the user
+having to re-enter an old password when <tt/pam_pwdb/ follows a module
+that possibly shared the user's old password - if this old password is
+not correct the user will be prompted for the correct one. The
+argument <tt/use_authtok/ is used to <em/force/ this module to set the
+new password to the one provided by the previously stacked
+<tt/password/ module (this is used in an example of the stacking of
+the <em/Cracklib/ module documented above).
+
+<p>
+The <tt/not_set_pass/ argument is used to inform the module that it is
+not to pay attention to/make available the old or new passwords from/to
+other (stacked) password modules.
+
+<p>
+The <tt/debug/ argument makes the password functions of this module
+<tt/syslog(3)/ more information on its actions. Other arguments may be
+logged as erroneous to <tt/syslog(3)/.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+An example of the stacking of this module with respect to the
+pluggable password checking module, <tt/pam_cracklib/, is given in
+that modules section above.
+</descrip>
+
+<sect2>Session component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+No arguments are recognized by this module component. Its action is
+simply to log the username and the service-type to
+<tt/syslog(3)/. Messages are logged at the beginning and end of the
+user's session.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+The use of the session modules is straightforward:
+<tscreen>
+<verb>
+#
+# pwdb - unix like session opening and closing
+#
+login session required pam_pwdb.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_radius.sgml b/contrib/libpam/doc/modules/pam_radius.sgml
new file mode 100644
index 000000000000..4d5f39ab3422
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_radius.sgml
@@ -0,0 +1,117 @@
+<!--
+ $Id: pam_radius.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Cristian Gafton <gafton@redhat.com>
+-->
+
+<sect1>The RADIUS session module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_radius/
+
+<tag><bf>Author:</bf></tag>
+Cristian Gafton &lt;gafton@redhat.com&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+session
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+This module does not deal with passwords
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+gcc reports 1 warning when compiling <tt>/usr/include/rpc/clnt.h</tt>.
+Hey, is not my fault !
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+
+yes; this is a network module (independent of application).
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module is intended to provide the session service for users
+autheticated with a RADIUS server. At the present stage, the only
+option supported is the use of the RADIUS server as an accounting
+server.
+
+<sect2>Session component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tt/debug/ - verbose logging to <tt/syslog(3)/.
+
+<tag><bf>Description:</bf></tag>
+
+This module is intended to provide the session service for users
+autheticated with a RADIUS server. At the present stage, the only
+option supported is the use of the RADIUS server as an <em/accounting/
+server.
+
+<p>
+(There are few things which needs to be cleared out first in
+the PAM project until one will be able to use this module and expect
+it to magically start pppd in response to a RADIUS server command to
+use PPP for this user, or to initiate a telnet connection to another
+host, or to hang and call back the user using parameters provided in
+the RADIUS server response. Most of these things are better suited for
+the radius login application. I hope to make available Real Soon (tm)
+patches for the login apps to make it work this way.)
+
+<p>
+When opening a session, this module sends an ``Accounting-Start''
+message to the RADIUS server, which will log/update/whatever a
+database for this user. On close, an ``Accounting-Stop'' message is
+sent to the RADIUS server.
+
+<p>
+This module has no other prerequisites for making it work. One can
+install a RADIUS server just for fun and use it as a centralized
+accounting server and forget about wtmp/last/sac etc. .
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+For the services that need this module (<em/login/ for example) put
+the following line in <tt>/etc/pam.conf</tt> as the last line for that
+service (usually after the pam_unix session line):
+<tscreen>
+<verb>
+login session required pam_radius.so
+</verb>
+</tscreen>
+Replace <tt/login/ for each service you are using this module.
+
+<p>
+This module make extensive use of the API provided in libpwdb
+0.54preB or later. By default, it will read the radius server
+configuration (hostname and secret) from <tt>/etc/raddb/server</tt>.
+This is a default compiled into libpwdb, and curently there is no way to
+modify this default without recompiling libpwdb. I am working on
+extending the radius support from libpwdb to provide a possibility
+to make this runtime-configurable.
+
+Also please note that libpwdb will require also the RADIUS
+dictionary to be present (<tt>/etc/raddb/dictionary</tt>).
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
+
diff --git a/contrib/libpam/doc/modules/pam_rhosts.sgml b/contrib/libpam/doc/modules/pam_rhosts.sgml
new file mode 100644
index 000000000000..91001022a2b0
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_rhosts.sgml
@@ -0,0 +1,157 @@
+<!--
+ $Id: pam_rhosts.sgml,v 1.4 1997/04/05 06:50:42 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The rhosts module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_rhosts_auth/
+
+<tag><bf>Author:</bf></tag>
+Al Longyear &lt;longyear@netcom.com&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+Clean.
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+Standard <tt/inet_addr()/, <tt/gethostbyname()/ function calls.
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module performs the standard network authentication for services,
+as used by traditional implementations of <em/rlogin/ and <em/rsh/
+etc.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/no_hosts_equiv/; <tt/no_rhosts/; <tt/debug/; <tt/no_warn/;
+<tt/privategroup/; <tt/promiscuous/; <tt/suppress/
+
+<tag><bf>Description:</bf></tag>
+
+The authentication mechanism of this module is based on the contents
+of two files; <tt>/etc/hosts.equiv</tt> (or <tt/_PATH_HEQUIV/ in
+<tt>#include &lt;netdb.h&gt;</tt>) and <tt>~/.rhosts</tt>. Firstly,
+hosts listed in the former file are treated as equivalent to the
+localhost. Secondly, entries in the user's own copy of the latter file
+is used to map "<tt/remote-host remote-user/" pairs to that user's
+account on the current host. Access is granted to the user if their
+host is present in <tt>/etc/hosts.equiv</tt> and their remote account
+is identical to their local one, or if their remote account has an
+entry in their personal configuration file.
+
+<p>
+Some restrictions are applied to the attributes of the user's personal
+configuration file: it must be a regular file (as defined by
+<tt/S_ISREG(x)/ of POSIX.1); it must be owned by the <em/superuser/ or
+the user; it must not be writable by any user besides its owner.
+
+<p>
+The module authenticates a remote user (internally specified by the
+item <tt/PAM_RUSER/) connecting from the remote host (internally
+specified by the item <tt/PAM_RHOST/). Accordingly, for applications
+to be compatible this authentication module they must set these items
+prior to calling <tt/pam_authenticate()/. The module is not capable
+of independently probing the network connection for such information.
+
+<p>
+In the case of <tt/root/-access, the <tt>/etc/host.equiv</tt> file is
+<em/ignored/. Instead, the superuser must have a correctly configured
+personal configuration file.
+
+<p>
+The behavior of the module is modified by flags:
+<itemize>
+<item>
+<tt/debug/ -
+log more information to <tt/syslog(3)/. (XXX - actually, this module
+does not do any logging currently, please volunteer to fix this!)
+
+<item>
+<tt/no_warn/ -
+do not give verbal warnings to the user about failures etc. (XXX -
+this module currently does not issue any warnings, please volunteer to
+fix this!)
+
+<item>
+<tt/no_hosts_equiv/ -
+ignore the contents of the <tt>/etc/hosts.equiv</tt> file.
+
+<item>
+<tt/no_rhosts/ -
+ignore the contents of all user's personal configuration file
+<tt>~/.rhosts</tt>.
+
+<item>
+<tt/privategroup/ -
+normally, the <tt>~/.rhosts</tt> file must not be writable by anyone
+other than its owner. This option overlooks group write access in the
+case that the group owner of this file has the same name as the
+user being authenticated. To lessen the security problems associated
+with this option, the module also checks that the user is the only
+member of their private group.
+
+<item>
+<tt/promiscuous/ -
+A host entry of `+' will lead to all hosts being granted
+access. Without this option, '+' entries will be ignored. Note, that
+the <tt/debug/ option will syslog a warning in this latter case.
+
+<item>
+<tt/suppress/ -
+This will prevent the module from <tt/syslog(3)/ing a warning message
+when this authentication fails. This option is mostly for keeping
+logs free of meaningless errors, in particular when the module is used
+with the <tt/sufficient/ control flag.
+
+</itemize>
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+To allow users to login from trusted remote machines, you should try
+adding the following line to your <tt>/etc/pam.conf</tt> file
+<em/before/ the line that would otherwise prompt the user for a
+password:
+<tscreen>
+<verb>
+#
+# No passwords required for users from hosts listed above.
+#
+login auth sufficient pam_rhosts_auth.so no_rhosts
+</verb>
+</tscreen>
+Note, in this example, the system administrator has turned off all
+<em/personal/ <em/rhosts/ configuration files. Also note, that this module
+can be used to <em/only/ allow remote login from hosts specified in
+the <tt>/etc/host.equiv</tt> file, by replacing <tt/sufficient/ in the
+above example with <tt/required/.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_rootok.sgml b/contrib/libpam/doc/modules/pam_rootok.sgml
new file mode 100644
index 000000000000..ff6aa86e34da
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_rootok.sgml
@@ -0,0 +1,85 @@
+<!--
+ $Id: pam_rootok.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>The root access module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+pam_rootok
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+<bf>Linux-PAM</bf> maintainer
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+Clean.
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module is for use in situations where the superuser wishes
+to gain access to a service without having to enter a password.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/
+
+<tag><bf>Description:</bf></tag>
+
+This module authenticates the user if their <tt/uid/ is <tt/0/.
+Applications that are created <em/setuid/-root generally retain the
+<tt/uid/ of the user but run with the authority of an enhanced
+<em/effective-/<tt/uid/. It is the real <tt/uid/ that is checked.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+In the case of the <tt/su/ application the historical usage is to
+permit the superuser to adopt the identity of a lesser user without
+the use of a password. To obtain this behavior under <tt/Linux-PAM/
+the following pair of lines are needed for the corresponding entry in
+the configuration file:
+<tscreen>
+<verb>
+#
+# su authentication. Root is granted access by default.
+#
+su auth sufficient pam_rootok.so
+su auth required pam_unix_auth.so
+</verb>
+</tscreen>
+
+<p>
+Note. For programs that are run by the superuser (or started when the
+system boots) this module should not be used to authenticate users.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_securetty.sgml b/contrib/libpam/doc/modules/pam_securetty.sgml
new file mode 100644
index 000000000000..276ae90435c2
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_securetty.sgml
@@ -0,0 +1,72 @@
+<!--
+ $Id: pam_securetty.sgml,v 1.1 1996/11/30 20:59:32 morgan Exp $
+
+ This file was written by Michael K. Johnson <johnsonm@redhat.com>
+-->
+
+<sect1>The securetty module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_securetty/
+
+<tag><bf>Author[s]:</bf></tag>
+Elliot Lee &lt;sopwith@cuc.edu&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Red Hat Software:<newline>
+<em/currently/ Michael K. Johnson &lt;johnsonm@redhat.com&gt;<newline>
+(if unavailable, contact Elliot Lee &lt;sopwith@cuc.edu&gt;).
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+<tt>/etc/securetty</tt> file
+
+<tag><bf>Network aware:</bf></tag>
+
+Requires the application to fill in the <tt>PAM_TTY</tt> item
+correctly in order to act meaningfully.
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+Provides standard Unix securetty checking.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+Provides standard Unix securetty checking, which causes authentication
+for root to fail unless <tt>PAM_TTY</tt> is set to a string listed in
+the <tt>/etc/securetty</tt> file. For all other users, it succeeds.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+For canonical usage, should be listed as a <tt>required</tt>
+authentication method before any <tt>sufficient</tt> authentication
+methods.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_time.sgml b/contrib/libpam/doc/modules/pam_time.sgml
new file mode 100644
index 000000000000..0b3cddfcb44a
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_time.sgml
@@ -0,0 +1,166 @@
+<!--
+ $Id: pam_time.sgml,v 1.2 1997/02/15 18:25:44 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>Time control
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_time/
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan <tt>&lt;morgan@parc.power.net&gt;</tt>
+
+<tag><bf>Maintainer:</bf></tag>
+Author
+
+<tag><bf>Management groups provided:</bf></tag>
+account
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+Requires a configuration file <tt>/etc/security/time.conf</tt>
+
+<tag><bf>Network aware:</bf></tag>
+Through the <tt/PAM_TTY/ item only
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+Running a well regulated system occasionally involves restricting
+access to certain services in a selective manner. This module offers
+some time control for access to services offered by a system. Its
+actions are determined with a configuration file. This module can be
+configured to deny access to (individual) users based on their name,
+the time of day, the day of week, the service they are applying for
+and their terminal from which they are making their request.
+
+<sect2>Account component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+This module bases its actions on the rules listed in its configuration
+file: <tt>/etc/security/pam.conf</tt>. Each rule has the following
+form,
+<tscreen>
+<em/services/<tt/;/<em/ttys/<tt/;/<em/users/<tt/;/<em/times/
+</tscreen>
+In words, each rule occupies a line, terminated with a newline or the
+beginning of a comment; a `<tt/#/'. It contains four fields separated
+with semicolons, `<tt/;/'. The fields are as follows:
+
+<p>
+<itemize>
+<item><em/services/ -
+a logic list of service names that are affected by this rule.
+
+<item><em/ttys/ -
+a logic list of terminal names indicating those terminals covered by
+the rule.
+
+<item><em/user/ -
+a logic list of usernames to which this rule applies
+
+<p>
+By a logic list we mean a sequence of tokens (associated with the
+appropriate <tt/PAM_/ item), containing no more than one wildcard
+character; `<tt/*/', and optionally prefixed with a negation operator;
+`<tt/!/'. Such a sequence is concatenated with one of two logical
+operators: <tt/&amp;/ (logical AND) and <tt/|/ (logical OR). Two
+examples are: <tt>!morgan&amp;!root</tt>, indicating that this rule
+does not apply to the user <tt>morgan</tt> nor to <tt>root</tt>; and
+<tt>tty*&amp;!ttyp*</tt>, which indicates that the rule applies only
+to console terminals but not pseudoterminals.
+
+<item><em/times/ - a logic list of times at which this rule
+applies. The format of each element is a day/time-range. The days are
+specified by a sequence of two character entries. For example,
+<tt/MoTuSa/, indicates Monday Tuesday and Saturday. Note that
+repeated days are <em/unset/; <tt/MoTuMo/ indicates Tuesday, and
+<tt/MoWk/ means all weekdays bar Monday. The two character
+combinations accepted are,
+<tscreen>
+<verb>
+Mo Tu We Th Fr Sa Su Wk Wd Al
+</verb>
+</tscreen>
+The last two of these being <em/weekend/ days and <em/all 7 days/ of
+the week respectively.
+
+<p>
+The time range part is a pair of 24-hour times, <em/HHMM/, separated
+by a hyphen -- indicating the start and finish time for the rule. If
+the finsish time is smaller than the start time, it is assumed to
+apply on the following day. For an example, <tt/Mo1800-0300/ indicates
+that the permitted times are Monday night from 6pm to 3am the
+following morning.
+
+</itemize>
+
+<p>
+Note, that the given time restriction is only applied when the first
+three fields are satisfied by a user's application for service.
+
+<p>
+For convenience and readability a rule can be extended beyond a single
+line with a `<tt>&bsol;</tt><em/newline/'.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+The use of this module is initiated with an entry in the
+<bf/Linux-PAM/ configuration file of the following type:
+<tscreen>
+<verb>
+#
+# apply pam_time accounting to login requests
+#
+login account required pam_time.so
+</verb>
+</tscreen>
+where, here we are applying the module to the <em/login/ application.
+
+<p>
+Some examples of rules that can be placed in the
+<tt>/etc/security/time.conf</tt> configuration file are the following:
+<descrip>
+
+<tag><tt>login ; tty* &amp ; !ttyp* ; !root ; !Al0000-2400</tt></tag>
+all users except for <tt/root/ are denied access to console-login at
+all times.
+
+<tag><tt>games ; * ; !waster ; Wd0000-2400 | Wk1800-0800</tt></tag>
+games (configured to use Linux-PAM) are only to be accessed out of
+working hours. This rule does not apply to the user <tt/waster/.
+
+</descrip>
+
+<p>
+Note, currently there is no daemon enforcing the end of a session.
+This needs to be remedied.
+
+<p>
+Poorly formatted rules are logged as errors using <tt/syslog(3)/.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_warn.sgml b/contrib/libpam/doc/modules/pam_warn.sgml
new file mode 100644
index 000000000000..6e81f187f694
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_warn.sgml
@@ -0,0 +1,67 @@
+<!--
+ $Id: pam_warn.sgml,v 1.1 1996/11/30 20:59:32 morgan Exp $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+-->
+
+<sect1>Warning logger module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_warn/
+
+<tag><bf>Author:</bf></tag>
+Andrew G. Morgan &lt;morgan@parc.power.net&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication; password
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+
+<tag><bf>Network aware:</bf></tag>
+logs information about the remote user and host (if pam-items are known)
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+This module is principally for logging information about a
+proposed authentication or application to update a password.
+
+<sect2>Authentication+Password component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+
+<tag><bf>Description:</bf></tag>
+
+Log the service, terminal, user, remote user and remote host to
+<tt/syslog(3)/. The items are not probed for, but instead obtained
+from the standard pam-items.
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+an example is provided in the configuration file section <ref
+id="configuration" name="above">.
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/modules/pam_wheel.sgml b/contrib/libpam/doc/modules/pam_wheel.sgml
new file mode 100644
index 000000000000..9139695fec84
--- /dev/null
+++ b/contrib/libpam/doc/modules/pam_wheel.sgml
@@ -0,0 +1,124 @@
+<!--
+ $Id: pam_wheel.sgml,v 1.3 1997/02/15 18:25:44 morgan Exp morgan $
+
+ This file was written by Andrew G. Morgan <morgan@parc.power.net>
+ from notes provided by Cristian Gafton.
+-->
+
+<sect1>The wheel module
+
+<sect2>Synopsis
+
+<p>
+<descrip>
+
+<tag><bf>Module Name:</bf></tag>
+<tt/pam_wheel/
+
+<tag><bf>Author:</bf></tag>
+Cristian Gafton &lt;gafton@redhat.com&gt;
+
+<tag><bf>Maintainer:</bf></tag>
+Author.
+
+<tag><bf>Management groups provided:</bf></tag>
+authentication
+
+<tag><bf>Cryptographically sensitive:</bf></tag>
+
+<tag><bf>Security rating:</bf></tag>
+
+<tag><bf>Clean code base:</bf></tag>
+
+<tag><bf>System dependencies:</bf></tag>
+Requires libpwdb.
+
+<tag><bf>Network aware:</bf></tag>
+
+</descrip>
+
+<sect2>Overview of module
+
+<p>
+Only permit root access to members of the wheel (<tt/gid=0/) group.
+
+<sect2>Authentication component
+
+<p>
+<descrip>
+
+<tag><bf>Recognized arguments:</bf></tag>
+<tt/debug/;
+<tt/use_uid/;
+<tt/trust/;
+<tt/deny/;
+<tt/group=XXXX/
+
+<tag><bf>Description:</bf></tag>
+
+This module is used to enforce the so-called wheel group. By default,
+it permits root access to the system if the applicant user is a member
+of the <tt/wheel/ group (better described as the group with group-id
+<tt/0/).
+
+<p>
+The action of the module may be modified from this default by one or
+more of the following flags in the <tt>/etc/pam.conf</tt> file.
+<itemize>
+<item>
+<tt/debug/ -
+Supply more debugging information to <tt/syslog(3)/.
+
+<item>
+<tt/use_id/ -
+This option modifies the behavior of the module by using the current
+<tt/uid/ of the process and not the <tt/getlogin(3)/ name of the user.
+This option is useful for being able to jump from one account to
+another, for example with 'su'.
+
+<item>
+<tt/trust/ -
+This option instructs the module to return <tt/PAM_SUCCESS/ should it
+find the user applying for root privilege is a member of the wheel
+group. The default action is to return <tt/PAM_IGNORE/ in this
+situation. By using the <tt/trust/ option it is possible to arrange
+for <tt/wheel/-group members to become root without typing a
+password. <bf/USE WITH CARE/.
+
+<item>
+<tt/deny/ -
+This is used to reverse the logic of the module's behavior.
+If the user is trying to get <tt/uid=0/ access and is a member of the wheel
+group, deny access (for the wheel group, this is perhaps nonsense!):
+it is intended for use in conjunction with the <tt/group=/ argument...
+
+<item>
+<tt/group=XXXX/ -
+Instead of checking the <tt/gid=0/ group, use the user's <tt/XXXX/
+group membership for the authentication. Here, <tt/XXXX/ is the name
+of the group and <bf/not/ its numeric identifier.
+
+</itemize>
+
+<tag><bf>Examples/suggested usage:</bf></tag>
+
+To restrict access to superuser status to the members of the
+<tt/wheel/ group, use the following entries in your configuration
+file:
+<tscreen>
+<verb>
+#
+# root gains access by default (rootok), only wheel members can
+# become root (wheel) but Unix authenticate non-root applicants.
+#
+su auth sufficient pam_rootok.so
+su auth required pam_wheel.so
+su auth required pam_unix_auth.so
+</verb>
+</tscreen>
+
+</descrip>
+
+<!--
+End of sgml insert for this module.
+-->
diff --git a/contrib/libpam/doc/pam_appl.sgml b/contrib/libpam/doc/pam_appl.sgml
new file mode 100644
index 000000000000..7c4170ae47ba
--- /dev/null
+++ b/contrib/libpam/doc/pam_appl.sgml
@@ -0,0 +1,1567 @@
+<!doctype linuxdoc system>
+
+<!--
+
+ $Id: pam_appl.sgml,v 1.16 1997/04/05 06:49:14 morgan Exp morgan $
+
+ Copyright (C) Andrew G. Morgan 1996, 1997. All rights reserved.
+
+Redistribution and use in source (sgml) and binary (derived) 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, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+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.
+
+ALTERNATIVELY, this product may be distributed under the terms of the
+GNU General Public License, in which case the provisions of the GNU
+GPL are required INSTEAD OF the above restrictions. (This clause is
+necessary due to a potential bad interaction between the GNU GPL and
+the restrictions contained in a BSD-style copyright.)
+
+THIS SOFTWARE IS PROVIDED ``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 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.
+
+ -->
+
+<article>
+
+<title>The Linux-PAM Application Developers' Guide
+<author>Andrew G. Morgan, <tt>morgan@linux.kernel.org</tt>
+<date>DRAFT v0.63 1998/1/18
+<abstract>
+This manual documents what an application developer needs to know
+about the <bf>Linux-PAM</bf> library. It describes how an application
+might use the <bf>Linux-PAM</bf> library to authenticate users. In
+addition it contains a description of the funtions to be found in
+<tt/libpam_misc/ library, that can be used in general applications.
+Finally, it contains some comments on PAM related security issues for
+the application developer.
+</abstract>
+
+<toc>
+
+<sect>Introduction
+
+<sect1>Synopsis
+
+<p>
+For general applications that wish to use the services provided by
+<bf/Linux-PAM/ the following is a summary of the relevant linking
+information:
+<tscreen>
+<verb>
+#include <security/pam_appl.h>
+
+cc -o application .... -lpam
+</verb>
+</tscreen>
+
+<p>
+In addition to <tt/libpam/, there is a library of miscellaneous
+functions that make the job of writing <em/PAM-aware/ applications
+easier (this library is not covered in the DCE-RFC for PAM and is
+specific to the Linux-PAM distribution):
+<tscreen>
+<verb>
+...
+#include <security/pam_misc.h>
+
+cc -o application .... -lpam -lpam_misc
+</verb>
+</tscreen>
+
+<sect1> Description
+
+<p>
+<bf>Linux-PAM</bf> (Pluggable Authentication Modules for Linux) is a
+library that enables the local system administrator to choose how
+individual applications authenticate users. For an overview of the
+<bf>Linux-PAM</bf> library see the <bf/Linux-PAM/ System
+Administrators' Guide.
+
+<p>
+It is the purpose of the <bf>Linux-PAM</bf> project to liberate the
+development of privilege granting software from the development of
+secure and appropriate authentication schemes. This is accomplished
+by providing a documented library of functions that an application may
+use for all forms of user authentication management. This library
+dynamically loads locally configured authentication modules that
+actually perform the authentication tasks.
+
+<p>
+From the perspective of an application developer the information
+contained in the local configuration of the PAM library should not be
+important. Indeed it is intended that an application treat the
+functions documented here as a ``black box'' that will deal with all
+aspects of user authentication. ``All aspects'' includes user
+verification, account management, session initialization/termination
+and also the resetting of passwords (<em/authentication tokens/).
+
+<sect>Overview
+
+<p>
+Most service-giving applications are restricted. In other words,
+their service is not available to all and every prospective client.
+Instead, the applying client must jump through a number of hoops to
+convince the serving application that they are authorized to obtain
+service.
+
+The process of <em/authenticating/ a client is what PAM is designed to
+manage. In addition to authentication, PAM provides account
+management, credential management, session management and
+authentication-token (password changing) management services. It is
+important to realize when writing a PAM based application that these
+services are provided in a manner that is <bf>transparent</bf> to the
+the application. That is to say, when the application is written, no
+assumptions can be made about <em>how</em> the client will be
+authenticated.
+
+<p>
+The process of authentication is performed by the PAM library via a
+call to <tt>pam_authenticate()</tt>. The return value of this
+function will indicate whether a named client (the <em>user</em>) has
+been authenticated. If the PAM library needs to prompt the user for
+any information, such as their <em>name</em> or a <em>password</em>
+then it will do so. If the PAM library is configured to authenticate
+the user using some silent protocol, it will do this too. (This
+latter case might be via some hardware interface for example.)
+
+<p>
+It is important to note that the application must leave all decisions
+about when to prompt the user at the discretion of the PAM library.
+
+<p>
+The PAM library, however, must work equally well for different styles
+of application. Some applications, like the familiar <tt>login</tt>
+and <tt>passwd</tt> are terminal based applications, exchanges of
+information with the client in these cases is as plain text messages.
+Graphically based applications, however, have a more sophisticated
+interface. They generally interact with the user via specially
+constructed dialogue boxes. Additionally, network based services
+require that text messages exchanged with the client are specially
+formatted for automated processing: one such example is <tt>ftpd</tt>
+which prefixes each exchanged message with a numeric identifier.
+
+<p>
+The presentation of simple requests to a client is thus something very
+dependent on the protocol that the serving application will use. In
+spite of the fact that PAM demands that it drives the whole
+authentication process, it is not possible to leave such protocol
+subtleties up to the PAM library. To overcome this potential problem,
+the application provides the PAM library with a <em>conversation</em>
+function. This function is called from <bf>within</bf> the PAM
+library and enables the PAM to directly interact with the client. The
+sorts of things that this conversation function must be able to do are
+prompt the user with text and/or obtain textual input from the user
+for processing by the PAM library. The details of this function are
+provided in a later section.
+
+<p>
+For example, the conversation function may be called by the PAM library
+with a request to prompt the user for a password. Its job is to
+reformat the prompt request into a form that the client will
+understand. In the case of <tt>ftpd</tt>, this will involve prefixing
+the string with the number <tt>331</tt> and sending the request over
+the network to a connected client. The conversation function will
+then obtain any reply and, after extracting the typed password, will
+return this string of text to the PAM library. Similar concerns need
+to be addressed in the case of an X-based graphical server.
+
+<p>
+There are a number of issues that need to be addressed when one is
+porting an existing application to become PAM compliant. A section
+below has been devoted to this: Porting legacy applications.
+
+<p>
+Besides authentication, PAM provides other forms of management.
+Session management is provided with calls to
+<tt>pam_open_session()</tt> and <tt>pam_close_session()</tt>. What
+these functions actually do is up to the local administrator. But
+typically, they could be used to log entry and exit from the system or
+for mounting and unmounting the user's home directory. If an
+application provides continuous service for a period of time, it
+should probably call these functions, first open after the user is
+authenticated and then close when the service is terminated.
+
+<p>
+Account management is another area that an application developer
+should include with a call to <tt/pam_acct_mgmt()/. This call will
+perform checks on the good health of the user's account (has it
+expired etc.). One of the things this function may check is whether
+the user's authentication token has expired - in such a case the
+application may choose to attempt to update it with a call to
+<tt/pam_chauthtok()/, although some applications are not suited to
+this task (<em>ftp</em> for example) and in this case the application
+should deny access to the user.
+
+<p>
+PAM is also capable of setting and deleting the users credentials with
+the call <tt>pam_setcred()</tt>. This function should always be
+called after the user is authenticated and before service is offered
+to the user. By convention, this should be the last call to the PAM
+library before service is given to the user. What exactly a
+credential is, is not well defined. However, some examples are given
+in the glossary below.
+
+<sect>The public interface to <bf>Linux-PAM</bf>
+
+<p>
+Firstly, the relevant include file for the <bf>Linux-PAM</bf> library
+is <tt>&lt;security/pam_appl.h&gt;</tt>. It contains the definitions
+for a number of functions. After listing these functions, we collect
+some guiding remarks for programmers.
+
+<sect1>What can be expected by the application
+
+<p>
+Here we document those functions in the <bf/Linux-PAM/ library that
+may be called from an application.
+
+<sect2>Initialization of Linux-PAM
+<label id="pam-start-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_start(const char *service_name, const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh);
+</verb>
+</tscreen>
+
+<p>
+This is the first of the <bf>Linux-PAM</bf> functions that must be
+called by an application. It initializes the interface and reads the
+system configuration file, <tt>/etc/pam.conf</tt> (see the
+<bf/Linux-PAM/ System Administrators' Guide). Following a successful
+return (<tt/PAM_SUCCESS/) the contents of <tt/*pamh/ is a handle that
+provides continuity for successive calls to the <bf/Linux-PAM/
+library. The arguments expected by <tt/pam_start/ are as follows: the
+<tt/service_name/ of the program, the <tt/user/name of the individual
+to be authenticated, a pointer to an application-supplied
+<tt/pam_conv/ structure and a pointer to a <tt/pam_handle_t/
+<em/pointer/.
+
+<p>
+The <tt>pam_conv</tt> structure is discussed more fully in the section
+<ref id="the-conversation-function" name="below">. The
+<tt>pam_handle_t</tt> is a <em>blind</em> structure and the
+application should not attempt to probe it directly for information.
+Instead the <bf>Linux-PAM</bf> library provides the functions
+<tt>pam_set_item</tt> and <tt>pam_get_item</tt>. These functions are
+documented below.
+
+<sect2>Termination of the library
+<label id="pam-end-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_end(pam_handle_t *pamh, int pam_status);
+</verb>
+</tscreen>
+
+<p>
+This function is the last function an application should call in the
+<bf>Linux-PAM</bf> library. Upon return the handle <tt/pamh/ is no
+longer valid and all memory associated with it will be invalid (likely
+to cause a segmentation fault if accessed).
+
+<p>
+Under normal conditions the argument <tt/pam_status/ has the value
+PAM_SUCCESS, but in the event of an unsuccessful service application
+the approprite <bf/Linux-PAM/ error-return value should be used
+here.
+attempt its purpose is to be passed as an argument to the
+module specific function <tt/cleanup()/ (see the <bf/Linux-PAM/
+<htmlurl url="pam_modules.html" name="Module Developers' Guide">).
+
+<sect2>Setting PAM items
+<label id="pam-set-item-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_set_item(pam_handle_t *pamh, int item_type,
+ const void *item);
+</verb>
+</tscreen>
+
+<p>This function is used to (re)set the value of one of the following
+<bf/item_type/s:
+
+<p><descrip>
+<tag><tt/PAM_SERVICE/</tag>
+ The service name
+
+<tag><tt/PAM_USER/</tag>
+ The user name
+
+<tag><tt/PAM_TTY/</tag>
+ The terminal name: prefixed by <tt>/dev/</tt> if it is a
+device file; for graphical, X-based, applications the value for this
+item should be the <tt/&dollar;DISPLAY/ variable.
+
+<tag><tt/PAM_RHOST/</tag>
+ The remote host name
+
+<tag><tt/PAM_CONV/</tag>
+ The conversation structure (see section <ref
+id="the-conversation-function" name="below">)
+
+<tag><tt/PAM_RUSER/</tag>
+ The remote user name
+
+<tag><tt/PAM_USER_PROMPT/</tag>
+ The string used when prompting for a user's name. The default
+value for this string is ``Please enter username: ''.
+
+</descrip>
+
+<p>
+For all <tt/item_type/s, other than <tt/PAM_CONV/, <tt/item/ is a
+pointer to a <tt>&lt;NUL&gt;</tt> terminated character string. In the
+case of <tt/PAM_CONV/, <tt/item/ points to an initialized
+<tt/pam_conv/ structure (see section <ref
+id="the-conversation-function" name="below">).
+
+<p>
+A successful call to this function returns <tt/PAM_SUCCESS/. However,
+the application should expect one of the following errors:
+
+<p>
+<descrip>
+<tag><tt/PAM_PERM_DENIED/</tag>
+ An attempt was made to replace the conversation structure with
+a <tt/NULL/ value.
+<tag><tt/PAM_BUF_ERR/</tag>
+ The function ran out of memory making a copy of the item.
+<tag><tt/PAM_BAD_ITEM/</tag>
+ The application attempted to set an undefined item.
+</descrip>
+
+<sect2>Getting PAM items
+<label id="pam-get-item-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_get_item(const pam_handle_t *pamh, int item_type,
+ const void **item);
+</verb>
+</tscreen>
+
+<p>
+This function is used to obtain the value of the indicated
+<tt/item_type/. Upon successful return, <tt/*item/ contains a pointer
+to the value of the corresponding item. Note, this is a pointer to
+the <em/actual/ data and should <em/not/ be <tt/free()/'ed or
+over-written! A successful call is signaled by a return value of
+<tt/PAM_SUCCESS/. If an attempt is made to get an undefined item,
+<tt/PAM_BAD_ITEM/ is returned.
+
+<sect2>Understanding errors
+<label id="pam-strerror-section">
+
+<p>
+<tscreen>
+<verb>
+extern const char *pam_strerror(pam_handle_t *pamh, int errnum);
+</verb>
+</tscreen>
+
+<p>
+This function returns some text describing the <bf>Linux-PAM</bf>
+error associated with the argument <tt/errnum/. If the error is not
+recognized ``<tt/Unknown Linux-PAM error/'' is returned.
+
+<sect2>Planning for delays
+
+<p>
+<tscreen>
+<verb>
+extern int pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec);
+</verb>
+</tscreen>
+
+<p>
+This function is offered by <bf/Linux-PAM/ to facilitate time delays
+following a failed call to <tt/pam_authenticate()/ and before control
+is returned to the application. When using this function the
+application programmer should check if it is available with,
+<tscreen>
+<verb>
+#ifdef HAVE_PAM_FAIL_DELAY
+ ....
+#endif /* HAVE_PAM_FAIL_DELAY */
+</verb>
+</tscreen>
+
+
+<p>
+Generally, an application requests that a user is authenticated by
+<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or
+<tt/pam_chauthtok()/. These functions calls each of the <em/stacked/
+authentication modules listed in the <tt>/etc/pam.conf</tt> file. As
+directed by this file, one of more of the modules may fail causing the
+<tt/pam_...()/ call to return an error. It is desirable for there to
+also be a pause before the application continues. The principal reason
+for such a delay is security: a delay acts to discourage <em/brute
+force/ dictionary attacks primarily, but also helps hinder
+<em/timed/ (covert channel) attacks.
+
+<p>
+The <tt/pam_fail_delay()/ function provides the mechanism by which an
+application or module can suggest a minimum delay (of <tt/micro_sec/
+<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time
+requested with this function. Should <tt/pam_authenticate()/ fail,
+the failing return to the application is delayed by an amount of time
+randomly distributed (by up to 25%) about this longest value.
+
+<p>
+Independent of success, the delay time is reset to its zero default
+value when <bf/Linux-PAM/ returns control to the application.
+
+<sect2>Authenticating the user
+
+<p>
+<tscreen>
+<verb>
+extern int pam_authenticate(pam_handle_t *pamh, int flags);
+</verb>
+</tscreen>
+
+<p>
+This function serves as an interface to the authentication mechanisms
+of the loaded modules. The single <em/optional/ flag, which may be
+logically OR'd with <tt/PAM_SILENT/, takes the following value,
+
+<p><descrip>
+
+<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag>
+ Instruct the authentication modules to return
+<tt/PAM_AUTH_ERR/ if the user does not have a registered
+authorization token---it is set to <tt/NULL/ in the system database.
+</descrip>
+
+<p>
+The value returned by this function is one of the following:
+
+<p><descrip>
+
+<tag><tt/PAM_AUTH_ERR/</tag>
+ The user was not authenticated
+<tag><tt/PAM_CRED_INSUFFICIENT/</tag>
+ For some reason the application does not have sufficient
+credentials to authenticate the user.
+<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag>
+ The modules were not able to access the authentication
+information. This might be due to a network or hardware failure etc.
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The supplied username is not known to the authentication
+service
+<tag><tt/PAM_MAXTRIES/</tag>
+ One or more of the authentication modules has reached its
+limit of tries authenticating the user. Do not try again.
+
+</descrip>
+
+<p>
+If one or more of the authentication modules fails to load, for
+whatever reason, this function will return <tt/PAM_ABORT/.
+
+<sect2>Setting user credentials
+<label id="pam-setcred-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_setcred(pam_handle_t *pamh, int flags);
+</verb>
+</tscreen>
+
+<p>
+This function is used to set the module-specific credentials of the
+user. It is usually called after the user has been authenticated,
+after the account management function has been called and after a
+session has been opened for the user.
+
+<p>
+A credential is something that the user possesses. It is some
+property, such as a <em>Kerberos</em> ticket, or a supplementary group
+membership that make up the uniqueness of a given user. On a Linux
+(or UN*X system) the user's <tt>UID</tt> and <tt>GID</tt>'s are
+credentials too. However, it has been decided that these properties
+(along with the default supplementary groups of which the user is a
+member) are credentials that should be set directly by the application
+and not by PAM.
+
+<p>
+This function simply calls the <tt/pam_sm_setcred/ functions of each
+of the loaded modules. Valid <tt/flags/, any one of which, may be
+logically OR'd with <tt/PAM_SILENT/, are:
+
+<p><descrip>
+<tag><tt/PAM_ESTABLISH_CRED/</tag>
+ Set the credentials for the authentication service,
+<tag><tt/PAM_DELETE_CRED/</tag>
+ Delete the credentials associated with the authentication service,
+<tag><tt/PAM_REINITIALIZE_CRED/</tag>
+ Reinitialize the user credentials, and
+<tag><tt/PAM_REFRESH_CRED/</tag>
+ Extend the lifetime of the user credentials.
+</descrip>
+
+<p>
+A successful return is signalled with <tt/PAM_SUCCESS/. Errors that
+are especially relevant to this function are the following:
+
+<p><descrip>
+<tag><tt/PAM_CRED_UNAVAIL/</tag>
+ A module cannot retrieve the user's credentials.
+<tag><tt/PAM_CRED_EXPIRED/</tag>
+ The user's credentials have expired.
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The user is not known to an authentication module.
+<tag><tt/PAM_CRED_ERR/</tag>
+ A module was unable to set the credentials of the user.
+</descrip>
+
+<sect2>Account management
+
+<p>
+<tscreen>
+<verb>
+extern int pam_acct_mgmt(pam_handle_t *pamh, int flags);
+</verb>
+</tscreen>
+
+<p>
+This function is typically called after the user has been
+authenticated. It establishes whether the user's account is healthy.
+That is to say, whether the user's account is still active and whether
+the user is permitted to gain access to the system at this time.
+Valid flags, any one of which, may be logically OR'd with
+<tt/PAM_SILENT/, and are the same as those applicable to the
+<tt/flags/ argument of <tt/pam_authenticate/.
+
+<p>
+This function simply calls the corresponding functions of each of the
+loaded modules, as instructed by the configuration file,
+<tt>/etc/pam.conf</tt>.
+
+<p>
+The normal response from this function is <tt/PAM_SUCCESS/, however,
+specific failures are indicated by the following error returns:
+
+<descrip>
+<tag><tt/PAM_AUTHTOKEN_REQD/</tag>
+The user <bf/is/ valid but their authentication token has
+<em/expired/. The correct response to this return-value is to require
+that the user satisfies the <tt/pam_chauthtok()/ function before
+obtaining service. It may not be possible for some applications to do
+this. In such cases, the user should be denied access until such time
+as they can update their password.
+
+<tag><tt/PAM_ACCT_EXPIRED/</tag>
+ The user is no longer permitted access to the system.
+<tag><tt/PAM_AUTH_ERR/</tag>
+ There was an authentication error.
+
+<tag><tt/PAM_PERM_DENIED/</tag>
+ The user is not permitted to gain access at this time.
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The user is not known to a module's account management
+component.
+
+</descrip>
+
+<sect2>Updating authentication tokens
+<label id="pam-chauthtok-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_chauthtok(pam_handle_t *pamh, const int flags);
+</verb>
+</tscreen>
+
+<p>
+This function is used to change the authentication token for a given
+user (as indicated by the state associated with the handle,
+<tt/pamh/). The following is a valid but optional flag which may be
+logically OR'd with <tt/PAM_SILENT/,
+
+<descrip>
+<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag>
+ This argument indicates to the modules that the users
+authentication token (password) should only be changed if it has
+expired.
+</descrip>
+
+<p>
+Note, if this argument is not passed, the application requires that
+<em/all/ authentication tokens are to be changed.
+
+<p>
+<tt/PAM_SUCCESS/ is the only successful return value, valid
+error-returns are:
+
+<descrip>
+<tag><tt/PAM_AUTHTOK_ERR/</tag>
+ A module was unable to obtain the new authentication token.
+
+<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag>
+ A module was unable to obtain the old authentication token.
+
+<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag>
+ One or more of the modules was unable to change the
+authentication token since it is currently locked.
+
+<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag>
+ Authentication token aging has been disabled for at least one
+of the modules.
+
+<tag><tt/PAM_PERM_DENIED/</tag>
+ Permission denied.
+
+<tag><tt/PAM_TRY_AGAIN/</tag>
+ Not all of the modules were in a position to update the
+authentication token(s). In such a case none of the user's
+authentication tokens are updated.
+
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The user is not known to the authentication token changing
+service.
+
+</descrip>
+
+<sect2>Session initialization
+<label id="pam-open-session-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_open_session(pam_handle_t *pamh, int flags);
+</verb>
+</tscreen>
+
+<p>
+This function is used to indicate that an authenticated session has
+begun. It is used to inform the module that the user is currently in
+a session. It should be possible for the <bf>Linux-PAM</bf> library
+to open a session and close the same session (see section <ref
+id="pam-close-session-section" name="below">) from different
+applications.
+
+<p>
+Currently, this function simply calls each of the corresponding
+functions of the loaded modules. The only valid flag is
+<tt/PAM_SILENT/ and this is, of course, <em/optional/.
+
+<p>
+If any of the <em/required/ loaded modules are unable to open a
+session for the user, this function will return <tt/PAM_SESSION_ERR/.
+
+<sect2>Terminating sessions
+<label id="pam-close-session-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_close_session(pam_handle_t *pamh, int flags);
+</verb>
+</tscreen>
+
+<p>
+This function is used to indicate that an authenticated session has
+ended. It is used to inform the module that the user is exiting a
+session. It should be possible for the <bf>Linux-PAM</bf> library to
+open a session and close the same session from different applications.
+
+<p>
+Currently, this function simply calls each of the corresponding
+functions of the loaded modules. The only valid flag is
+<tt/PAM_SILENT/ and this is, of course, <em/optional/.
+
+<p>
+If any of the <em/required/ loaded modules are unable to close a
+session for the user, this function will return <tt/PAM_SESSION_ERR/.
+
+<sect2>Setting PAM environment variables
+<label id="pam-putenv-section">
+
+<p>
+<tscreen>
+<verb>
+extern int pam_putenv(pam_handle_t *pamh, const char *name_value);
+</verb>
+</tscreen>
+
+<p>
+<em>
+Warning, the environment support in <bf/Linux-PAM/ is based solely
+on a six line email from the developers at Sun. Its interface is
+likely to be generally correct, however, the details are likely to be
+changed as more information becomes available.
+</em>
+
+<p>
+This function attempts to (re)set a <bf/Linux-PAM/ environment
+variable. The <tt/name_value/ argument is a single <tt/NUL/ terminated
+string of one of the following forms:
+<descrip>
+<tag>``<tt/NAME=value of variable/''</tag>
+
+In this case the environment variable of the given <tt/NAME/ is set to
+the indicated value: ``<tt/value of variable/''. If this variable is
+already known, it is overwritten. Otherwise it is added to the
+<bf/Linux-PAM/ environment.
+
+<tag>``<tt/NAME=/''</tag>
+
+This function sets the variable to an empty value. It is listed
+separately to indicate that this is the correct way to achieve such a
+setting.
+
+<tag>``<tt/NAME/''</tag>
+
+Without an `<tt/=/' the <tt/pam_putenv()/ function will delete the
+correspoding variable from the <bf/Linux-PAM/ environment.
+
+</descrip>
+
+<p>
+Success is indicated with a return value of <tt/PAM_SUCCESS/. Failure
+is indicated by one of the following returns:
+
+<descrip>
+<tag><tt/PAM_PERM_DENIED/</tag>
+ name given is a <tt/NULL/ pointer
+
+<tag><tt/PAM_BAD_ITEM/</tag>
+ variable requested (for deletion) is not currently set
+
+<tag><tt/PAM_ABORT/</tag>
+ the <bf/Linux-PAM/ handle, <tt/pamh/, is corrupt
+
+<tag><tt/PAM_BUF_ERR/</tag>
+ failed to allocate memory when attempting update
+
+</descrip>
+
+<sect2>Getting a PAM environment variable
+<label id="pam-getenv-section">
+
+<p>
+<tscreen>
+<verb>
+extern const char *pam_getenv(pam_handle_t *pamh, const char *name);
+</verb>
+</tscreen>
+
+<p>
+<em>
+Warning, the environment support in <bf/Linux-PAM/ is based solely
+on a six-line email from the developers at Sun. Its interface is
+likely to be generally correct, however, the details are likely to be
+changed as more information becomes available.
+</em>
+
+<p>
+Obtain the value of the indicated <bf/Linux-PAM/ environment
+variable. On error, internal failure or the unavailability of the
+given variable (unspecified), this function simply returns <tt/NULL/.
+
+<sect2>Getting the PAM environment
+<label id="pam-getenvlist-section">
+
+<p>
+<tscreen>
+<verb>
+extern const char * const *pam_getenvlist(pam_handle_t *pamh);
+</verb>
+</tscreen>
+
+<p>
+<em>
+Warning, the environment support in <bf/Linux-PAM/ is based solely
+on a six line email from the developers at Sun. Its interface is
+likely to be generally correct, however, the details are likely to be
+changed as more information becomes available.
+</em>
+
+<p>
+This function returns a pointer to the complete <tt/Linux-PAM/
+environment. It is a pointer to a <em/read-only/ list of
+<em/read-only/ environment variables. It should be noted that this
+memory will become invalid after a call to <tt/pam_end()/ (see the
+section <ref id="pam-end-section" name="above">). If application
+wishes to make use of this list after such a call, it should first
+make a copy of all the set variables. (A function that performs such a
+transcription is to be found in <tt/libpam_misc/.)
+
+<sect1>What is expected of an application
+
+<sect2>The conversation function
+<label id="the-conversation-function">
+
+<p>
+An application must provide a ``conversation function''. It is used
+for direct communication between a loaded module and the application
+and will typically provide a means for the module to prompt the user
+for a password etc. . The structure, <tt/pam_conv/, is defined by
+including <tt>&lt;security/pam_appl.h&gt</tt>; to be,
+
+<p>
+<tscreen>
+<verb>
+struct pam_conv {
+ int (*conv)(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr);
+ void *appdata_ptr;
+};
+</verb>
+</tscreen>
+
+<p>
+It is initialized by the application before it is passed to the
+library. The <em/contents/ of this structure are attached to the
+<tt/*pamh/ handle. The point of this argument is to provide a
+mechanism for any loaded module to interact directly with the
+application program. This is why it is called a <em/conversation/
+structure.
+
+<p>
+When a module calls the referenced <tt/conv()/ function, the argument
+<tt/*appdata_ptr/ is set to the second element of this structure.
+
+<p>
+The other arguments of a call to <tt/conv()/ concern the information
+exchanged by module and application. That is to say, <tt/num_msg/
+holds the length of the array of pointers, <tt/msg/. After a
+successful return, the pointer <tt/*resp/ points to an array of
+<tt/pam_response/ structures, holding the application supplied text.
+Note, <tt/*resp/ is an <tt/struct pam_response/ array and <em/not/ an
+array of pointers.
+
+<p>
+The message (from the module to the application) passing structure is
+defined by <tt>&lt;security/pam_appl.h&gt;</tt> as:
+
+<p>
+<tscreen>
+<verb>
+struct pam_message {
+ int msg_style;
+ const char *msg;
+};
+</verb>
+</tscreen>
+
+<p>
+Valid choices for <tt/msg_style/ are:
+
+<p><descrip>
+<tag><tt/PAM_PROMPT_ECHO_OFF/</tag>
+ Obtain a string without echoing any text
+<tag><tt/PAM_PROMPT_ECHO_ON/</tag>
+ Obtain a string whilst echoing text
+<tag><tt/PAM_ERROR_MSG/</tag>
+ Display an error
+<tag><tt/PAM_TEXT_INFO/</tag>
+ Display some text.
+</descrip>
+
+<p>
+The point of having an array of messages is that it becomes possible
+to pass a number of things to the application in a single call from
+the module. It can also be convenient for the application that related
+things come at once: a windows based application can then present a
+single form with many messages/prompts on at once.
+
+<p>
+The response (from the application to the module) passing structure is
+defined by including <tt>&lt;security/pam_appl.h&gt;</tt> as:
+
+<p><tscreen><verb>
+struct pam_response {
+ char *resp;
+ int resp_retcode;
+};
+</verb></tscreen>
+
+<p>
+Currently, there are no definitions for <tt/resp_retcode/ values; the
+normal value is <tt/0/.
+
+<p>
+Prior to the 0.59 release of Linux-PAM, the length of the returned
+<tt/pam_response/ array was equal to the number of <em/prompts/ (types
+<tt/PAM_PROMPT_ECHO_OFF/ and <tt/PAM_PROMPT_ECHO_ON/) in the
+<tt/pam_message/ array with which the conversation function was
+called. This meant that it was not always necessary for the module to
+<tt/free(3)/ the responses if the conversation function was only used
+to display some text.
+
+<p>
+Post Linux-PAM-0.59 (and in the interests of compatibility with
+Sunsoft). The number of resposes is always equal to the <tt/num_msg/
+conversation function argument. This is slightly easier to program
+but does require that the response array is <tt/free(3)/'d after every
+call to the conversation function. The index of the responses
+corresponds directly to the prompt index in the <tt/pam_message/
+array.
+
+<p>
+The maximum length of the <tt/pam_msg.msg/ and <tt/pam_response.resp/
+character strings is <tt/PAM_MAX_MSG_SIZE/. (This is not enforced by
+Linux-PAM.)
+
+<p>
+<tt/PAM_SUCCESS/ is the expected return value of this
+function. However, should an error occur the application should not
+set <tt/*resp/ but simply return <tt/PAM_CONV_ERR/.
+
+<p>
+Note, if an application wishes to use two conversation functions, it
+should activate the second with a call to <tt/pam_set_item()/.
+
+<p>
+<bf>Notes:</bf> New item types are being added to the conversation
+protocol. Currently Linux-PAM supports: <tt>PAM_BINARY_PROMPT</tt>
+and <tt>PAM_BINARY_MSG</tt>. These two are intended for server-client
+hidden information exchange and may be used as an interface for
+maching-machine authentication.
+
+<sect1>Programming notes
+
+<p>
+Note, all of the authentication service function calls accept the
+token <tt/PAM_SILENT/, which instructs the modules to not send
+messages to the application. This token can be logically OR'd with any
+one of the permitted tokens specific to the individual function calls.
+<tt/PAM_SILENT/ does not override the prompting of the user for
+passwords etc., it only stops informative messages from being
+generated.
+
+<sect>Security issues of <bf>Linux-PAM</bf>
+
+<p>
+A poorly (or maliciously) written application can defeat any
+<bf/Linux-PAM/ module's authentication mechanisms by simply ignoring
+it's return values. It is the applications task and responsibility to
+grant privileges and access to services. The <bf/Linux-PAM/ library
+simply assumes the responsibility of <em/authenticating/ the user;
+ascertaining that the user <em/is/ who they say they are. Care should
+be taken to anticipate all of the documented behavior of the
+<bf/Linux-PAM/ library functions. A failure to do this will most
+certainly lead to a future security breach.
+
+<sect1>Care about standard library calls
+
+<p>
+In general, writers of authorization-granting applications should
+assume that each module is likely to call any or <em/all/ `libc'
+functions. For `libc' functions that return pointers to
+static/dynamically allocated structures (ie. the library allocates the
+memory and the user is not expected to `<tt/free()/' it) any module
+call to this function is likely to corrupt a pointer previously
+obtained by the application. The application programmer should either
+re-call such a `libc' function after a call to the <bf/Linux-PAM/
+library, or copy the structure contents to some safe area of memory
+before passing control to the <bf/Linux-PAM/ library.
+
+<p>
+Two function classes that fall into this category are
+<tt>getpwnam(3)</tt> and <tt>syslog(3)</tt>.
+
+<sect1>Choice of a service name
+
+<p>
+When picking the <em/service-name/ that corresponds to the first entry
+in the <tt>/etc/pam.conf</tt> file, the application programmer should
+<bf/avoid/ the temptation of choosing something related to
+<tt/argv[0]/. It is a trivial matter for any user to invoke any
+application on a system under a different name -- this should not be
+permitted to cause a security breach.
+
+<p>
+To invoke some <tt/target/ application by another name, the user may
+symbolically link the target application with the desired name. To be
+precise all the user need do is,
+<tscreen>
+<verb>
+ln -s /target/application ./preferred_name
+</verb>
+</tscreen>
+and then <em/run/ <tt>./preferred_name</tt>
+
+<p>
+By studying the <bf/Linux-PAM/ configuration file,
+<tt>/etc/pam.conf</tt>, an attacker can choose the <tt/preferred_name/
+to be that of a service enjoying minimal protection; for example a
+game which uses <bf/Linux-PAM/ to restrict access to certain hours of
+the day. If the service-name were to be linked to the filename under
+which the service was invoked, it is clear that the user is
+effectively in the position of dictating which authentication scheme
+the service uses. Needless to say, this is not a secure situation.
+
+<p>
+The conclusion is that the application developer should carefully
+define the service-name of an application. The safest thing is to make
+it a single hard-wired name.
+
+<sect1>The conversation function
+
+<p>
+Care should be taken to ensure that the <tt/conv()/ function is
+robust. Such a function is provided in the library <tt/libpam_misc/
+(see <ref id="libpam-misc-section" name="below">).
+
+<sect1>The identity of the user
+
+<p>
+The <bf/Linux-PAM/ modules will need to determine the identity of the
+user who requests a service, and the identity of the user who grants
+the service. These two users will seldom be the same. Indeed there
+is generally a third user identity to be considered, the new (assumed)
+identity of the user once the service is granted.
+
+<p>
+The need for keeping tabs on these identities is clearly an issue of
+security. Basically, the identity of the user requesting a service
+should be the current <tt/uid/ (userid) of the running process; the
+identity of the privilege granting user is the <tt/euid/ (effective
+userid) of the running process; the identity of the user, under whose
+name the service will be executed, is given by the contents of the
+<tt/PAM_USER/ <tt/pam_get_item(2)/.
+
+<p>
+In addition the identity of a remote user, requesting the service from
+a distant location, will be placed in the <tt/PAM_RUSER/ item.
+
+<sect1>Sufficient resources
+
+<p>
+Care should be taken to ensure that the proper execution of an
+application is not compromised by a lack of system resources. If an
+application is unable to open sufficient files to perform its service,
+it should fail gracefully, or request additional resources.
+Specifically, the quantities manipulated by the <tt/setrlimit(2)/
+family of commands should be taken into consideration.
+
+<sect>A library of miscellaneous helper functions
+<label id="libpam-misc-section">
+
+<p>
+To aid the work of the application developer a library of
+miscellaneous functions is provided. It is called <tt/libpam_misc/,
+and contains functions for allocating memory (securely), a text based
+conversation function, and routines for enhancing the standard
+PAM-environment variable support.
+
+<sect1>Requirements
+
+<p>
+The functions, structures and macros, made available by this library
+can be defined by including <tt>&lt;security/pam_misc.h&gt;</tt>. It
+should be noted that this library is specific to <bf/Linux-PAM/ and is
+not referred to in the defining DCE-RFC (see <ref id="bibliography"
+name="the bibliography">) below.
+
+<sect1>Functions supplied
+
+<sect2>Safe string duplication
+
+<p>
+<tscreen>
+<verb>
+extern char *xstrdup(const char *s)
+</verb>
+</tscreen>
+Return a duplicate copy of the <tt/NUL/ terminated string,
+<tt/s/. <tt/NULL/ is returned if there is insufficient memory
+available for the duplicate or if <tt/s=NULL/.
+
+<sect2>A text based conversation function
+
+<p>
+<tscreen>
+<verb>
+extern int misc_conv(int num_msg, const struct pam_message **msgm,
+ struct pam_response **response, void *appdata_ptr);
+</verb>
+</tscreen>
+
+<p>
+This is a function that will prompt the user with the appropriate
+comments and obtain the appropriate inputs as directed by
+authentication modules.
+
+<p>
+In addition to simply slotting into the appropriate <tt/struct
+pam_conv/, this function provides some time-out facilities. The
+function exports five variables that can be used by an application
+programmer to limit the amount of time this conversation function will
+spend waiting for the user to type something.
+
+<p>
+The five variables are as follows:
+<descrip>
+<tag><tt>extern time_t pam_misc_conv_warn_time;</tt></tag>
+
+This variable contains the <em/time/ (as returned by <tt/time()/) that
+the user should be first warned that the clock is ticking. By default
+it has the value <tt/0/, which indicates that no such warning will be
+given. The application may set its value to sometime in the future,
+but this should be done prior to passing control to the <bf/Linux-PAM/
+library.
+
+<tag><tt>extern const char *pam_misc_conv_warn_line;</tt></tag>
+
+Used in conjuction with <tt/pam_misc_conv_warn_time/, this variable is
+a pointer to the string that will be displayed when it becomes time to
+warn the user that the timeout is approaching. Its default value is
+``..&bsol;a.Time is running out...&bsol;n'', but this can be changed
+by the application prior to passing control to <bf/Linux-PAM/.
+
+<tag><tt>extern time_t pam_misc_conv_die_time;</tt></tag>
+
+This variable contains the <em/time/ (as returned by <tt/time()/) that
+the conversation will time out. By default it has the value <tt/0/,
+which indicates that the conversation function will not timeout. The
+application may set its value to sometime in the future, this should
+be done prior to passing control to the <bf/Linux-PAM/ library.
+
+<tag><tt>extern const char *pam_misc_conv_die_line;</tt></tag>
+
+Used in conjuction with <tt/pam_misc_conv_die_time/, this variable is
+a pointer to the string that will be displayed when the conversation
+times out. Its default value is ``..&bsol;a.Sorry, your time is
+up!&bsol;n'', but this can be changed by the application prior to
+passing control to <bf/Linux-PAM/.
+
+<tag><tt>extern int pam_misc_conv_died;</tt></tag>
+
+Following a return from the <bf/Linux-PAM/ libraray, the value of this
+variable indicates whether the conversation has timed out. A value of
+<tt/1/ indicates the time-out occurred.
+
+<tag><tt>extern int (*pam_binary_handler_fn)(const union pam_u_packet_p send,
+ union pam_u_packet_p *receive);</tt></tag>
+
+This function pointer is initialized to <tt/NULL/ but can be filled
+with a function that provides machine-machine (hidden) message
+exchange. It is intended for use with hidden authentication protocols
+such as RSA or Diffie-Hellman key exchanges. (This is still under
+development.)
+
+</descrip>
+
+<sect2>Transcribing an environment to that of Linux-PAM
+<p>
+<tscreen>
+<verb>
+extern int pam_misc_paste_env(pam_handle_t *pamh,
+ const char * const * user_env);
+</verb>
+</tscreen>
+
+This function takes the supplied list of environment pointers and
+<em/uploads/ its contents to the <bf/Linux-PAM/ environment. Success
+is indicated by <tt/PAM_SUCCESS/.
+
+<sect2>Saving the Linux-PAM environment for later use
+<p>
+<tscreen>
+<verb>
+extern char **pam_misc_copy_env(pam_handle_t *pamh);
+</verb>
+</tscreen>
+
+This function returns a pointer to a list of environment variables
+that are a direct copy of the <bf/Linux-PAM/ environment. The memory
+associated with these variables are the responsibility of the
+application and should be liberated with a call to
+<tt/pam_misc_drop_env()/.
+
+<sect2>Liberating a locally saved environment
+<p>
+<tscreen>
+<verb>
+extern char **pam_misc_drop_env(char **env);
+</verb>
+</tscreen>
+
+This function is defined to complement the <tt/pam_misc_copy_env()/
+function. It liberates the memory associated with <tt/env/,
+<em/overwriting/ with <tt/0/ all memory before <tt/free()/ing it.
+
+<sect2>BSD like Linux-PAM environment variable setting
+<p>
+<tscreen>
+<verb>
+extern int pam_misc_setenv(pam_handle_t *pamh, const char *name,
+ const char *value, int readonly);
+</verb>
+</tscreen>
+
+This function performs a task equivalent to <tt/pam_putenv()/, its
+syntax is, however, more like the BSD style function; <tt/setenv()/.
+The <tt/name/ and <tt/value/ are concatenated with an ``<tt/=/'' to
+form a <tt/name_value/ and passed to <tt/pam_putenv()/. If, however,
+the <bf/Linux-PAM/ variable is already set, the replacement will only
+be applied if the last argument, <tt/readonly/, is zero.
+
+<sect>Porting legacy applications
+
+<p>
+The following is extracted from an email. I'll tidy it up later.
+
+<p>
+The point of PAM is that the application is not supposed to have any
+idea how the attatched authentication modules will choose to
+authenticate the user. So all they can do is provide a conversation
+function that will talk directly to the user(client) on the modules'
+behalf.
+
+<p>
+Consider the case that you plug a retinal scanner into the login
+program. In this situation the user would be prompted: "please look
+into the scanner". No username or password would be needed - all this
+information could be deduced from the scan and a database lookup. The
+point is that the retinal scanner is an ideal task for a "module".
+
+<p>
+While it is true that a pop-daemon program is designed with the POP
+protocol in mind and no-one ever considered attatching a retinal
+scanner to it, it is also the case that the "clean" PAM'ification of
+such a daemon would allow for the possibility of a scanner module
+being be attatched to it. The point being that the "standard"
+pop-authentication protocol(s) [which will be needed to satisfy
+inflexible/legacy clients] would be supported by inserting an
+appropriate pam_qpopper module(s). However, having rewritten popd
+once in this way any new protocols can be implemented in-situ.
+
+<p>
+One simple test of a ported application would be to insert the
+<tt/pam_permit/ module and see if the application demands you type a
+password... In such a case, <tt/xlock/ would fail to lock the
+terminal - or would at best be a screen-saver, ftp would give password
+free access to all etc.. Neither of these is a very secure thing to
+do, but they do illustrate how much flexibility PAM puts in the hands
+of the local admin.
+
+<p>
+The key issue, in doing things correctly, is identifying what is part
+of the authentication procedure (how many passwords etc..) the
+exchange protocol (prefixes to prompts etc., numbers like 331 in the
+case of ftpd) and what is part of the service that the application
+delivers. PAM really needs to have total control in the
+authentication "proceedure", the conversation function should only
+deal with reformatting user prompts and extracting responses from raw
+input.
+
+<sect>Glossary of PAM related terms
+
+<p>
+The following are a list of terms used within this document.
+
+<p>
+<descrip>
+
+<tag>Authentication token</tag>
+Generally, this is a password. However, a user can authenticate
+him/herself in a variety of ways. Updating the user's authentication
+token thus corresponds to <em>refreshing</em> the object they use to
+authenticate themself with the system. The word password is avoided
+to keep open the possibility that the authentication involves a
+retinal scan or other non-textual mode of challenge/response.
+
+<tag>Credentials</tag>
+Having successfully authenticated the user, PAM is able to establish
+certain characteristics/attributes of the user. These are termed
+<em>credentials</em>. Examples of which are group memberships to
+perform privileged tasks with, and <em>tickets</em> in the form of
+environment variables etc. . Some user-credentials, such as the
+user's UID and GID (plus default group memberships) are not deemed to
+be PAM-credentials. It is the responsibility of the application to
+grant these directly.
+
+</descrip>
+
+<sect>An example application
+
+<p>
+To get a flavor of the way a <tt/Linux-PAM/ application is written we
+include the following example. It prompts the user for their password
+and indicates whether their account is valid on the standard output,
+its return code also indicates the success (<tt/0/ for success; <tt/1/
+for failure).
+
+<p>
+<tscreen>
+<verb>
+/*
+ This program was contributed by Shane Watts
+ [modifications by AGM]
+
+ You need to add the following (or equivalent) to the /etc/pam.conf file.
+ # check authorization
+ check_user auth required /usr/lib/security/pam_unix_auth.so
+ check_user account required /usr/lib/security/pam_unix_acct.so
+ */
+
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#include <stdio.h>
+
+static struct pam_conv conv = {
+ misc_conv,
+ NULL
+};
+
+int main(int argc, char *argv[])
+{
+ pam_handle_t *pamh=NULL;
+ int retval;
+ const char *user="nobody";
+
+ if(argc == 2) {
+ user = argv[1];
+ }
+
+ if(argc > 2) {
+ fprintf(stderr, "Usage: check_user [username]\n");
+ exit(1);
+ }
+
+ retval = pam_start("check_user", user, &ero;conv, &ero;pamh);
+
+ if (retval == PAM_SUCCESS)
+ retval = pam_authenticate(pamh, 0); /* is user really user? */
+
+ if (retval == PAM_SUCCESS)
+ retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
+
+ /* This is where we have been authorized or not. */
+
+ if (retval == PAM_SUCCESS) {
+ fprintf(stdout, "Authenticated\n");
+ } else {
+ fprintf(stdout, "Not Authenticated\n");
+ }
+
+ if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
+ pamh = NULL;
+ fprintf(stderr, "check_user: failed to release authenticator\n");
+ exit(1);
+ }
+
+ return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */
+}
+</verb>
+</tscreen>
+
+<sect>Files
+
+<p><descrip>
+
+<tag><tt>/usr/include/security/pam_appl.h</tt></tag>
+
+header file for <bf/Linux-PAM/ applications interface
+
+<tag><tt>/usr/include/security/pam_misc.h</tt></tag>
+
+header file for useful library functions for making applications
+easier to write
+
+<tag><tt>/usr/lib/libpam.so.*</tt></tag>
+
+the shared library providing applications with access to
+<bf/Linux-PAM/.
+
+<tag><tt>/etc/pam.conf</tt></tag>
+
+the <bf/Linux-PAM/ configuration file.
+
+<tag><tt>/usr/lib/security/pam_*.so</tt></tag>
+
+the primary location for <bf/Linux-PAM/ dynamically loadable object
+files; the modules.
+
+</descrip>
+
+<sect>See also
+<label id="bibliography">
+
+<p><itemize>
+
+<item>The <bf/Linux-PAM/
+<htmlurl url="pam.html" name="System Administrators' Guide">.
+
+<item>The <bf/Linux-PAM/
+<htmlurl url="pam_modules.html" name="Module Writers' Guide">.
+
+<item>The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH
+PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request
+For Comments 86.0, October 1995.
+
+</itemize>
+
+<sect>Notes
+
+<p>
+I intend to put development comments here... like ``at the moment
+this isn't actually supported''. At release time what ever is in
+this section will be placed in the Bugs section below! :)
+
+<p>
+<itemize>
+
+<item> <tt/pam_strerror()/ should be internationalized....
+
+<item>
+Note, the <tt/resp_retcode/ of struct <tt/pam_message/, has no
+purpose at the moment. Ideas/suggestions welcome!
+
+<item> more security issues are required....
+
+</itemize>
+
+<sect>Author/acknowledgments
+
+<p>
+This document was written by Andrew G. Morgan
+(morgan@transmeta.com) with many contributions from
+<!-- insert credits here -->
+<!--
+ an sgml list of people to credit for their contributions to Linux-PAM
+ $Id: CREDITS,v 1.4 1997/04/05 06:47:26 morgan Exp morgan $
+ -->
+Peter Allgeyer,
+Tim Baverstock,
+Craig S. Bell,
+Derrick J. Brashear,
+Ben Buxton,
+Oliver Crow,
+Chris Dent,
+Marc Ewing,
+Cristian Gafton,
+Eric Hester,
+Roger Hu,
+Eric Jacksch,
+Michael K. Johnson,
+David Kinchlea,
+Nicolai Langfeldt,
+Elliot Lee,
+Al Longyear,
+Ingo Luetkebohle,
+Marek Michalkiewicz,
+Aleph One,
+Martin Pool,
+Sean Reifschneider,
+Erik Troan,
+Theodore Ts'o,
+Jeff Uphoff,
+Myles Uyema,
+Savochkin Andrey Vladimirovich,
+Ronald Wahl,
+David Wood,
+John Wilmes,
+Joseph S. D. Yao
+and
+Alex O. Yuriev.
+
+
+<p>
+Thanks are also due to Sun Microsystems, especially to Vipin Samar and
+Charlie Lai for their advice. At an early stage in the development of
+<bf/Linux-PAM/, Sun graciously made the documentation for their
+implementation of PAM available. This act greatly accelerated the
+development of <bf/Linux-PAM/.
+
+<sect>Bugs/omissions
+
+<p>
+This manual is hopelessly unfinished. Only a partial list of people is
+credited for all the good work they have done.
+
+<sect>Copyright information for this document
+
+<p>
+Copyright (c) Andrew G. Morgan 1996, 1997. All rights reserved.
+<newline>
+Email: <tt>&lt;morgan@transmeta.com&gt;</tt>
+
+<p>
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+<p>
+<itemize>
+
+<item>
+1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+<item>
+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.
+
+<item>
+3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+</itemize>
+
+<p>
+<bf/Alternatively/, this product may be distributed under the terms of
+the GNU General Public License (GPL), in which case the provisions of
+the GNU GPL are required <bf/instead of/ the above restrictions.
+(This clause is necessary due to a potential bad interaction between
+the GNU GPL and the restrictions contained in a BSD-style copyright.)
+
+<p>
+THIS SOFTWARE IS PROVIDED ``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 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.
+
+<p>
+<tt>$Id: pam_appl.sgml,v 1.16 1997/04/05 06:49:14 morgan Exp morgan $</tt>
+
+</article>
diff --git a/contrib/libpam/doc/pam_modules.sgml b/contrib/libpam/doc/pam_modules.sgml
new file mode 100644
index 000000000000..418b09beafd3
--- /dev/null
+++ b/contrib/libpam/doc/pam_modules.sgml
@@ -0,0 +1,1425 @@
+<!doctype linuxdoc system>
+
+<!--
+
+ $Id: pam_modules.sgml,v 1.19 1997/04/05 06:49:14 morgan Exp morgan $
+
+ Copyright (c) Andrew G. Morgan 1996, 1997. All rights reserved.
+
+ ** some sections, in this document, were contributed by other
+ ** authors. They carry individual copyrights.
+
+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, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+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.
+
+ALTERNATIVELY, this product may be distributed under the terms of the
+GNU General Public License, in which case the provisions of the GNU
+GPL are required INSTEAD OF the above restrictions. (This clause is
+necessary due to a potential bad interaction between the GNU GPL and
+the restrictions contained in a BSD-style copyright.)
+
+THIS SOFTWARE IS PROVIDED ``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 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.
+
+ -->
+
+<article>
+
+<title>The Linux-PAM Module Writers' Guide
+<author>Andrew G. Morgan, <tt>morgan@transmeta.com</tt>
+<date>DRAFT v0.59 1997/10/17
+<abstract>
+This manual documents what a programmer needs to know in order to
+write a module that conforms to the <bf/Linux-PAM/ standard. It also
+discusses some security issues from the point of view of the module
+programmer.
+</abstract>
+
+<toc>
+
+<sect>Introduction
+
+<sect1> Synopsis
+<p>
+<tscreen>
+<verb>
+#include <security/pam_modules.h>
+
+gcc -fPIC -c pam_module-name.c
+ld -x --shared -o pam_module-name.so pam_module-name.o -lpam
+</verb>
+</tscreen>
+
+<sect1> Description
+
+<p>
+<bf/Linux-PAM/ (Pluggable Authentication Modules for Linux) is a
+library that enables the local system administrator to choose how
+individual applications authenticate users. For an overview of the
+<bf/Linux-PAM/ library see the <bf/Linux-PAM/ System Administrators'
+Guide.
+
+<p>
+A <bf/Linux-PAM/ module is a single executable binary file that can be
+loaded by the <bf/Linux-PAM/ interface library. This PAM library is
+configured locally with a system file, <tt>/etc/pam.conf</tt>, to
+authenticate a user request via the locally available authentication
+modules. The modules themselves will usually be located in the
+directory <tt>/usr/lib/security</tt> and take the form of dynamically
+loadable object files (see dlopen(3)). Alternatively, the modules can
+be statically linked into the <bf/Linux-PAM/ library; this is mostly to
+allow <bf/Linux-PAM/ to be used on platforms without dynamic linking
+available, but the two forms can be used together. It is the
+<bf/Linux-PAM/ interface that is called by an application and it is
+the responsibility of the library to locate, load and call the
+appropriate functions in a <bf/Linux-PAM/-module.
+
+<p>
+Except for the immediate purpose of interacting with the user
+(entering a password etc..) the module should never call the
+application directly. This exception requires a "conversation
+mechanism" which is documented below.
+
+<sect>What can be expected by the module
+
+<p>
+Here we list the interface that the conventions that all
+<bf/Linux-PAM/ modules must adhere to.
+
+<sect1>Getting and setting <tt/PAM_ITEM/s and <em/data/
+
+<p>
+First, we cover what the module should expect from the <bf/Linux-PAM/
+library and a <bf/Linux-PAM/ <em/aware/ application. Essesntially this
+is the <tt/libpam.*/ library.
+
+<sect2>
+Setting data
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern int pam_set_data(pam_handle_t *pamh
+ , const char *module_data_name
+ , void *data
+ , void (*cleanup)(pam_handle_t *pamh
+ , void *data
+ , int error_status)
+ );
+</verb>
+</tscreen>
+
+<p>
+The modules may be dynamically loadable objects. In general such files
+should not contain <tt/static/ variables. This and the subsequent
+function provide a mechanism for a module to associate some data with
+the handle <tt/pamh/. Typically a module will call the
+<tt/pam_set_data()/ function to register some data under a (hopefully)
+unique <tt/module_data_name/. The data is available for use by other
+modules too but <em/not/ by an application.
+
+<p>
+The function <tt/cleanup()/ is associated with the <tt/data/ and, if
+non-<tt/NULL/, it is called when this data is over-written or
+following a call to <tt/pam_end()/ (see the Linux-PAM Application
+Developers' Guide).
+
+<p>
+The <tt/error_status/ argument is used to indicate to the module the
+sort of action it is to take in cleaning this data item. As an
+example, Kerberos creates a ticket file during the authentication
+phase, this file might be associated with a data item. When
+<tt/pam_end()/ is called by the module, the <tt/error_status/
+carries the return value of the <tt/pam_authenticate()/ or other
+<tt/libpam/ function as appropriate. Based on this value the Kerberos
+module may choose to delete the ticket file (<em/authentication
+failure/) or leave it in place.
+
+<p>
+(*This paragraph is currently under advisement with Sun*) The
+<tt/error_status/ may have been logically OR'd with either of the
+following two values:
+
+<p>
+<descrip>
+<tag><tt/PAM_DATA_REPLACE/</tag>
+ When a data item is being replaced (through a second call to
+<tt/pam_set_data()/) this mask is used is used. Otherwise, the call is
+assumed to be from <tt/pam_end()/.
+
+<tag><tt/PAM_DATA_SILENT/</tag>
+ Which indicates that the process would prefer to perform the
+<tt/cleanup()/ quietly. That is, discourages logging/messages to the
+user.
+
+</descrip>
+
+
+<sect2>
+Getting data
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern int pam_get_data(const pam_handle_t *pamh
+ , const char *module_data_name
+ , const void **data
+ );
+</verb>
+</tscreen>
+
+<p>
+This function together with the previous one provides a method of
+associating module-specific data with the handle <tt/pamh/. A
+successful call to <tt/pam_get_data/ will result in <tt/*data/
+pointing to the data associated with the <tt/module_data_name/. Note,
+this data is <em/not/ a copy and should be treated as <em/constant/
+by the module.
+
+<p>
+Note, if there is an entry but it has the value <tt/NULL/, then this
+call returns <tt/PAM_NO_MODULE_DATA/.
+
+<sect2>
+Setting items
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern int pam_set_item(pam_handle_t *pamh
+ , int item_type
+ , const void *item
+ );
+</verb>
+</tscreen>
+
+<p>
+This function is used to (re)set the value of one of the
+<tt/item_type/s. The reader is urged to read the entry for this
+function in the <bf/Linux-PAM/ application developers' manual.
+
+<p>
+In addition to the <tt/item/s listed there, the module can set the
+following two <tt/item_type/s:
+
+<p>
+<descrip>
+<tag><tt/PAM_AUTHTOK/</tag>
+
+The authentication token (password). This token should be ignored by
+all module functions besides <tt/pam_sm_authenticate()/ and
+<tt/pam_sm_chauthtok()/. In the former function it is used to pass the
+most recent authentication token from one stacked module to
+another. In the latter function the token is used for another
+purpose. It contains the currently active authentication token.
+
+<tag><tt/PAM_OLDAUTHTOK/</tag>
+
+The old authentication token. This token should be ignored by all
+module functions except <tt/pam_sm_chauthtok()/.
+
+</descrip>
+
+<p>
+Both of these items are reset before returning to the application.
+When resetting these items, the <bf/Linux-PAM/ library first writes
+<tt/0/'s to the current tokens and then <tt/free()/'s the associated
+memory.
+
+<p>
+The return values for this function are listed in the
+<bf>Linux-PAM</bf> Application Developers' Guide.
+
+<sect2>
+Getting items
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern int pam_get_item(const pam_handle_t *pamh
+ , int item_type
+ , const void **item
+ );
+</verb>
+</tscreen>
+
+<p>
+This function is used to obtain the value of the specified
+<tt/item_type/. It is better documented in the <bf/Linux-PAM/
+Application Developers' Guide. However, there are three things worth
+stressing here:
+<itemize>
+
+<item>
+Generally, if the module wishes to obtain the name of the user, it
+should not use this function, but instead perform a call to
+<tt/pam_get_user()/ (see section <ref id="pam-get-user"
+name="below">).
+
+<item>
+The module is additionally privileged to read the authentication
+tokens, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/ (see the section
+above on <tt/pam_set_data()/).
+
+<item>
+The module should <em/not/ <tt/free()/ or alter the data pointed to by
+<tt/*item/ after a successful return from <tt/pam_get_item()/. This
+pointer points directly at the data contained within the <tt/*pamh/
+structure. Should a module require that a change is made to the this
+<tt/ITEM/ it should make the appropriate call to <tt/pam_set_item()/.
+</itemize>
+
+<sect2>The <em/conversation/ mechanism
+
+<p>
+Following the call <tt>pam_get_item(pamh,PAM_CONV,&amp;item)</tt>, the
+pointer <tt/item/ points to a <em/conversation/-function that provides
+limited but direct access to the application. The purpose of this
+function is to allow the module to prompt the user for their password
+and pass other information in a manner consistent with the
+application. For example, an X-windows based program might pop up a
+dialog box to report a login failure. Just as the application should
+not be concerned with the method of authentication, so the module
+should not dictate the manner in which input (output) is
+obtained from (presented to) to the user.
+
+<p>
+The reader is strongly urged to read the more complete description of
+the <tt/pam_conv/ structure, written from the perspective of the
+application developer, in the <bf/Linux-PAM/ Application Developers'
+Guide.
+
+<p>
+The <tt/pam_response/ structure returned after a call to the
+<tt/pam_conv/ function must be <tt/free()/'d by the module. Since the
+call to the conversation function originates from the module, it is
+clear that either this <tt/pam_response/ structure could be either
+statically or dynamically (using <tt/malloc()/ etc.) allocated within
+the application. Repeated calls to the conversation function would
+likely overwrite static memory, so it is required that for a
+successful return from the conversation function the memory for the
+response structure is dynamically allocated by the application with
+one of the <tt/malloc()/ family of commands and <em/must/ be
+<tt/free()/'d by the module.
+
+<p>
+If the <tt/pam_conv/ mechanism is used to enter authentication tokens,
+the module should either pass the result to the <tt/pam_set_item()/
+library function, or copy it itself. In such a case, once the token
+has been stored (by one of these methods or another one), the memory
+returned by the application should be overwritten with <tt/0/'s, and
+then <tt/free()/'d.
+
+<p>
+The return values for this function are listed in the
+<bf>Linux-PAM</bf> Application Developers' Guide.
+
+<sect2>Getting the name of a user<label id="pam-get-user">
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern int pam_get_user(pam_handle_t *pamh
+ , const char **user
+ , const char *prompt
+ );
+</verb>
+</tscreen>
+
+<p>
+This is a <bf/Linux-PAM/ library function that returns the
+(prospective) name of the user. To determine the username it does the
+following things, in this order:
+<itemize>
+
+<item> checks what <tt/pam_get_item(pamh, PAM_USER, ... );/ would have
+returned. If this is not <tt/NULL/ this is what it returns. Otherwise,
+
+<item> obtains a username from the application via the <tt/pam_conv/
+mechanism, it prompts the user with the first non-<tt/NULL/ string in
+the following list:
+<itemize>
+
+<item> The <tt/prompt/ argument passed to the function
+<item> What is returned by <tt/pam_get_item(pamh,PAM_USER_PROMPT, ... );/
+<item> The default prompt: ``Please enter username: ''
+
+</itemize>
+</itemize>
+
+<p>
+By whatever means the username is obtained, a pointer to it is
+returned as the contents of <tt/*user/. Note, this memory should
+<em/not/ be <tt/free()/'d by the module. Instead, it will be liberated
+on the next call to <tt/pam_get_user()/, or by <tt/pam_end()/ when the
+application ends its interaction with <bf/Linux-PAM/.
+
+<p>
+Also, in addition, it should be noted that this function sets the
+<tt/PAM_USER/ item that is associated with the <tt/pam_[gs]et_item()/
+function.
+
+<sect2>Setting a Linux-PAM environment variable
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern int pam_putenv(pam_handle_t *pamh, const char *name_value);
+</verb>
+</tscreen>
+
+<p>
+<bf/Linux-PAM/ (0.54+) comes equipped with a series of functions for
+maintaining a set of <em/environment/ variables. The environment is
+initialized by the call to <tt/pam_start()/ and is <bf/erased/ with a
+call to <tt/pam_end()/. This <em/environment/ is associated with the
+<tt/pam_handle_t/ pointer returned by the former call.
+
+<p>
+The default environment is all but empty. It contains a single
+<tt/NULL/ pointer, which is always required to terminate the
+variable-list. The <tt/pam_putenv()/ function can be used to add a
+new environment variable, replace an existing one, or delete an old
+one.
+
+<p>
+<itemize>
+<item>Adding/replacing a variable<newline>
+
+To add or overwrite a <bf/Linux-PAM/ environment variable the value of
+the argument <tt/name_value/, should be of the following form:
+<tscreen>
+<verb>
+name_value="VARIABLE=VALUE OF VARIABLE"
+</verb>
+</tscreen>
+Here, <tt/VARIABLE/ is the environment variable's name and what
+follows the `<tt/=/' is its (new) value. (Note, that <tt/"VARIABLE="/
+is a valid value for <tt/name_value/, indicating that the variable is
+set to <tt/""/.)
+
+<item> Deleting a variable<newline>
+
+To delete a <bf/Linux-PAM/ environment variable the value of
+the argument <tt/name_value/, should be of the following form:
+<tscreen>
+<verb>
+name_value="VARIABLE"
+</verb>
+</tscreen>
+Here, <tt/VARIABLE/ is the environment variable's name and the absence
+of an `<tt/=/' indicates that the variable should be removed.
+
+</itemize>
+
+<p>
+In all cases <tt/PAM_SUCCESS/ indicates success.
+
+<sect2>Getting a Linux-PAM environment variable
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern const char *pam_getenv(pam_handle_t *pamh, const char *name);
+</verb>
+</tscreen>
+
+<p>
+This function can be used to return the value of the given
+variable. If the returned value is <tt/NULL/, the variable is not
+known.
+
+<sect2>Listing the Linux-PAM environment
+
+<p>
+Synopsis:
+<tscreen>
+<verb>
+extern char * const *pam_getenvlist(pam_handle_t *pamh);
+</verb>
+</tscreen>
+
+<p>
+This function returns a pointer to the entire <bf/Linux-PAM/
+environment array. At first sight the <em/type/ of the returned data
+may appear a little confusing. It is basically a <em/read-only/ array
+of character pointers, that lists the <tt/NULL/ terminated list of
+environment variables set so far.
+
+<p>
+Although, this is not a concern for the module programmer, we mention
+here that an application should be careful to copy this entire array
+before executing <tt/pam_end()/ otherwise all the variable information
+will be lost. (There are functions in <tt/libpam_misc/ for this
+purpose: <tt/pam_misc_copy_env()/ and <tt/pam_misc_drop_env()/.)
+
+<sect1>Other functions provided by <tt/libpam/
+
+<sect2>Understanding errors
+
+<p>
+<itemize>
+
+<item>
+<tt>extern const char *pam_strerror(pam_handle_t *pamh, int errnum);</tt>
+
+<p>
+This function returns some text describing the <bf/Linux-PAM/ error
+associated with the argument <tt/errnum/. If the error is not
+recognized <tt/``Unknown Linux-PAM error''/ is returned.
+
+</itemize>
+
+<sect2>Planning for delays
+
+<p>
+<itemize>
+
+<item>
+<tt>extern int pam_fail_delay(pam_handle_t *pamh, unsigned int
+micro_sec)</tt>
+
+<p>
+This function is offered by <bf/Linux-PAM/ to facilitate time delays
+following a failed call to <tt/pam_authenticate()/ and before control
+is returned to the application. When using this function the module
+programmer should check if it is available with,
+<tscreen>
+<verb>
+#ifdef HAVE_PAM_FAIL_DELAY
+ ....
+#endif /* HAVE_PAM_FAIL_DELAY */
+</verb>
+</tscreen>
+
+<p>
+Generally, an application requests that a user is authenticated by
+<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or
+<tt/pam_chauthtok()/. These functions calls each of the <em/stacked/
+authentication modules listed in the <tt>/etc/pam.conf</tt> file. As
+directed by this file, one of more of the modules may fail causing the
+<tt/pam_...()/ call to return an error. It is desirable for there to
+also be a pause before the application continues. The principal reason
+for such a delay is security: a delay acts to discourage <em/brute
+force/ dictionary attacks primarily, but also helps hinder
+<em/timed/ (covert channel) attacks.
+
+<p>
+The <tt/pam_fail_delay()/ function provides the mechanism by which an
+application or module can suggest a minimum delay (of <tt/micro_sec/
+<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time
+requested with this function. Should <tt/pam_authenticate()/ fail,
+the failing return to the application is delayed by an amount of time
+randomly distributed (by up to 25%) about this longest value.
+
+<p>
+Independent of success, the delay time is reset to its zero default
+value when <bf/Linux-PAM/ returns control to the application.
+
+</itemize>
+
+<sect>What is expected of a module
+
+<p>
+The module must supply a sub-set of the six functions listed
+below. Together they define the function of a <bf/Linux-PAM
+module/. Module developers are strongly urged to read the comments on
+security that follow this list.
+
+<sect1> Overview
+
+<p>
+The six module functions are grouped into four independent management
+groups. These groups are as follows: <em/authentication/,
+<em/account/, <em/session/ and <em/password/. To be properly defined,
+a module must define all functions within at least one of these
+groups. A single module may contain the necessary functions for
+<em/all/ four groups.
+
+<sect2> Functional independence
+
+<p>
+The independence of the four groups of service a module can offer
+means that the module should allow for the possibility that any one of
+these four services may legitimately be called in any order. Thus, the
+module writer should consider the appropriateness of performing a
+service without the prior success of some other part of the module.
+
+<p>
+As an informative example, consider the possibility that an
+application applies to change a user's authentication token, without
+having first requested that <bf/Linux-PAM/ authenticate the user. In
+some cases this may be deemed appropriate: when <tt/root/ wants to
+change the authentication token of some lesser user. In other cases it
+may not be appropriate: when <tt/joe/ maliciously wants to reset
+<tt/alice/'s password; or when anyone other than the user themself
+wishes to reset their <em/KERBEROS/ authentication token. A policy for
+this action should be defined by any reasonable authentication scheme,
+the module writer should consider this when implementing a given
+module.
+
+<sect2> Minimizing administration problems
+
+<p>
+To avoid system administration problems and the poor construction of a
+<tt>/etc/pam.conf</tt> file, the module developer may define all
+six of the following functions. For those functions that would not be
+called, the module should return <tt/PAM_SERVICE_ERR/ and write an
+appropriate message to the system log. When this action is deemed
+inappropriate, the function would simply return <tt/PAM_IGNORE/.
+
+<sect2> Arguments supplied to the module
+
+<p>
+The <tt/flags/ argument of each of the following functions can be
+logically OR'd with <tt/PAM_SILENT/, which is used to inform the
+module to not pass any <em/text/ (errors or warnings) to the
+application.
+
+<p>
+The <tt/argc/ and <tt/argv/ arguments are taken from the line
+appropriate to this module---that is, with the <em/service_name/
+matching that of the application---in the configuration file (see the
+<bf/Linux-PAM/ System Administrators' Guide). Together these two
+parameters provide the number of arguments and an array of pointers to
+the individual argument tokens. This will be familiar to C programmers
+as the ubiquitous method of passing command arguments to the function
+<tt/main()/. Note, however, that the first argument (<tt/argv[0]/) is
+a true argument and <bf/not/ the name of the module.
+
+<sect1> Authentication management
+
+<p>
+To be correctly initialized, <tt/PAM_SM_AUTH/ must be <tt/#define/'d
+prior to including <tt>&lt;security/pam_modules.h&gt;</tt>. This will
+ensure that the prototypes for static modules are properly declared.
+
+<p>
+<itemize>
+
+<item>
+<tt>PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+int argc, const char **argv);</tt>
+
+<p>
+This function performs the task of authenticating the user.
+
+<p>
+The <tt/flags/ argument can be a logically OR'd with <tt/PAM_SILENT/
+and optionally take the following value:
+
+<p><descrip>
+<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag>
+ return <tt/PAM_AUTH_ERR/ if the database of authentication
+tokens for this authentication mechanism has a <tt/NULL/ entry for the
+user. Without this flag, such a <tt/NULL/ token will lead to a success
+without the user being prompted.
+</descrip>
+
+<p>
+Besides <tt/PAM_SUCCESS/ return values that can be sent by this
+function are one of the following:
+
+<descrip>
+
+<tag><tt/PAM_AUTH_ERR/</tag>
+ The user was not authenticated
+<tag><tt/PAM_CRED_INSUFFICIENT/</tag>
+ For some reason the application does not have sufficient
+credentials to authenticate the user.
+<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag>
+ The modules were not able to access the authentication
+information. This might be due to a network or hardware failure etc.
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The supplied username is not known to the authentication
+service
+<tag><tt/PAM_MAXTRIES/</tag>
+ One or more of the authentication modules has reached its
+limit of tries authenticating the user. Do not try again.
+
+</descrip>
+
+<item>
+<tt>PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int
+argc, const char **argv);</tt>
+
+<p>
+This function performs the task of altering the credentials of the
+user with respect to the corresponding authorization
+scheme. Generally, an authentication module may have access to more
+information about a user than their authentication token. This
+function is used to append such information to the application. It
+should only be called <em/after/ the user has been authenticated.
+
+<p>
+Permitted flags, one of which, may be logically OR'd with
+<tt/PAM_SILENT/ are,
+
+<p><descrip>
+<tag><tt/PAM_ESTABLISH_CRED/</tag>
+ Set the credentials for the authentication service,
+<tag><tt/PAM_DELETE_CRED/</tag>
+ Delete the credentials associated with the authentication service,
+<tag><tt/PAM_REINITIALIZE_CRED/</tag>
+ Reinitialize the user credentials, and
+<tag><tt/PAM_REFRESH_CRED/</tag>
+ Extend the lifetime of the user credentials.
+</descrip>
+
+<p>
+Besides <tt/PAM_SUCCESS/, the module may return one of the following
+errors:
+
+<p><descrip>
+<tag><tt/PAM_CRED_UNAVAIL/</tag>
+ This module cannot retrieve the user's credentials.
+<tag><tt/PAM_CRED_EXPIRED/</tag>
+ The user's credentials have expired.
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The user is not known to this authentication module.
+<tag><tt/PAM_CRED_ERR/</tag>
+ This module was unable to set the credentials of the user.
+</descrip>
+
+</itemize>
+
+<sect1> Account management
+
+<p>
+To be correctly initialized, <tt/PAM_SM_ACCOUNT/ must be
+<tt/#define/'d prior to including <tt>&lt;security/pam_modules.h&gt;</tt>.
+This will ensure that the prototype for a static module is properly
+declared.
+
+<p>
+<itemize>
+
+<item>
+<tt>PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int
+argc, const char **argv);</tt>
+
+<p>
+This function performs the task of establishing whether the user is
+permitted to gain access at this time. It should be understood that
+the user has previously been validated by an authentication
+module. This function checks for other things. Such things might be:
+the time of day or the date, the terminal line, remote
+hostname, etc. .
+
+<p>
+This function may also determine things like the expiration on
+passwords, and respond that the user change it before continuing.
+
+<p>
+Valid flags, which may be logically OR'd with <tt/PAM_SILENT/, are the
+same as those applicable to the <tt/flags/ argument of
+<tt/pam_sm_authenticate/.
+
+<p>
+This function may return one of the following errors,
+
+<descrip>
+
+<tag><tt/PAM_ACCT_EXPIRED/</tag>
+ The user is no longer permitted access to the system.
+<tag><tt/PAM_AUTH_ERR/</tag>
+ There was an authentication error.
+<tag><tt/PAM_AUTHTOKEN_REQD/</tag>
+ The user's authentication token has expired. Before calling
+this function again the application will arrange for a new one to be
+given. This will likely result in a call to <tt/pam_sm_chauthtok()/.
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The user is not known to the module's account management
+component.
+
+</descrip>
+
+</itemize>
+
+<sect1> Session management
+
+<p>
+To be correctly initialized, <tt/PAM_SM_SESSION/ must be
+<tt/#define/'d prior to including
+<tt>&lt;security/pam_modules.h&gt;</tt>. This will ensure that the
+prototypes for static modules are properly declared.
+
+<p>
+The following two functions are defined to handle the
+initialization/termination of a session. For example, at the beginning
+of a session the module may wish to log a message with the system
+regarding the user. Similarly, at the end of the session the module
+would inform the system that the user's session has ended.
+
+<p>
+It should be possible for sessions to be opened by one application and
+closed by another. This either requires that the module uses only
+information obtained from <tt/pam_get_item()/, or that information
+regarding the session is stored in some way by the operating system
+(in a file for example).
+
+<p>
+<itemize>
+
+<item>
+<tt>PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int
+argc, const char **argv);</tt>
+
+<p>
+This function is called to commence a session. The only valid, but
+optional, flag is <tt/PAM_SILENT/.
+
+<p>
+As a return value, <tt/PAM_SUCCESS/ signals success and
+<tt/PAM_SESSION_ERR/ failure.
+
+<item>
+<tt>PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int
+argc, const char **argv);</tt>
+
+<p>
+This function is called to terminate a session. The only valid, but
+optional, flag is <tt/PAM_SILENT/.
+
+<p>
+As a return value, <tt/PAM_SUCCESS/ signals success and
+<tt/PAM_SESSION_ERR/ failure.
+
+</itemize>
+
+<sect1> Password management
+
+<p>
+To be correctly initialized, <tt/PAM_SM_PASSWORD/ must be
+<tt/#define/'d prior to including <tt>&lt;security/pam_modules.h&gt;</tt>.
+This will ensure that the prototype for a static module is properly
+declared.
+
+<p>
+<itemize>
+
+<item>
+<tt>PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int
+argc, const char **argv);</tt>
+
+<p>
+This function is used to (re-)set the authentication token of the
+user. A valid flag, which may be logically OR'd with <tt/PAM_SILENT/,
+can be built from the following list,
+
+<descrip>
+<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag>
+ This argument indicates to the module that the users
+authentication token (password) should only be changed if it has
+expired. This flag is optional and <em/must/ be combined with one of
+the following two flags. Note, however, the following two options are
+<em/mutually exclusive/.
+
+<tag><tt/PAM_PRELIM_CHECK/</tag>
+ This indicates that the modules are being probed as to their
+ready status for altering the user's authentication token. If the
+module requires access to another system over some network it should
+attempt to verify it can connect to this system on receiving this
+flag. If a module cannot establish it is ready to update the user's
+authentication token it should return <tt/PAM_TRY_AGAIN/, this
+information will be passed back to the application.
+
+<tag><tt/PAM_UPDATE_AUTHTOK/</tag>
+ This informs the module that this is the call it should change
+the authorization tokens. If the flag is logically OR'd with
+<tt/PAM_CHANGE_EXPIRED_AUTHTOK/, the token is only changed if it has
+actually expired.
+
+</descrip>
+
+<p>
+Note, the <bf/Linux-PAM/ library calls this function twice in
+succession. The first time with <tt/PAM_PRELIM_CHECK/ and then, if the
+module does not return <tt/PAM_TRY_AGAIN/, subsequently with
+<tt/PAM_UPDATE_AUTHTOK/. It is only on the second call that the
+authorization token is (possibly) changed.
+
+<p>
+<tt/PAM_SUCCESS/ is the only successful return value, valid
+error-returns are:
+
+<descrip>
+<tag><tt/PAM_AUTHTOK_ERR/</tag>
+ The module was unable to obtain the new authentication token.
+
+<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag>
+ The module was unable to obtain the old authentication token.
+
+<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag>
+ Cannot change the authentication token since it is currently
+locked.
+
+<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag>
+ Authentication token aging has been disabled.
+
+<tag><tt/PAM_PERM_DENIED/</tag>
+ Permission denied.
+
+<tag><tt/PAM_TRY_AGAIN/</tag>
+ Preliminary check was unsuccessful. Signals an immediate return
+to the application is desired.
+
+<tag><tt/PAM_USER_UNKNOWN/</tag>
+ The user is not known to the authentication token changing
+service.
+
+</descrip>
+
+</itemize>
+
+<sect>Generic optional arguments
+
+<p>
+Here we list the generic arguments that all modules can expect to
+be passed. They are not mandatory, and their absence should be
+accepted without comment by the module.
+
+<p>
+<descrip>
+<tag><tt/debug/</tag>
+
+Use the <tt/syslog(3)/ call to log debugging information to the system
+log files.
+
+<tag><tt/no_warn/</tag>
+
+Instruct module to not give warning messages to the application.
+
+<tag><tt/use_first_pass/</tag>
+
+The module should not prompt the user for a password. Instead, it
+should obtain the previously typed password (by a call to
+<tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ item), and use that. If
+that doesn't work, then the user will not be authenticated. (This
+option is intended for <tt/auth/ and <tt/passwd/ modules only).
+
+<tag><tt/try_first_pass/</tag>
+
+The module should attempt authentication with the previously typed
+password (by a call to <tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/
+item). If that doesn't work, then the user is prompted for a
+password. (This option is intended for <tt/auth/ modules only).
+
+<tag><tt/use_mapped_pass/</tag>
+
+<bf/WARNING:/ coding this functionality may cause the module writer to
+break <em/local/ encryption laws. For example, in the U.S. there are
+restrictions on the export computer code that is capable of strong
+encryption. It has not been established whether this option is
+affected by this law, but one might reasonably assume that it does
+until told otherwise. For this reason, this option is not supported
+by any of the modules distributed with <bf/Linux-PAM/.
+
+The intended function of this argument, however, is that the module
+should take the existing authentication token from a previously
+invoked module and use it as a key to retrieve the authentication
+token for this module. For example, the module might create a strong
+hash of the <tt/PAM_AUTHTOK/ item (established by a previously
+executed module). Then, with logical-exclusive-or, use the result as a
+<em/key/ to safely store/retrieve the authentication token for this
+module in/from a local file <em/etc/. .
+
+</descrip>
+
+<sect>Programming notes
+
+<p>
+Here we collect some pointers for the module writer to bear in mind
+when writing/developing a <bf/Linux-PAM/ compatible module.
+
+<sect1>Security issues for module creation
+
+<sect2>Sufficient resources
+
+<p>
+Care should be taken to ensure that the proper execution of a module
+is not compromised by a lack of system resources. If a module is
+unable to open sufficient files to perform its task, it should fail
+gracefully, or request additional resources. Specifically, the
+quantities manipulated by the <tt/setrlimit(2)/ family of commands
+should be taken into consideration.
+
+<sect2>Who's who?
+
+<p>
+Generally, the module may wish to establish the identity of the user
+requesting a service. This may not be the same as the username
+returned by <tt/pam_get_user()/. Indeed, that is only going to be the
+name of the user under whose identity the service will be given. This
+is not necessarily the user that requests the service.
+
+<p>
+In other words, user X runs a program that is setuid-Y, it grants the
+user to have the permissions of Z. A specific example of this sort of
+service request is the <em/su/ program: user <tt/joe/ executes
+<em/su/ to become the user <em/jane/. In this situation X=<tt/joe/,
+Y=<tt/root/ and Z=<tt/jane/. Clearly, it is important that the module
+does not confuse these different users and grant an inappropriate
+level of privilege.
+
+<p>
+The following is the convention to be adhered to when juggling
+user-identities.
+
+<p>
+<itemize>
+<item>X, the identity of the user invoking the service request.
+This is the user identifier; returned by the function <tt/getuid(2)/.
+
+<item>Y, the privileged identity of the application used to grant the
+requested service. This is the <em/effective/ user identifier;
+returned by the function <tt/geteuid(2)/.
+
+<item>Z, the user under whose identity the service will be granted.
+This is the username returned by <tt/pam_get_user(2)/ and also stored
+in the <bf/Linux-PAM/ item, <tt/PAM_USER/.
+
+<item><bf/Linux-PAM/ has a place for an additional user identity that
+a module may care to make use of. This is the <tt/PAM_RUSER/ item.
+Generally, network sensitive modules/applications may wish to set/read
+this item to establish the identity of the user requesting a service
+from a remote location.
+
+</itemize>
+
+<p>
+Note, if a module wishes to modify the identity of either the <tt/uid/
+or <tt/euid/ of the running process, it should take care to restore
+the original values prior to returning control to the <bf/Linux-PAM/
+library.
+
+<sect2>Using the conversation function
+<p>
+Prior to calling the conversation function, the module should reset
+the contents of the pointer that will return the applications
+response. This is a good idea since the application may fail to fill
+the pointer and the module should be in a position to notice!
+
+<p>
+The module should be prepared for a failure from the conversation. The
+generic error would be <tt/PAM_CONV_ERR/, but anything other than
+<tt/PAM_SUCCESS/ should be treated as indicating failure.
+
+<sect2>Authentication tokens
+
+<p>
+To ensure that the authentication tokens are not left lying around the
+items, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/, are not available to
+the application: they are defined in
+<tt>&lt;security/pam_modules.h&gt;</tt>. This is ostensibly for
+security reasons, but a maliciously programmed application will always
+have access to all memory of the process, so it is only superficially
+enforced. As a general rule the module should overwrite
+authentication tokens as soon as they are no longer needed.
+Especially before <tt/free()/'ing them. The <bf/Linux-PAM/ library is
+required to do this when either of these authentication token items
+are (re)set.
+
+<p>
+Not to dwell too little on this concern; should the module store the
+authentication tokens either as (automatic) function variables or
+using <tt/pam_[gs]et_data()/ the associated memory should be
+over-written explicitly before it is released. In the case of the
+latter storage mechanism, the associated <tt/cleanup()/ function
+should explicitly overwrite the <tt/*data/ before <tt/free()/'ing it:
+for example,
+
+<tscreen>
+<verb>
+/*
+ * An example cleanup() function for releasing memory that was used to
+ * store a password.
+ */
+
+int cleanup(pam_handle_t *pamh, void *data, int error_status)
+{
+ char *xx;
+
+ if ((xx = data)) {
+ while (*xx)
+ *xx++ = '\0';
+ free(data);
+ }
+ return PAM_SUCCESS;
+}
+</verb>
+</tscreen>
+
+<sect1>Use of <tt/syslog(3)/
+
+<p>
+Only rarely should error information be directed to the user. Usually,
+this is to be limited to ``<em/sorry you cannot login now/'' type
+messages. Information concerning errors in the configuration file,
+<tt>/etc/pam.conf</tt>, or due to some system failure encountered by
+the module, should be written to <tt/syslog(3)/ with
+<em/facility-type/ <tt/LOG_AUTHPRIV/.
+
+<p>
+With a few exceptions, the level of logging is, at the discretion of
+the module developer. Here is the recommended usage of different
+logging levels:
+
+<p>
+<itemize>
+
+<item>
+As a general rule, errors encountered by a module should be logged at
+the <tt/LOG_ERR/ level. However, information regarding an unrecognized
+argument, passed to a module from an entry in the
+<tt>/etc/pam.conf</tt> file, is <bf/required/ to be logged at the
+<tt/LOG_ERR/ level.
+
+<item>
+Debugging information, as activated by the <tt/debug/ argument to the
+module in <tt>/etc/pam.conf</tt>, should be logged at the
+<tt/LOG_DEBUG/ level.
+
+<item>
+If a module discovers that its personal configuration file or some
+system file it uses for information is corrupted or somehow unusable,
+it should indicate this by logging messages at level, <tt/LOG_ALERT/.
+
+<item>
+Shortages of system resources, such as a failure to manipulate a file
+or <tt/malloc()/ failures should be logged at level <tt/LOG_CRIT/.
+
+<item>
+Authentication failures, associated with an incorrectly typed password
+should be logged at level, <tt/LOG_NOTICE/.
+
+</itemize>
+
+<sect1> Modules that require system libraries
+
+<p>
+Writing a module is much like writing an application. You have to
+provide the "conventional hooks" for it to work correctly, like
+<tt>pam_sm_authenticate()</tt> etc., which would correspond to the
+<tt/main()/ function in a normal function.
+
+<p>
+Typically, the author may want to link against some standard system
+libraries. As when one compiles a normal program, this can be done for
+modules too: you simply append the <tt>-l</tt><em>XXX</em> arguments
+for the desired libraries when you create the shared module object. To
+make sure a module is linked to the <tt>lib<em>whatever</em>.so</tt>
+library when it is <tt>dlopen()</tt>ed, try:
+<tscreen>
+<verb>
+% gcc -shared -Xlinker -x -o pam_module.so pam_module.o -lwhatever
+</verb>
+</tscreen>
+
+<sect1> Added requirements for <em/statically/ loaded modules.
+
+<!--
+ Copyright (C) Michael K. Johnson 1996.
+ Last modified: AGM 1996/5/31.
+ -->
+
+<p>
+Modules may be statically linked into libpam. This should be true of
+all the modules distributed with the basic <bf/Linux-PAM/
+distribution. To be statically linked, a module needs to export
+information about the functions it contains in a manner that does not
+clash with other modules.
+
+The extra code necessary to build a static module should be delimited
+with <tt/#ifdef PAM_STATIC/ and <tt/#endif/. The static code should do
+the following:
+<itemize>
+<item> Define a single structure, <tt/struct pam_module/, called
+<tt>_pam_<it>modname</it>_modstruct</tt>, where
+<tt><it>modname</it></tt> is the name of the module <bf/as used in the
+filesystem/ but without the leading directory name (generally
+<tt>/usr/lib/security/</tt> or the suffix (generally <tt/.so/).
+
+</itemize>
+
+<p>
+As a simple example, consider the following module code which defines
+a module that can be compiled to be <em/static/ or <em/dynamic/:
+
+<p>
+<tscreen>
+<verb>
+#include <stdio.h> /* for NULL define */
+
+#define PAM_SM_PASSWORD /* the only pam_sm_... function declared */
+#include <security/pam_modules.h>
+
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+#ifdef PAM_STATIC /* for the case that this module is static */
+
+struct pam_module _pam_modname_modstruct = { /* static module data */
+ "pam_modname",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_chauthtok,
+};
+
+#endif /* end PAM_STATIC */
+</verb>
+</tscreen>
+
+<p>
+To be linked with <em/libpam/, staticly-linked modules must be built
+from within the <tt>Linux-PAM-X.YY/modules/</tt> subdirectory of the
+<bf/Linux-PAM/ source directory as part of a normal build of the
+<bf/Linux-PAM/ system.
+
+The <em/Makefile/, for the module in question, must execute the
+<tt/register_static/ shell script that is located in the
+<tt>Linux-PAM-X.YY/modules/</tt> subdirectory. This is to ensure that
+the module is properly registered with <em/libpam/.
+
+The <bf/two/ manditory arguments to <tt/register_static/ are the
+title, and the pathname of the object file containing the module's
+code. The pathname is specified relative to the
+<tt>Linux-PAM-X.YY/modules</tt> directory. The pathname may be an
+empty string---this is for the case that a single object file needs to
+register more than one <tt/struct pam_module/. In such a case, exactly
+one call to <tt/register_static/ must indicate the object file.
+
+<p>
+Here is an example; a line in the <em/Makefile/ might look like this:
+<tscreen>
+<verb>
+register:
+ifdef STATIC
+ (cd ..; ./register_static pam_modname pam_modname/pam_modname.o)
+endif
+</verb>
+</tscreen>
+
+For some further examples, see the <tt>modules</tt> subdirectory of
+the current <bf/Linux-PAM/ distribution.
+
+<p>
+<sect>An example module file
+
+<p>
+<em>
+perhaps this should point to a place in the file structure!?
+</em>
+
+<sect>Files
+
+<p><descrip>
+
+<tag><tt>/usr/lib/libpam.so.*</tt></tag>
+
+the shared library providing applications with access to
+<bf/Linux-PAM/.
+
+<tag><tt>/etc/pam.conf</tt></tag>
+
+the <bf/Linux-PAM/ configuration file.
+
+<tag><tt>/usr/lib/security/pam_*.so</tt></tag>
+
+the primary location for <bf/Linux-PAM/ dynamically loadable object
+files; the modules.
+
+</descrip>
+
+<sect>See also
+
+<p><itemize>
+<item>The <bf/Linux-PAM/ System Administrators' Guide.
+<item>The <bf/Linux-PAM/ Application Writers' Guide.
+<item>
+V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE
+AUTHENTICATION MODULES'', Open Software Foundation Request For
+Comments 86.0, October 1995.
+</itemize>
+
+<sect>Notes
+
+<p>
+I intend to put development comments here... like ``at the moment
+this isn't actually supported''. At release time what ever is in
+this section will be placed in the Bugs section below! :)
+
+<p>
+<itemize>
+<item>
+Perhaps we should keep a registry of data-names as used by
+<tt/pam_[gs]et_data()/ so there are no unintentional problems due to
+conflicts?
+
+<item>
+<tt/pam_strerror()/ should be internationalized....
+
+<item>
+There has been some debate about whether <tt/initgroups()/ should be
+in an application or in a module. It was settled by Sun who stated
+that initgroups is an action of the <em/application/. The modules are
+permitted to add additional groups, however.
+
+<item>
+Refinements/futher suggestions to <tt/syslog(3)/ usage by modules are
+needed.
+
+</itemize>
+
+<sect>Author/acknowledgments
+
+<p>
+This document was written by Andrew G. Morgan
+(<tt/morgan@transmeta.com/) with many contributions from
+<!-- insert credits here -->
+<!--
+ an sgml list of people to credit for their contributions to Linux-PAM
+ -->
+<!--
+ an sgml list of people to credit for their contributions to Linux-PAM
+ $Id: CREDITS,v 1.4 1997/04/05 06:47:26 morgan Exp morgan $
+ -->
+Peter Allgeyer,
+Tim Baverstock,
+Craig S. Bell,
+Derrick J. Brashear,
+Ben Buxton,
+Oliver Crow,
+Chris Dent,
+Marc Ewing,
+Cristian Gafton,
+Eric Hester,
+Roger Hu,
+Eric Jacksch,
+Michael K. Johnson,
+David Kinchlea,
+Nicolai Langfeldt,
+Elliot Lee,
+Al Longyear,
+Ingo Luetkebohle,
+Marek Michalkiewicz,
+Aleph One,
+Martin Pool,
+Sean Reifschneider,
+Erik Troan,
+Theodore Ts'o,
+Jeff Uphoff,
+Myles Uyema,
+Savochkin Andrey Vladimirovich,
+Ronald Wahl,
+David Wood,
+John Wilmes,
+Joseph S. D. Yao
+and
+Alex O. Yuriev.
+
+<p>
+Thanks are also due to Sun Microsystems, especially to Vipin Samar and
+Charlie Lai for their advice. At an early stage in the development of
+<bf/Linux-PAM/, Sun graciously made the documentation for their
+implementation of PAM available. This act greatly accelerated the
+development of <bf/Linux-PAM/.
+
+<sect>Bugs/omissions
+
+<p>
+Few PAM modules currently exist. Few PAM-aware applications exist.
+This document is hopelessly unfinished. Only a partial list of people is
+credited for all the good work they have done.
+
+<sect>Copyright information for this document
+
+<p>
+Copyright (c) Andrew G. Morgan 1996, 1997. All rights reserved.
+<newline>
+Email: <tt>&lt;morgan@transmeta.com&gt;</tt>
+
+<p>
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+<p>
+<itemize>
+
+<item>
+1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+<item>
+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.
+
+<item>
+3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+</itemize>
+
+<p>
+<bf/Alternatively/, this product may be distributed under the terms of
+the GNU General Public License (GPL), in which case the provisions of
+the GNU GPL are required <bf/instead of/ the above restrictions.
+(This clause is necessary due to a potential bad interaction between
+the GNU GPL and the restrictions contained in a BSD-style copyright.)
+
+<p>
+THIS SOFTWARE IS PROVIDED ``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 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.
+
+<p>
+<tt>$Id: pam_modules.sgml,v 1.19 1997/04/05 06:49:14 morgan Exp morgan $</tt>
+
+</article>
diff --git a/contrib/libpam/doc/pam_source.sgml b/contrib/libpam/doc/pam_source.sgml
new file mode 100644
index 000000000000..093998a0aad1
--- /dev/null
+++ b/contrib/libpam/doc/pam_source.sgml
@@ -0,0 +1,985 @@
+<!doctype linuxdoc system>
+
+<!--
+
+ $Id: pam_source.sgml,v 1.5 1997/04/05 06:49:14 morgan Exp morgan $
+
+ Copyright (c) Andrew G. Morgan 1996,1997. All rights reserved.
+
+Redistribution and use in source (sgml) and binary (derived) 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, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+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.
+
+ALTERNATIVELY, this product may be distributed under the terms of the
+GNU General Public License, in which case the provisions of the GNU
+GPL are required INSTEAD OF the above restrictions. (This clause is
+necessary due to a potential bad interaction between the GNU GPL and
+the restrictions contained in a BSD-style copyright.)
+
+THIS SOFTWARE IS PROVIDED ``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 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.
+
+ -->
+
+<article>
+
+<title>The Linux-PAM System Administrators' Guide
+<author>Andrew G. Morgan, <tt>morgan@linux.kernel.org</tt>
+<date>DRAFT v0.59 1998/1/7
+<abstract>
+This manual documents what a system-administrator needs to know about
+the <bf>Linux-PAM</bf> library. It covers the correct syntax of the
+PAM configuration file and discusses strategies for maintaining a
+secure system.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Introduction
+
+<p><bf/Linux-PAM/ (Pluggable Authentication Modules for Linux) is a
+suite of shared libraries that enable the local system administrator
+to choose how applications authenticate users.
+
+<p>In other words, without (rewriting and) recompiling a PAM-aware
+application, it is possible to switch between the authentication
+mechanism(s) it uses. Indeed, one may entirely upgrade the local
+authentication system without touching the applications themselves.
+
+<p>Historically an application that has required a given user to be
+authenticated, has had to be compiled to use a specific authentication
+mechanism. For example, in the case of traditional UN*X systems, the
+identity of the user is verified by the user entering a correct
+password. This password, after being prefixed by a two character
+``salt'', is encrypted (with crypt(3)). The user is then authenticated
+if this encrypted password is identical to the second field of the
+user's entry in the system password database (the <tt>/etc/passwd</tt>
+file). On such systems, most if not all forms of privileges are
+granted based on this single authentication scheme. Privilege comes in
+the form of a personal user-identifier (<tt/uid/) and membership of
+various groups. Services and applications are available based on the
+personal and group identity of the user. Traditionally, group
+membership has been assigned based on entries in the
+<tt>/etc/group</tt> file.
+
+<p>
+Unfortunately, increases in the speed of computers and the
+widespread introduction of network based computing, have made once
+secure authentication mechanisms, such as this, vulnerable to
+attack. In the light of such realities, new methods of authentication
+are continuously being developed.
+
+<p>
+It is the purpose of the <bf/Linux-PAM/ project to separate the
+development of privilege granting software from the development of
+secure and appropriate authentication schemes. This is accomplished
+by providing a library of functions that an application may use to
+request that a user be authenticated. This PAM library is configured
+locally with a system file, <tt>/etc/pam.conf</tt> (or a series of
+configuration files located in <tt>/etc/pam.d/</tt>) to authenticate a
+user request via the locally available authentication modules. The
+modules themselves will usually be located in the directory
+<tt>/usr/lib/security</tt> and take the form of dynamically loadable
+object files (see <tt/dlopen(3)/).
+
+<sect>Some comments on the text<label id="text-conventions">
+
+<p>
+Before proceeding to read the rest of this document, it should be
+noted that the text assumes that certain files are placed in certain
+directories. Where they have been specified, the conventions we adopt
+here for locating these files are those of the relevant RFC (RFC-86.0,
+see <ref id="see-also-sec" name="bibliography">). If you are using a
+distribution of Linux (or some other operating system) that supports
+PAM but chooses to distribute these files in a diferent way (Red Hat
+is one such distribution), you should be careful when copying examples
+directly from the text.
+
+<p>
+As an example of the above, where it is explicit, the text assumes
+that PAM loadable object files (the <em/modules/) are to be located in
+the following directory: <tt>/usr/lib/security/</tt>. However, Red Hat
+Linux, in agreement with the Linux File System Standard (the FSSTND),
+places these files in <tt>/lib/security</tt>. Please be careful to
+perform the necessary transcription when using the examples from the
+text.
+
+<sect>Overview<label id="overview-section">
+
+<p>
+For the uninitiated, we begin by considering an example. We take an
+application that grants some service to users; <em/login/ is one such
+program. <em/Login/ does two things, it first establishes that the
+requesting user is whom they claim to be and second provides them with
+the requested service: in the case of <em/login/ the service is a
+command shell (<em>bash, tcsh, zsh, etc.</em>) running with the
+identity of the user.
+
+<p>
+Traditinally, the former step is achieved by the <em/login/
+application prompting the user for a password and then verifying that
+it agrees with that located on the system; hence verifying that the
+so far as the system is concerned the user is who they claim to be.
+This is the task that is delegated to <bf/Linux-PAM/.
+
+<p>
+From the perspective of the application programmer (in this case the
+person that wrote the <em/login/ application), <bf/Linux-PAM/ takes
+care of this authentication task -- verifying the identity of the user.
+
+<p>
+The flexibility of <bf/Linux-PAM/ is that <em/you/, the system
+administrator, have the freedom to stipulate which authentication
+scheme is to be used. You have the freedom to set the scheme for
+any/all PAM-aware applications on your Linux system. That is, you can
+authenticate from anything as naive as <em/simple trust/
+(<tt/pam_permit/) to something as paranoid as a combination of a
+retinal scan, a voice print and a one-time password!
+
+<p>
+To illustrate the flexibility you face, consider the following
+situation: a system administrator (parent) wishes to improve the
+mathematical ability of her users (children). She can configure their
+favorite ``Shoot 'em up game'' (PAM-aware of course) to authenticate
+them with a request for the product of a couple of random numbers less
+than 12. It is clear that if the game is any good they will soon learn
+their <em/multiplication tables/. As they mature, the authentication
+can be upgraded to include (long) division!
+
+<p>
+<bf/Linux-PAM/ deals with four separate types of (management)
+task. These are: <em/authentication management/; <em/account
+management/; <em/session management/; and <em/password management/.
+The association of the preferred management scheme with the behavior
+of an application is made with entries in the relevant <bf/Linux-PAM/
+configuration file. The management functions are performed by
+<em/modules/ specified in the configuration file. The syntax for this
+file is discussed in the section <ref id="configuration"
+name="below">.
+
+<p>
+Here is a figure that describes the overall organization of
+<bf/Linux-PAM/.
+<tscreen>
+<verb>
+ +----------------+
+ | application: X |
+ +----------------+ / +----------+ +================+
+ | authentication-[---->--\--] Linux- |--<--| PAM config file|
+ | + [----<--/--] PAM | |================|
+ |[conversation()][--+ \ | | | X auth .. a.so |
+ +----------------+ | / +-n--n-----+ | X auth .. b.so |
+ | | | __| | | _____/
+ | service user | A | | |____,-----'
+ | | | V A
+ +----------------+ +------|-----|---------+ -----+------+
+ +---u-----u----+ | | |
+ | auth.... |--[ a ]--[ b ]--[ c ]
+ +--------------+
+ | acct.... |--[ b ]--[ d ]
+ +--------------+
+ | password |--[ b ]--[ c ]
+ +--------------+
+ | session |--[ e ]--[ c ]
+ +--------------+
+</verb>
+</tscreen>
+By way of explanation, the left of the figure represents the
+application; application X. Such an application interfaces with the
+<bf/Linux-PAM/ library and knows none of the specifics of its
+configured authentication method. The <bf/Linux-PAM/ library (in the
+center) consults the contents of the PAM configuration file and loads
+the modules that are appropriate for application-X. These modules fall
+into one of four management groups (lower-center) and are stacked in
+the order they appear in the configuaration file. These modules, when
+called by <bf/Linux-PAM/, perform the various authentication tasks for
+the application. Textual information, required from/or offered to the
+user, can be exchanged through the use of the application-supplied
+<em/conversation/ function.
+
+<sect>The Linux-PAM configuration file
+<label id="configuration">
+
+<p>
+<bf/Linux-PAM/ is designed to provide the system administrator with a
+great deal of flexibility in configuring the privilege granting
+applications of their system. The local configuration of those aspects
+of system security controlled by <tt/Linux-PAM/ is contained in one of
+two places: either the single system file, <tt>/etc/pam.conf</tt>; or
+the <tt>/etc/pam.d/</tt> directory. In this section we discuss the
+correct syntax of and generic options respected by entries to these
+files.
+
+<sect1>Configuration file syntax
+
+<p>
+The reader should note that the <bf/Linux-PAM/ specific tokens in this
+file are case <em/insensitive/. The module paths, however, are case
+sensitive since they indicate a file's <em/name/ and reflect the case
+dependence of typical Linux file-systems. The case-sensitivity of the
+arguments to any given module is defined for each module in turn.
+
+<p>
+In addition to the lines described below, there are two <em/special/
+characters provided for the convenience of the system administrator:
+comments are preceded by a `<tt/&num;/' and extend to the
+next end-of-line; also, module specification lines may be extended
+with a `<tt/&bsol;/' escaped newline.
+
+<p>
+A general configuration line of the <tt>/etc/pam.conf</tt> file has
+the following form:
+<tscreen>
+<verb>
+service-name module-type control-flag module-path arguments
+</verb>
+</tscreen>
+Below, we explain the meaning of each of these tokens. The second (and
+more recently adopted) way of configuring <bf/Linux-PAM/ is via the
+contents of the <tt>/etc/pam.d/</tt> directory. Once we have explained
+the meaning of the above tokens, we will describe this method.
+
+<p>
+<descrip>
+<tag><tt/service-name/</tag>
+The name of the service associated with this entry. Frequently the
+service name is the conventional name of the given application. For
+example, `<tt/ftpd/', `<tt/rlogind/' and `<tt/su/', <em/etc./ .
+
+<p>
+There is a special <tt/service-name/, reserved for defining a default
+authentication mechanism. It has the name `<tt/OTHER/' and may be
+specified in either lower or upper case characters. Note, when there
+is a module specified for a named service, the `<tt/OTHER/' entries
+are ignored.
+
+<tag><tt/module-type/</tag>
+One of (currently) four types of module. The four types are as
+follows:
+<itemize>
+<item> <tt/auth/; this module type provides two aspects of
+authenticating the user. Firstly, it establishes that the user is who
+they claim to be, by instructing the application to prompt the user
+for a password or other means of identification. Secondly, the module
+can grant <tt/group/ membership (independently of the
+<tt>/etc/groups</tt> file discussed above) or other privileges through
+its <em/credential/ granting properties.
+
+<item> <tt/account/; this module performs non-authentication based
+account management. It is typically used to restrict/permit access to
+a service based on the time of day, currently available system
+resources (maximum number of users) or perhaps the location of the
+applicant user---`<tt/root/' login only on the console.
+
+<item> <tt/session/; primarily, this module is associated with doing
+things that need to be done for the user before/after they can be
+given service. Such things include the logging of information
+concerning the opening/closing of some data exchange with a user,
+mounting directories, etc. .
+
+<item> <tt/password/; this last module type is required for updating the
+authentication token associated with the user. Typically, there is one
+module for each `challenge/response' based authentication (<tt/auth/)
+module-type.
+
+</itemize>
+
+<tag><tt/control-flag/</tag>
+
+The control-flag is used to indicate how the PAM library will react to
+the success or failure of the module it is associated with. Since
+modules can be <em/stacked/ (modules of the same type execute in
+series, one after another), the control-flags determine the relative
+importance of each module. The application is not made aware of the
+individual success or failure of modules listed in the
+`<tt>/etc/pam.conf</tt>' file. Instead, it receives a summary
+<em/success/ or <em/fail/ response from the <bf/Linux-PAM/ library.
+The order of execution of these modules is that of the entries in the
+<tt>/etc/pam.conf</tt> file; earlier entries are executed before later
+ones. As of Linux-PAM v0.60, this <em/control-flag/ can be defined
+with one of two syntaxes.
+
+<p>
+The simpler (and historical) syntax for the control-flag is a single
+keyword defined to indicate the severity of concern associated with
+the success or failure of a specific module. There are four such
+keywords: <tt/required/, <tt/requisite/, <tt/sufficient/ and
+<tt/optional/.
+
+<p>
+The Linux-PAM library interprets these keywords in the following
+manner:
+
+<itemize>
+
+<item> <tt/required/; this indicates that the success of the module is
+required for the <tt/module-type/ facility to succeed. Failure of this
+module will not be apparent to the user until all of the remaining
+modules (of the same <tt/module-type/) have been executed.
+
+<item> <tt/requisite/; like <tt/required/, however, in the case that
+such a module returns a failure, control is directly returned to the
+application. The return value is that associated with the <em/first/
+<tt/required/ or <tt/requisite/ module to fail. Note, this flag can be
+used to protect against the possibility of a user getting the
+opportunity to enter a password over an unsafe medium. It is
+conceivable that such behavior might inform an attacker of valid
+accounts on a system. This possibility should be weighed against the
+not insignificant concerns of exposing a sensitive password in a
+hostile environment.
+
+<item> <tt/sufficient/; the success of this module is deemed
+`<em/sufficient/' to satisfy the <bf/Linux-PAM/ library that this
+module-type has succeeded in its purpose. In the event that no
+previous <tt/required/ module has failed, no more `<em/stacked/'
+modules of this type are invoked. (Note, in this case subsequent
+<tt/required/ modules are <bf/not/ invoked.). A failure of this module
+is not deemed as fatal to satisfying the application that this
+<tt/module-type/ has succeeded.
+
+<item> <tt/optional/; as its name suggests, this <tt/control-flag/
+marks the module as not being critical to the success or failure of
+the user's application for service. However, in the absence of any
+successes of previous or subsequent stacked modules this module will
+determine the nature of the response to the application.
+
+</itemize>
+
+<p>
+The more elaborate (newer) syntax is much more specific and gives the
+administrator a great deal of control over how the user is
+authenticated. This form of the control flag is delimeted with square
+brackets and consists of a series of <tt/value=action/ tokens:
+<tscreen>
+<verb>
+ [value1=action1 value2=action2 ...]
+</verb>
+</tscreen>
+
+<p>
+Here, <tt/valueI/ is one of the following <em/return values/:
+<tt/success/; <tt/open_err/; <tt/symbol_err/; <tt/service_err/;
+<tt/system_err/; <tt/buf_err/; <tt/perm_denied/; <tt/auth_err/;
+<tt/cred_insufficient/; <tt/authinfo_unavail/; <tt/user_unknown/;
+<tt/maxtries/; <tt/new_authtok_reqd/; <tt/acct_expired/;
+<tt/session_err/; <tt/cred_unavail/; <tt/cred_expired/; <tt/cred_err/;
+<tt/no_module_data/; <tt/conv_err/; <tt/authtok_err/;
+<tt/authtok_recover_err/; <tt/authtok_lock_busy/;
+<tt/authtok_disable_aging/; <tt/try_again/; <tt/ignore/; <tt/abort/;
+<tt/authtok_expired/; <tt/module_unknown/; <tt/bad_item/; and
+<tt/default/. The last of these (<tt/default/) can be used to set the
+action for those return values that are not set explicitly.
+
+<p>
+The <tt/actionI/ can be a positive integer or one of the following
+tokens: <tt/ignore/; <tt/ok/; <tt/done/; <tt/bad/; <tt/die/; and
+<tt/reset/. A positive integer, <tt/J/, when specified as the action
+can be used to indicate that the next <em/J/ modules of the current
+type will be skipped. In this way, the administrator can develop a
+moderately sophisticated stack of modules with a number of different
+paths of execution. Which path is taken can be determined by the
+reactions of individual modules.
+
+<p>
+<bf>Note, at time of writing, this newer syntax is so new that I don't
+want to write too much about it. Please play with this. Report all
+the bugs and make suggestions for new actions (etc.).</bf>
+
+<tag> <tt/module-path/</tag>
+
+The path-name of the dynamically loadable object file; <em/the
+pluggable module/ itself. If the first character of the module path is
+`<tt>/</tt>', it is assumed to be a complete path. If this is not the
+case, the given module path is appended to the default module path:
+<tt>/usr/lib/security</tt> (but see the notes <ref
+id="text-conventions" name="above">).
+
+<tag> <tt/args/</tag>
+
+The <tt/args/ are a list of tokens that are passed to the module when
+it is invoked. Much like arguments to a typical Linux shell command.
+Generally, valid arguments are optional and are specific to any given
+module. Invalid arguments are ignored by a module, however, when
+encountering an invalid argument, the module is required to write an
+error to <tt/syslog(3)/. For a list of <em/generic/ options see the
+next section.
+
+</descrip>
+
+<p>
+Any line in (one of) the confiuration file(s), that is not formatted
+correctly, will generally tend (erring on the side of caution) to make
+the authentication process fail. A corresponding error is written to
+the system log files with a call to <tt/syslog(3)/.
+
+<sect1>Directory based configuration
+
+<p>
+More flexible than the single configuration file, as of version 0.56,
+it is possible to configure <tt>libpam</tt> via the contents of the
+<tt>/etc/pam.d/</tt> directory. In this case the directory is filled
+with files each of which has a filename equal to a service-name (in
+lower-case): it is the personal configuration file for the named
+service.
+
+<p>
+<bf/Linux-PAM/ can be compiled in one of two modes. The preferred
+mode uses either <tt>/etc/pam.d/</tt> or <tt>/etc/pam.conf</tt>
+configuration but not both. That is to say, if there is a
+<tt>/etc/pam.d/</tt> directory then libpam only uses the files
+contained in this directory. However, in the absence of the
+<tt>/etc/pam.d/</tt> directory the <tt>/etc/pam.conf</tt> file is
+used. The other mode (and the one currently supported by Red Hat 4.2)
+is to use both <tt>/etc/pam.d/</tt> and <tt>/etc/pam.conf</tt> in
+sequence. In this mode, entries in <tt>/etc/pam.d/</tt> override
+those of <tt>/etc/pam.conf</tt>.
+
+The syntax of each file in <tt>/etc/pam.d/</tt> is similar to that of
+the <tt>/etc/pam.conf</tt> file and is made up of lines of the
+following form:
+<tscreen>
+<verb>
+module-type control-flag module-path arguments
+</verb>
+</tscreen>
+The only difference being that the <tt>service-name</tt> is not
+present. The service-name is of course the name of the given
+configuration file. For example, <tt>/etc/pam.d/login</tt> contains
+the configuration for the <em>login</em> service.
+
+<p>
+This method of configuration has a number of advantages over the
+single file approach. We list them here to assist the reader in
+deciding which scheme to adopt:
+
+<p>
+<itemize>
+
+<item>A lower chance of misconfiguring an application. There is one
+less field to mis-type when editing the configuration files by hand.
+
+<item>Easier to maintain. One application may be reconfigured without
+risk of interfering with other applications on the system.
+
+<item>It is possible to symbolically link different services
+configuration files to a single file. This makes it easier to keep the
+system policy for access consistent across different applications.
+(It should be noted, to conserve space, it is equally possible to
+<em>hard</em> link a number of configuration files. However, care
+should be taken when administering this arrangement as editing a hard
+linked file is likely to break the link.)
+
+<item>A potential for quicker configuration file parsing. Only the
+relevant entries are parsed when a service gets bound to its modules.
+
+<item>It is possible to limit read access to individual <bf/Linux-PAM/
+configuration files using the file protections of the filesystem.
+
+<item>Package management becomes simpler. Every time a new
+application is installed, it can be accompanied by an
+<tt>/etc/pam.d/</tt><em>xxxxxx</em> file.
+
+</itemize>
+
+<sect1>Generic optional arguments
+
+<p>
+The following are optional arguments which are likely to be understood
+by any module. Arguments (including these) are in general
+<em/optional/.
+
+<p>
+<descrip>
+<tag><tt/debug/</tag>
+
+Use the <tt/syslog(3)/ call to log debugging information to the system
+log files.
+
+<tag> <tt/no_warn/</tag>
+
+Instruct module to not give warning messages to the application.
+
+<tag> <tt/use_first_pass/</tag>
+
+The module should not prompt the user for a password. Instead, it
+should obtain the previously typed password (from the preceding
+<tt/auth/ module), and use that. If that doesn't work, then the user
+will not be authenticated. (This option is intended for <tt/auth/
+and <tt/password/ modules only).
+
+<tag> <tt/try_first_pass/</tag>
+
+The module should attempt authentication with the previously typed
+password (from the preceding <tt/auth/ module). If that doesn't work,
+then the user is prompted for a password. (This option is intended for
+<tt/auth/ modules only).
+
+<tag> <tt/use_mapped_pass/</tag>
+
+This argument is not currently supported by any of the modules in the
+<bf/Linux-PAM/ distribution because of possible consequences
+associated with U.S. encryption exporting restrictions. Within the
+U.S., module developers are, of course, free to implement it (as are
+developers in other countries). For compatibility reasons we describe
+its use as suggested in the <bf/DCE-RFC 86.0/, see section <ref
+id="see-also-sec" name="bibliography"> for a pointer to this document.
+
+<p>
+The <tt/use_mapped_pass/ argument instructs the module to take the
+clear text authentication token entered by a previous module (that
+requests such a token) and use it to generate an encryption/decryption
+key with which to safely store/retrieve the authentication token
+required for this module. In this way the user can enter a single
+authentication token and be quietly authenticated by a number of
+stacked modules. Obviously a convenient feature that necessarily
+requires some reliably strong encryption to make it secure.
+This argument is intended for the <tt/auth/ and <tt/password/ module
+types only.
+
+</descrip>
+
+<sect1>Example configuration file entries
+
+<p>
+In this section, we give some examples of entries that can be present
+in the <bf/Linux-PAM/ configuration file. As a first attempt at
+configuring your system you could do worse than to implement these.
+
+<sect2>Default policy
+
+<p>
+If a system is to be considered secure, it had better have a
+reasonably secure `<tt/OTHER/' entry. The following is a paranoid
+setting (which is not a bad place to start!):
+<tscreen>
+<verb>
+#
+# default; deny access
+#
+OTHER auth required /usr/lib/security/pam_deny.so
+OTHER account required /usr/lib/security/pam_deny.so
+OTHER password required /usr/lib/security/pam_deny.so
+OTHER session required /usr/lib/security/pam_deny.so
+</verb>
+</tscreen>
+Whilst fundamentally a secure default, this is not very sympathetic to
+a misconfigured system. For example, such a system is vulnerable to
+locking everyone out should the rest of the file become badly written.
+
+<p>
+The module <tt/pam_deny/ (documented in a later section) is not very
+sophisticated. For example, it logs no information when it is invoked
+so unless the users of a system contact the administrator when failing
+to execute a service application, the administrator may go for a long
+while in ignorance of the fact that his system is misconfigured.
+
+<p>
+The addition of the following line before those in the above example
+would provide a suitable warning to the administrator.
+<tscreen>
+<verb>
+#
+# default; wake up! This application is not configured
+#
+OTHER auth required /usr/lib/security/pam_warn.so
+OTHER password required /usr/lib/security/pam_warn.so
+</verb>
+</tscreen>
+Having two ``<tt/OTHER auth/'' lines is an example of stacking.
+
+<p>
+On a system that uses the <tt>/etc/pam.d/</tt> configuration, the
+corresponding default setup would be achieved with the following file:
+<tscreen>
+<verb>
+#
+# default configuration: /etc/pam.d/other
+#
+auth required /usr/lib/security/pam_warn.so
+auth required /usr/lib/security/pam_deny.so
+account required /usr/lib/security/pam_deny.so
+password required /usr/lib/security/pam_warn.so
+password required /usr/lib/security/pam_deny.so
+session required /usr/lib/security/pam_deny.so
+</verb>
+</tscreen>
+This is the only explicit example we give for an <tt>/etc/pam.d/</tt>
+file. In general, it should be clear how to transpose the remaining
+examples to this configuration scheme.
+
+<p>
+On a less sensitive computer, one on which the system administrator
+wishes to remain ignorant of much of the power of <tt/Linux-PAM/, the
+following selection of lines (in <tt>/etc/pam.conf</tt>) is likely to
+mimic the historically familiar Linux setup.
+<tscreen>
+<verb>
+#
+# default; standard UNIX access
+#
+OTHER auth required /usr/lib/security/pam_unix_auth.so
+OTHER account required /usr/lib/security/pam_unix_acct.so
+OTHER password required /usr/lib/security/pam_unix_passwd.so
+OTHER session required /usr/lib/security/pam_unix_session.so
+</verb>
+</tscreen>
+In general this will provide a starting place for most applications.
+Unfortunately, most is not all. One application that might require
+additional lines is <em/ftpd/ if you wish to enable
+<em/anonymous-ftp/.
+
+<p>
+To enable anonymous-ftp, the following lines might be used to replace
+the default (<tt/OTHER/) ones. (<bf/*WARNING*/ as of 1996/12/28 this
+does not work correctly with any ftpd. Consequently, this description
+may be subject to change or the application will be fixed.)
+<tscreen>
+<verb>
+#
+# ftpd; add ftp-specifics. These lines enable anonymous ftp over
+# standard UNIX access (the listfile entry blocks access to
+# users listed in /etc/ftpusers)
+#
+ftpd auth sufficient /usr/lib/security/pam_ftp.so
+ftpd auth required /usr/lib/security/pam_unix_auth.so use_first_pass
+ftpd auth required /usr/lib/security/pam_listfile.so \
+ onerr=succeed item=user sense=deny file=/etc/ftpusers
+</verb>
+</tscreen>
+Note, the second line is necessary since the default entries are
+ignored by a service application (here <em/ftpd/) if there are
+<em/any/ entries in <tt>/etc/pam.conf</tt> for that specified service.
+Again, this is an example of authentication module stacking. Note the
+use of the <tt/sufficient/ control-flag. It says that ``if this module
+authenticates the user, ignore the subsequent <tt/auth/
+modules''. Also note the use of the ``<tt/use_first_pass/''
+module-argument, this instructs the UNIX authentication module that it
+is not to prompt for a password but rely one already having been
+obtained by the ftp module.
+
+<p>
+The standard UNIX modules, used above, are strongly tied to using the
+default `<tt/libc/' user database functions (see for example, <tt/man
+getpwent/). It is the opinion of the author that these functions are
+not sufficently flexible to make full use of the power of
+<bf/Linux-PAM/. For this reason, and as a small plug, I mention in
+passing that there is a pluggable replacement for the <tt/pam_unix_../
+modules; <tt/pam_pwdb/. See the section below for a more complete
+description.
+
+
+<sect>Security issues of Linux-PAM
+
+<p>
+This section will discuss good practices for using Linux-PAM in a
+secure manner. <em>It is currently sadly lacking...suggestions are
+welcome!</em>
+
+<sect1>If something goes wrong
+
+<p>
+<bf/Linux-PAM/ has the potential to seriously change the security of
+your system. You can choose to have no security or absolute security
+(no access permitted). In general, <bf/Linux-PAM/ errs towards the
+latter. Any number of configuration errors can dissable access to
+your system partially, or completely.
+
+<p>
+The most dramatic problem that is likely to be encountered when
+configuring <bf/Linux-PAM/ is that of <em>deleting</em> the
+configuration file(s): <tt>/etc/pam.d/*</tt> and/or
+<tt>/etc/pam.conf</tt>. This will lock you out of your own system!
+
+<p>
+To recover, your best bet is to reboot the system in single user mode
+and set about correcting things from there. The following has been
+<em>adapted</em> from a life-saving email on the subject from David
+Wood:
+<verb>
+> What the hell do I do now?
+
+OK, don't panic. The first thing you have to realize is that
+this happens to 50% of users who ever do anything with PAM.
+It happened here, not once, not twice, but three times, all
+different, and in the end, the solution was the same every
+time.
+
+First, I hope you installed LILO with a delay. If you can,
+reboot, hit shift or tab or something and type:
+
+ LILO boot: linux single
+
+(Replace 'linux' with 'name-of-your-normal-linux-image').
+This will let you in without logging in. Ever wondered how
+easy it is to break into a linux machine from the console?
+Now you know.
+
+If you can't do that, then get yourself a bootkernel floppy
+and a root disk a-la slackware's rescue.gz. (Red Hat's
+installation disks can be used in this mode too.)
+
+In either case, the point is to get back your root prompt.
+
+Second, I'm going to assume that you haven't completely
+nuked your pam installation - just your configuration files.
+Here's how you make your configs nice again:
+
+ cd /etc
+ mv pam.conf pam.conf.orig
+ mv pam.d pam.d.orig
+ mkdir pam.d
+ cd pam.d
+
+and then use vi to create a file called "other" in this
+directory. It should contain the following four lines:
+
+ auth required pam_unix_auth.so
+ account required pam_unix_acct.so
+ password required pam_unix_passwd.so
+ session required pam_unix_session.so
+
+Now you have the simplest possible PAM configuration that
+will work the way you're used to. Everything should
+magically start to work again. Try it out by hitting ALT-F2
+and logging in on another virtual console. If it doesn't
+work, you have bigger problems, or you've mistyped
+something. One of the wonders of this system (seriously,
+perhaps) is that if you mistype anything in the conf files,
+you usually get no error reporting of any kind on the
+console - just some entries in the log file. So look there!
+(Try 'tail /var/log/messages'.)
+
+From here you can go back and get a real configuration
+going, hopefully after you've tested it first on a machine
+you don't care about screwing up. :/
+
+Some pointers (to make everything "right" with Red Hat...):
+
+ Install the newest pam, pamconfig, and pwdb from the
+ redhat current directory, and do it all on the same
+ command line with rpm...
+
+ rpm -Uvh [maybe --force too] pam-* pamconfig-* pwdb-*
+
+ Then make sure you install (or reinstall) the newest
+ version of libc, util-linux, wuftp, and NetKit. For
+ kicks you might try installing the newest versions of
+ the affected x apps, like xlock, but I haven't gotten
+ those to work at all yet.
+
+</verb>
+
+<sect1>Avoid having a weak `other' configuration
+
+<p>
+It is not a good thing to have a weak default (<tt/OTHER/) entry.
+This service is the default configuration for all PAM aware
+applications and if it is weak, your system is likely to be vulnerable
+to attack.
+
+<sect>A reference guide for available modules
+
+<p>
+Here, we collect together some descriptions of the various modules
+available for <bf/Linux-PAM/. In general these modules should be
+freely available. Where this is not the case, it will be indicated.
+
+<p>
+Also please note the comments contained in the section <ref
+id="text-conventions" name="on text conventions above"> when copying
+the examples listed below.
+
+<!-- insert-file MODULES-SGML -->
+
+<sect>Files
+
+<p><descrip>
+
+<tag><tt>/usr/lib/libpam.so.*</tt></tag>
+
+the shared library providing applications with access to
+<bf/Linux-PAM/.
+
+<tag><tt>/etc/pam.conf</tt></tag>
+
+the <bf/Linux-PAM/ configuration file.
+
+<tag><tt>/usr/lib/security/pam_*.so</tt></tag>
+
+the primary location for <bf/Linux-PAM/ dynamically loadable object
+files; the modules.
+
+</descrip>
+
+<sect>See also<label id="see-also-sec">
+
+<p><itemize>
+
+<item>The <bf/Linux-PAM/ Application Writers' Guide.
+
+<item>The <bf/Linux-PAM/ Module Writers' Guide.
+
+<item>The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH
+PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request
+For Comments 86.0, October 1995. See this url:
+<tt><htmlurl
+url="http://www.pilgrim.umass.edu/pub/osf_dce/RFC/rfc86.0.txt"
+name="http://www.pilgrim.umass.edu/pub/osf&lowbar;dce/RFC/rfc86.0.txt"></tt>
+
+</itemize>
+
+<sect>Notes
+
+<p>
+I intend to put development comments here... like ``at the moment
+this isn't actually supported''. At release time what ever is in
+this section will be placed in the Bugs section below! :)
+
+<p>
+Are we going to be able to support the <tt/use_mapped_pass/ module
+argument? Anyone know a cheap (free) good lawyer?!
+
+<p>
+<itemize>
+<item>
+This issue may go away, as Sun have investigated adding a new
+management group for mappings. In this way, libpam would have mapping
+modules that could securely store passwords using strong cryptography
+and in such a way that they need not be distributed with Linux-PAM.
+</itemize>
+
+<sect>Author/acknowledgments
+
+<p>
+This document was written by Andrew G. Morgan (morgan@parc.power.net)
+with many contributions from
+<!-- insert credits here -->
+<!--
+ an sgml list of people to credit for their contributions to Linux-PAM
+ $Id: pam_source.sgml,v 1.5 1997/04/05 06:49:14 morgan Exp morgan $
+ -->
+Craig S. Bell,
+Derrick J. Brashear,
+Ben Buxton,
+Oliver Crow,
+Marc Ewing,
+Cristian Gafton,
+Eric Hester,
+Eric Jacksch,
+Michael K. Johnson,
+David Kinchlea,
+Elliot Lee,
+Al Longyear,
+Marek Michalkiewicz,
+Aleph One,
+Sean Reifschneider,
+Eric Troan,
+Theodore Ts'o,
+Jeff Uphoff,
+Ronald Wahl,
+John Wilmes,
+Joseph S. D. Yao
+and
+Alex O. Yuriev.
+
+
+<p>
+Thanks are also due to Sun Microsystems, especially to Vipin Samar and
+Charlie Lai for their advice. At an early stage in the development of
+<bf/Linux-PAM/, Sun graciously made the documentation for their
+implementation of PAM available. This act greatly accelerated the
+development of <bf/Linux-PAM/.
+
+<sect>Bugs/omissions
+
+<p>
+More PAM modules are being developed all the time. It is unlikely that
+this document will ever be truely up to date!
+
+<p>
+Currently there is no documentation for PAM-aware applications.
+
+<p>
+This manual is unfinished. Only a partial list of people is credited
+for all the good work they have done.
+
+<sect>Copyright information for this document
+
+<p>
+Copyright (c) Andrew G. Morgan 1996. All rights reserved.
+<newline>
+Email: <tt>&lt;morgan@parc.power.net&gt;</tt>
+
+<p>
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+<p>
+<itemize>
+
+<item>
+1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+<item>
+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.
+
+<item>
+3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+</itemize>
+
+<p>
+<bf/Alternatively/, this product may be distributed under the terms of
+the GNU General Public License (GPL), in which case the provisions of
+the GNU GPL are required <bf/instead of/ the above restrictions.
+(This clause is necessary due to a potential bad interaction between
+the GNU GPL and the restrictions contained in a BSD-style copyright.)
+
+<p>
+THIS SOFTWARE IS PROVIDED ``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 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.
+
+<p>
+<tt>$Id: pam_source.sgml,v 1.5 1997/04/05 06:49:14 morgan Exp morgan $</tt>
+
+</article>
diff --git a/contrib/libpam/doc/ps/README b/contrib/libpam/doc/ps/README
new file mode 100644
index 000000000000..6234e14f8f8e
--- /dev/null
+++ b/contrib/libpam/doc/ps/README
@@ -0,0 +1,3 @@
+$Id: README,v 1.1 1996/11/10 19:28:16 morgan Exp $
+
+this is the directory for the postscipt documentation
diff --git a/contrib/libpam/doc/specs/draft-morgan-pam-00.raw b/contrib/libpam/doc/specs/draft-morgan-pam-00.raw
new file mode 100644
index 000000000000..6e37b86a6868
--- /dev/null
+++ b/contrib/libpam/doc/specs/draft-morgan-pam-00.raw
@@ -0,0 +1,270 @@
+PAM working group ## A.G. Morgan
+Internet Draft: ## March 24, 1998
+Document: draft-morgan-pam-00.txt ##
+Expires: September 24, 1998 ##
+Obsoletes: ##
+
+## Pluggable Authentication Modules ##
+
+#$ Status of this memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet- Drafts as reference
+material or to cite them other than as "work in progress."
+
+To view the entire list of current Internet-Drafts, please check the
+"1id-abstracts.txt" listing contained in the Internet-Drafts Shadow
+Directories on ftp.is.co.za (Africa), ftp.nordu.net (Northern Europe),
+ftp.nis.garr.it (Southern Europe), munnari.oz.au (Pacific Rim),
+ftp.ietf.org (US East Coast), or ftp.isi.edu (US West Coast).
+
+#$ Abstract
+
+This document is concerned with the definition of a general
+infrastructure for module based authentication. The infrastructure is
+named Pluggable Authentication Modules (PAM for short).
+
+#$ Introduction
+
+Computers are tools. They provide services to people and other
+computers (collectively we shall call these "users" entities). In
+order to provide convenient, reliable and individual service to
+different entities, it is common for entities to be labelled. Having
+defined a label as refering to a some specific entity, the label is
+used for the purpose of protecting and allocating data resources.
+
+All modern operating systems have a notion of labelled entities and
+all modern operating systems face a common problem: how to
+authenticate the association of a predefined label with applicant
+entities.
+
+There are as many authentication methods as one might care to count.
+None of them are perfect and none of them are invulnerable. In
+general, any given authentication method becomes weaker over time. It
+is common then for new authentication methods to be developed in
+response to newly discovered weaknesses in the old authentication
+methods.
+
+The problem with reinventing authentication methods is the fact that
+old applications do not support them. This contributes to an inertia
+that discourages the overhaul of weakly protected systems. Another
+problem is that individuals (people) are frequently powerless to layer
+the protective authentication around their systems. They are forced
+to rely on single (lowest common denominator) authentication schemes
+even in situations where this is far from appropriate.
+
+PAM, as discussed in this document, is a generalization of the
+approach first introduced in [#$R#{OSF_RFC_PAM}]. In short, it is a
+general framework of interfaces that abstract the process of
+authentication. With PAM, a service provider can custom protect
+individual services to the level that they deam is appropriate.
+
+PAM has nothing explicit to say about transport layer encryption.
+Within the context of this document encryption and/or compression of
+data exchanges are application specific (strictly between client and
+server).
+
+#$ Definitions
+
+Here we pose the authentication problem as one of configuring defined
+interfaces between two entities.
+
+#$$#{players} Players in the authentication process
+
+PAM reserves the following words to specify unique entities in the
+authentication process:
+
+ applicant
+ the entity (user) initiating an application for service
+ [PAM associates PAM_RUSER with this requesting user].
+
+ arbitrator
+ the entity (user) under who's identity the service application
+ is negotiated and with who's authority service is granted.
+
+ user
+ the entity (user) who's identity is being authenticated
+ [PAM associates PAM_USER with this identity].
+
+ server
+ the application that provides service, or acts as an
+ authenticated gateway to the requested service. This
+ application is completely responsible for the transport
+ layer. PAM makes no assumptions about how data is
+ exchanged between the server and the client.
+
+ client
+ application providing the direct/primary interface to
+ applicant. This application is completely responsible
+ for transporting client-side data to the server.
+ PAM makes no assumptions about how data is exchanged between
+ the client and the server.
+
+ module
+ authentication binary that provides server-side support for
+ some authentication method.
+
+ agent
+ authentication binary that provides client-side support for
+ some authentication method.
+
+#$$ Special cases
+
+In the previous section (#{players}) we identified the most general
+selection of authentication participants. In the case of network
+authentication, it is easy to ascribe identities to the defined
+players. However, there are special (less general) cases and we
+recognize them here.
+
+The primary authentication step, when a user is directly introduced
+into a computer system (log's on to a workstation) is a special case.
+In this situation, the "client" and the "server" are generally one
+application. Before authenticating such a user, the "applicant" is
+formally unknown.
+
+#$ Defined interfaces
+
+Here, we discuss the formal interfaces between the players in the
+authentication process.
+
+#$$#{applicant_client} Applicant <-> client
+
+Once the client is invoked, requests to the applicant entity are
+initiated by the client application. General clients are able to make
+the following requests to an applicant:
+
+ echo text
+ echo error
+ prompt for echo'd text input
+ prompt for concealed text input
+
+the nature of the interface provided by the client for the benefit of
+the applicant entity is client specific and not defined by PAM.
+
+#$$ Client <-> agent
+
+In general, authentication schemes require more modes of exchange than
+the four defined in the previous section (#{applicant_client}). This
+provides a role for client-loadable agents. The client and agent
+exchange binary-messages that can have one of the following forms:
+
+ client -> agent
+ prompt for binary data packet using a binary packet
+
+ agent -> client
+ set environment variable
+ get environment variable
+ echo text
+ echo error
+ prompt for echo'd text input
+ prompt for concealed text input
+
+The single defined procedure for exchange is that the client first
+prompts the agent with a binary packet and expects to receive a binary
+(response) packet in return. Before returning the binary response,
+the agent may request an arbitrary number of exchanges with the client.
+
+#$$ Client <-> server
+
+Once the client has established a connection with the server (the
+nature of the transport protocol is not specified by PAM), the server
+is reponsible for driving the authentication process.
+
+General servers can request the following from the client:
+
+ (directed to the applicant)
+ echo text
+ echo error
+ prompt for echo'd text response
+ prompt for concealed text response
+
+ (directed to the appropriate agent)
+ binary prompt for a binary response
+
+Client side agents are required to process binary prompts. Their
+binary responses are passed directly back to the server.
+
+#$$ Server <-> module
+
+Modules drive the authentication process. The server provides a
+conversation function with which it encapsulates module-generated
+requests and exchanges them with the client.
+
+General conversation functions can support the following five
+"conversation" requests:
+
+ echo text
+ echo error
+ prompt for echo'd text response
+ prompt for concealed text response
+ prompt for binary packet with binary packet
+
+The server is responsible for redirecting these requests to the
+client.
+
+#$ C API for defined interfaces
+
+#$$ Applicant <-> client
+
+No API is defined for this interface. The interface is considered to
+be specific to the client application. Example applications include
+terminal login, (X)windows login, machine file transfer applications.
+
+#$$ Client <-> agent
+
+This interface is concerned with the exchange of "binary prompts". A
+binary prompt has the following form: { 4 8-bit bytes in network order
+encoding an unsigened 32 bit integer (length), 4 8-bit bytes in
+network order encoding an unsigened 32 bit integer (control),
+"length-4" 8-bit bytes bytes comprising upto 2^32-4 bytes of binary
+data }.
+
+## [ u32 | u32 | (length-4 bytes) ] ##
+## length control data ##
+
+The composition of the "data" is not specified. Valid control values
+are:
+
+##control value | used by | description ##
+##------------------------------------------------------------------##
+## | | ##
+##PAMC_CONTROL_OK | agent | agent is happy ##
+##PAMC_CONTROL_FAIL | agent | agent failed ##
+##PAMC_CONTROL_BUSY | agent | agent is busy ##
+##PAMC_CONTROL_PUTENV | agent | set envvar of client ##
+##PAMC_CONTROL_GETENV | agent | want envvar of client ##
+##PAMC_CONTROL_GETECHO | agent | echo'd prompt to applicant##
+##PAMC_CONTROL_GETNOECHO | agent | secret prompt to applicant##
+##PAMC_CONTROL_PUTTEXT | agent | echo text to applicant ##
+##PAMC_CONTROL_SELECT | client | client selects named agent##
+##PAMC_CONTROL_EXCHANGE | client+agent | data exchange packet ##
+##PAMC_CONTROL_DONE | agent | agent has completed ##
+##PAMC_CONTROL_EMPTY | agent | agent has no reply ##
+
+#$ Security considerations
+
+This document is devoted to standardizing authentication
+infrastructure: everything in this document has implications for
+security.
+
+#$ Contact
+
+The email list for discussing issues related to this document is
+<pam-list@redhat.com>.
+
+#$ References
+
+[#{OSF_RFC_PAM}] OSF RFC 86.0, "Unified Login with Pluggable Authentication
+ Modules (PAM)", October 1995
+
+#$ Author's Address
+
+Andrew Morgan
+Email: morgan@ftp.kernel.org
+
diff --git a/contrib/libpam/doc/specs/formatter/Makefile b/contrib/libpam/doc/specs/formatter/Makefile
new file mode 100644
index 000000000000..d73258d7819f
--- /dev/null
+++ b/contrib/libpam/doc/specs/formatter/Makefile
@@ -0,0 +1,16 @@
+LIBS=-lfl
+
+padout: parse.tab.o
+ $(CC) -o padout parse.tab.o $(LIBS)
+
+parse.tab.o: parse.tab.c lex.yy.c
+ $(CC) -c parse.tab.c
+
+parse.tab.c: parse.y
+ bison parse.y
+
+lex.yy.c: parse.lex
+ flex parse.lex
+
+clean:
+ rm -f parse.tab.o parse.tab.c lex.yy.c padout *~ core
diff --git a/contrib/libpam/doc/specs/formatter/parse.lex b/contrib/libpam/doc/specs/formatter/parse.lex
new file mode 100644
index 000000000000..1d5c898e0549
--- /dev/null
+++ b/contrib/libpam/doc/specs/formatter/parse.lex
@@ -0,0 +1,11 @@
+%%
+
+\#[\$]+[a-zA-Z]*(\=[0-9]+)? return NEW_COUNTER;
+\#\{[a-zA-Z][a-zA-Z0-9\_]*\} return LABEL;
+\# return NO_INDENT;
+\#\# return RIGHT;
+\\\# return HASH;
+[^\n] return CHAR;
+[\n] return NEWLINE;
+
+%%
diff --git a/contrib/libpam/doc/specs/formatter/parse.y b/contrib/libpam/doc/specs/formatter/parse.y
new file mode 100644
index 000000000000..6da47d17e9a0
--- /dev/null
+++ b/contrib/libpam/doc/specs/formatter/parse.y
@@ -0,0 +1,293 @@
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXLINE 1000
+#define INDENT_STRING " "
+#define PAPER_WIDTH 74
+
+ int indent=0;
+ int line=1;
+ char *last_label=NULL;
+
+ extern void yyerror(const char *x);
+ extern char *get_label(const char *label);
+ extern void set_label(const char *label, const char *target);
+ char *new_counter(const char *key);
+
+#include "lex.yy.c"
+
+%}
+
+%union {
+ int def;
+ char *string;
+}
+
+%token NEW_COUNTER LABEL HASH CHAR NEWLINE NO_INDENT RIGHT
+%type <string> stuff text
+
+%start doc
+
+%%
+
+doc:
+| doc NEWLINE {
+ printf("\n");
+ ++line;
+}
+| doc stuff NEWLINE {
+ if (strlen($2) > (PAPER_WIDTH-(indent ? strlen(INDENT_STRING):0))) {
+ yyerror("line too long");
+ }
+ printf("%s%s\n", indent ? INDENT_STRING:"", $2);
+ free($2);
+ indent = 1;
+ ++line;
+}
+| doc stuff RIGHT stuff NEWLINE {
+ char fixed[PAPER_WIDTH+1];
+ int len;
+
+ len = PAPER_WIDTH-(strlen($2)+strlen($4));
+
+ if (len >= 0) {
+ memset(fixed, ' ', len);
+ fixed[len] = '\0';
+ } else {
+ yyerror("line too wide");
+ fixed[0] = '\0';
+ }
+ printf("%s%s%s\n", $2, fixed, $4);
+ free($2);
+ free($4);
+ indent = 1;
+ ++line;
+}
+| doc stuff RIGHT stuff RIGHT stuff NEWLINE {
+ char fixed[PAPER_WIDTH+1];
+ int len, l;
+
+ len = PAPER_WIDTH-(strlen($2)+strlen($4));
+
+ if (len < 0) {
+ len = 0;
+ yyerror("line too wide");
+ }
+
+ l = len/2;
+ memset(fixed, ' ', l);
+ fixed[l] = '\0';
+ printf("%s%s%s", $2, fixed, $4);
+ free($2);
+ free($4);
+
+ l = (len+1)/2;
+ memset(fixed, ' ', l);
+ fixed[l] = '\0';
+ printf("%s%s\n", fixed, $6);
+ free($6);
+
+ indent = 1;
+ ++line;
+}
+| doc stuff RIGHT stuff RIGHT stuff NEWLINE {
+ char fixed[PAPER_WIDTH+1];
+ int len, l;
+
+ len = PAPER_WIDTH-(strlen($2)+strlen($4));
+
+ if (len < 0) {
+ len = 0;
+ yyerror("line too wide");
+ }
+
+ l = len/2;
+ memset(fixed, ' ', l);
+ fixed[l] = '\0';
+ printf("%s%s%s", $2, fixed, $4);
+ free($2);
+ free($4);
+
+ l = (len+1)/2;
+ memset(fixed, ' ', l);
+ fixed[l] = '\0';
+ printf("%s%s\n", fixed, $6);
+ free($6);
+
+ indent = 1;
+ ++line;
+}
+;
+
+stuff: {
+ $$ = strdup("");
+}
+| stuff text {
+ $$ = malloc(strlen($1)+strlen($2)+1);
+ sprintf($$,"%s%s", $1, $2);
+ free($1);
+ free($2);
+}
+;
+
+text: CHAR {
+ $$ = strdup(yytext);
+}
+| text CHAR {
+ $$ = malloc(strlen($1)+2);
+ sprintf($$,"%s%s", $1, yytext);
+ free($1);
+}
+| NO_INDENT {
+ $$ = strdup("");
+ indent = 0;
+}
+| HASH {
+ $$ = strdup("#");
+}
+| LABEL {
+ if (($$ = get_label(yytext)) == NULL) {
+ set_label(yytext, last_label);
+ $$ = strdup("");
+ }
+}
+| NEW_COUNTER {
+ $$ = new_counter(yytext);
+}
+;
+
+%%
+
+typedef struct node_s {
+ struct node_s *left, *right;
+ const char *key;
+ char *value;
+} *node_t;
+
+node_t label_root = NULL;
+node_t counter_root = NULL;
+
+const char *find_key(node_t root, const char *key)
+{
+ while (root) {
+ int cmp = strcmp(key, root->key);
+
+ if (cmp > 0) {
+ root = root->right;
+ } else if (cmp) {
+ root = root->left;
+ } else {
+ return root->value;
+ }
+ }
+ return NULL;
+}
+
+node_t set_key(node_t root, const char *key, const char *value)
+{
+ if (root) {
+ int cmp = strcmp(key, root->key);
+ if (cmp > 0) {
+ root->right = set_key(root->right, key, value);
+ } else if (cmp) {
+ root->left = set_key(root->left, key, value);
+ } else {
+ free(root->value);
+ root->value = strdup(value);
+ }
+ } else {
+ root = malloc(sizeof(struct node_s));
+ root->right = root->left = NULL;
+ root->key = strdup(key);
+ root->value = strdup(value);
+ }
+ return root;
+}
+
+void yyerror(const char *x)
+{
+ fprintf(stderr, "line %d: %s\n", line, x);
+}
+
+char *get_label(const char *label)
+{
+ const char *found = find_key(label_root, label);
+
+ if (found) {
+ return strdup(found);
+ }
+ return NULL;
+}
+
+void set_label(const char *label, const char *target)
+{
+ if (target == NULL) {
+ yyerror("no hanging value for label");
+ target = "<??>";
+ }
+ label_root = set_key(label_root, label, target);
+}
+
+char *new_counter(const char *key)
+{
+ int i=0, j, ndollars = 0;
+ const char *old;
+ char *new;
+
+ if (key[i++] != '#') {
+ yyerror("bad index");
+ return strdup("<???>");
+ }
+
+ while (key[i] == '$') {
+ ++ndollars;
+ ++i;
+ }
+
+ key += i;
+ old = find_key(counter_root, key);
+ new = malloc(20*ndollars);
+
+ if (old) {
+ for (j=0; ndollars > 1 && old[j]; ) {
+ if (old[j++] == '.' && --ndollars <= 0) {
+ break;
+ }
+ }
+ if (j) {
+ strncpy(new, old, j);
+ }
+ if (old[j]) {
+ i = atoi(old+j);
+ } else {
+ new[j++] = '.';
+ i = 0;
+ }
+ } else {
+ j=0;
+ while (--ndollars > 0) {
+ new[j++] = '0';
+ new[j++] = '.';
+ }
+ i = 0;
+ }
+ new[j] = '\0';
+ sprintf(new+j, "%d", ++i);
+
+ counter_root = set_key(counter_root, key, new);
+
+ if (last_label) {
+ free(last_label);
+ }
+ last_label = strdup(new);
+
+ return new;
+}
+
+main()
+{
+ yyparse();
+}
diff --git a/contrib/libpam/doc/specs/rfc86.0.txt b/contrib/libpam/doc/specs/rfc86.0.txt
new file mode 100644
index 000000000000..6dd5e6ea36dc
--- /dev/null
+++ b/contrib/libpam/doc/specs/rfc86.0.txt
@@ -0,0 +1,1851 @@
+
+
+
+
+
+
+
+
+ Open Software Foundation V. Samar (SunSoft)
+ Request For Comments: 86.0 R. Schemers (SunSoft)
+ October 1995
+
+
+
+ UNIFIED LOGIN WITH
+ PLUGGABLE AUTHENTICATION MODULES (PAM)
+
+
+ 1. INTRODUCTION
+
+ Since low-level authentication mechanisms constantly evolve, it is
+ important to shield the high-level consumers of these mechanisms
+ (system-entry services and users) from such low-level changes. With
+ the Pluggable Authentication Module (PAM) framework, we can provide
+ pluggability for a variety of system-entry services -- not just
+ system authentication _per se_, but also for account, session and
+ password management. PAM's ability to _stack_ authentication modules
+ can be used to integrate `login' with different authentication
+ mechanisms such as RSA, DCE, and Kerberos, and thus unify login
+ mechanisms. The PAM framework can also provide easy integration of
+ smart cards into the system.
+
+ Modular design and pluggability have become important for users who
+ want ease of use. In the PC hardware arena, no one wants to set the
+ interrupt vector numbers or resolve the addressing conflict between
+ various devices. In the software arena, people also want to be able
+ to replace components easily for easy customization, maintenance, and
+ upgrades.
+
+ Authentication software deserves special attention because
+ authentication forms a very critical component of any secure computer
+ system. The authentication infrastructure and its components may
+ have to be modified or replaced either because some deficiencies have
+ been found in the current algorithms, or because sites want to
+ enforce a different security policy than what was provided by the
+ system vendor. The replacement and modification should be done in
+ such a way that the user is not affected by these changes.
+
+ The solution has to address not just how the applications use the new
+ authentication mechanisms in a generic fashion, but also how the user
+ will be authenticated to these mechanisms in a generic way. The
+ former is addressed by GSS-API [Linn 93], while this RFC addresses
+ the later; these two efforts are complementary to each other.
+
+ Since most system-entry services (for example, `login', `dtlogin',
+ `rlogin', `ftp', `rsh') may want to be independent of the specific
+ authentication mechanisms used by the machine, it is important that
+ there be a framework for _plugging_ in various mechanisms. This
+ requires that the system applications use a standard API to interact
+
+
+
+ Samar, Schemers Page 1
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ with the authentication services. If these system-entry services
+ remain independent of the actual mechanism used on that machine, the
+ system administrator can install suitable authentication modules
+ without requiring changes to these applications.
+
+ For any security system to be successful, it has to be easy to use.
+ In the case of authentication, the single most important ease-of-use
+ characteristic is that the user should not be required to learn about
+ various ways of authentication and remember multiple passwords.
+ Ideally, there should be one all-encompassing authentication system
+ where there is only one password, but for heterogeneous sites,
+ multiple authentication mechanisms have to co-exist. The problem of
+ integrating multiple authentication mechanisms such as Kerberos
+ [Steiner 88], RSA [Rivest 78], and Diffie-Hellman [Diffie 76, Taylor
+ 88], is also referred to as _integrated login_, or _unified login_
+ problem. Even if the user has to use multiple authentication
+ mechanisms, the user should not be forced to type multiple passwords.
+ Furthermore, the user should be able to use the new network identity
+ without taking any further actions. The key here is in modular
+ integration of the network authentication technologies with `login'
+ and other system-entry services.
+
+ In this RFC we discuss the architecture and design of pluggable
+ authentication modules. This design gives the capability to use
+ field-replaceable authentication modules along with unified login
+ capability. It thus provides for both _pluggability_ and _ease-of-
+ use_.
+
+ The RFC is organized as follows. We first motivate the need for a
+ generic way to authenticate the user by various system-entry services
+ within the operating system. We describe the goals and constraints
+ of the design. This leads to the architecture, description of the
+ interfaces, and _stacking_ of modules to get unified login
+ functionality. We then describe our experience with the design, and
+ end with a description of future work.
+
+
+ 2. OVERVIEW OF IDENTIFICATION AND AUTHENTICATION MECHANISMS
+
+ An identification and authentication ("I&A") mechanism is used to
+ establish a user's identity the system (i.e., to a local machine's
+ operating system) and to other principals on the network. On a
+ typical UNIX system, there are various ports of entry into the
+ system, such as `login', `dtlogin', `rlogin', `ftp', `rsh', `su', and
+ `telnet'. In all cases, the user has to be identified and
+ authenticated before granting appropriate access rights to the user.
+ The user identification and authentication for all these entry points
+ needs to be coordinated to ensure a secure system.
+
+ In most of the current UNIX systems, the login mechanism is based
+ upon verification of the password using the modified DES algorithm.
+
+
+
+ Samar, Schemers Page 2
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ The security of the implementation assumes that the password cannot
+ be guessed, and that the password does not go over the wire in the
+ clear. These assumptions, however, are not universally valid.
+ Various programs are now available freely on the Internet that can
+ run dictionary attack against the encrypted password. Further, some
+ of the network services (for example, `rlogin', `ftp', `telnet') send
+ the password over in clear, and there are "sniffer" programs freely
+ available to steal these passwords. The classical assumptions may be
+ acceptable on a trusted network, but in an open environment there is
+ a need to use more restrictive and stronger authentication
+ mechanisms. Examples of such mechanisms include Kerberos, RSA,
+ Diffie-Hellman, one-time password [Skey 94], and challenge-response
+ based smart card authentication systems. Since this list will
+ continue to evolve, it is important that the system-entry services do
+ not have hard-coded dependencies on any of these authentication
+ mechanisms.
+
+
+ 3. DESIGN GOALS
+
+ The goals of the PAM framework are as follows:
+
+ (a) The system administrator should be able to choose the default
+ authentication mechanism for the machine. This can range from
+ a simple password-based mechanism to a biometric or a smart
+ card based system.
+
+ (b) It should be possible to configure the user authentication
+ mechanism on a per application basis. For example, a site may
+ require S/Key password authentication for `telnet' access,
+ while allowing machine `login' sessions with just UNIX password
+ authentication.
+
+ (c) The framework should support the display requirements of the
+ applications. For example, for a graphical login session such
+ as `dtlogin', the user name and the password may have to be
+ entered in a new window. For networking system-entry
+ applications such as `ftp' and `telnet', the user name and
+ password has to be transmitted over the network to the client
+ machine.
+
+ (d) It should be possible to configure multiple authentication
+ protocols for each of those applications. For example, one may
+ want the users to get authenticated by both Kerberos and RSA
+ authentication systems.
+
+ (e) The system administrator should be able to _stack_ multiple
+ user authentication mechanisms such that the user is
+ authenticated with all authentication protocols without
+ retyping the password.
+
+
+
+
+ Samar, Schemers Page 3
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ (f) The architecture should allow for multiple passwords if
+ necessary to achieve higher security for users with specific
+ security requirements.
+
+ (g) The system-entry services should not be required to change when
+ the underlying mechanism changes. This can be very useful for
+ third-party developers because they often do not have the
+ source code for these services.
+
+ (h) The architecture should provide for a _pluggable_ model for
+ system authentication, as well as for other related tasks such
+ as password, account, and session management.
+
+ (i) For backward-compatibility reasons, the PAM API should support
+ the authentication requirements of the current system-entry
+ services.
+
+ There are certain issues that the PAM framework does not specifically
+ address:
+
+ (a) We focus only on providing a generic scheme through which users
+ use passwords to establish their identities to the machine.
+ Once the identity is established, how the identity is
+ communicated to other interested parties is outside the scope
+ of this design. There are efforts underway at IETF [Linn 93]
+ to develop a Generic Security Services Application Interface
+ (GSSAPI) that can be used by applications for secure and
+ authenticated communication without knowing the underlying
+ mechanism.
+
+ (b) The _single-signon_ problem of securely transferring the
+ identity of the caller to a remote site is not addressed. For
+ example, the problem of delegating credentials from the
+ `rlogin' client to the other machine without typing the
+ password is not addressed by our work. We also do not address
+ the problem of sending the passwords over the network in the
+ clear.
+
+ (c) We do not address the source of information obtained from the
+ "`getXbyY()'" family of calls (e.g., `getpwnam()'). Different
+ operating systems address this problem differently. For
+ example, Solaris uses the name service switch (NSS) to
+ determine the source of information for the "`getXbyY()'"
+ calls. It is expected that data which is stored in multiple
+ sources (such as passwd entries in NIS+ and the DCE registry)
+ is kept in sync using the appropriate commands (such as
+ `passwd_export').
+
+
+
+
+
+
+
+ Samar, Schemers Page 4
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ 4. OVERVIEW OF THE PAM FRAMEWORK
+
+ We propose that the goals listed above can be met through a framework
+ in which authentication modules can be _plugged_ independently of the
+ application. We call this the _Pluggable Authentication Modules_
+ (PAM) framework.
+
+ The core components of the PAM framework are the authentication
+ library API (the front end) and the authentication mechanism-specific
+ modules (the back end), connected through the Service Provider
+ Interface (SPI). Applications write to the PAM API, while the
+ authentication-system providers write to the PAM SPI and supply the
+ back end modules that are independent of the application.
+
+ ftp telnet login (Applications)
+ | | |
+ | | |
+ +--------+--------+
+ |
+ +-----+-----+
+ | PAM API | <-- pam.conf file
+ +-----+-----+
+ |
+ +--------+--------+
+ UNIX Kerberos Smart Cards (Mechanisms)
+
+ Figure 1: The Basic PAM Architecture
+
+ Figure 1 illustrates the relationship between the application, the
+ PAM library, and the authentication modules. Three applications
+ (`login', `telnet' and `ftp') are shown which use the PAM
+ authentication interfaces. When an application makes a call to the
+ PAM API, it loads the appropriate authentication module as determined
+ by the configuration file, `pam.conf'. The request is forwarded to
+ the underlying authentication module (for example, UNIX password,
+ Kerberos, smart cards) to perform the specified operation. The PAM
+ layer then returns the response from the authentication module to the
+ application.
+
+ PAM unifies system authentication and access control for the system,
+ and allows plugging of associated authentication modules through well
+ defined interfaces. The plugging can be defined through various
+ means, one of which uses a configuration file, such as the one in
+ Table 1. For each of the system applications, the file specifies the
+ authentication module that should be loaded. In the example below,
+ `login' uses the UNIX password module, while `ftp' and `telnet' use
+ the S/Key module.
+
+
+
+
+
+
+
+ Samar, Schemers Page 5
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ Table 1: A Simplified View of a Sample PAM Configuration File.
+
+ service module_path
+ ------- -----------
+ login pam_unix.so
+ ftp pam_skey.so
+ telnet pam_skey.so
+
+ Authentication configuration is only one aspect of this interface.
+ Other critical components include account management, session
+ management, and password management. For example, the `login'
+ program may want to verify not only the password but also whether the
+ account has aged or expired. Generic interfaces also need to be
+ provided so that the password can be changed according to the
+ requirements of the module. Furthermore, the application may want to
+ log information about the current session as determined by the
+ module.
+
+ Not all applications or services may need all of the above
+ components, and not each authentication module may need to provide
+ support for all of the interfaces. For example, while `login' may
+ need access to all four components, `su' may need access to just the
+ authentication component. Some applications may use some specific
+ authentication and password management modules but share the account
+ and session management modules with others.
+
+ This reasoning leads to a partitioning of the entire set of
+ interfaces into four areas of functionality: (1) authentication, (2)
+ account, (3) session, and (4) password. The concept of PAM was
+ extended to these functional areas by implementing each of them as a
+ separate pluggable module.
+
+ Breaking the functionality into four modules helps the module
+ providers because they can use the system-provided libraries for the
+ modules that they are not changing. For example, if a supplier wants
+ to provide a better version of Kerberos, they can just provide that
+ new authentication and password module, and reuse the existing ones
+ for account and session.
+
+ 4.1. Module Description
+
+ More details on specific API's are described in Appendix A. A brief
+ description of four modules follows:
+
+ (a) Authentication management: This set includes the
+ `pam_authenticate()' function to authenticate the user, and the
+ `pam_setcred()' interface to set, refresh or destroy the user
+ credentials.
+
+ (b) Account management: This set includes the `pam_acct_mgmt()'
+ function to check whether the authenticated user should be
+
+
+
+ Samar, Schemers Page 6
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ given access to his/her account. This function can implement
+ account expiration and access hour restrictions.
+
+ (c) Session management: This set includes the `pam_open_session()'
+ and `pam_close_session()' functions for session management and
+ accounting. For example, the system may want to store the
+ total time for the session.
+
+ (d) Password management: This set includes a function,
+ `pam_chauthtok()', to change the password.
+
+
+ 5. FRAMEWORK INTERFACES
+
+ The PAM framework further provides a set of administrative interfaces
+ to support the above modules and to provide for application-module
+ communication. There is no corresponding service provider interface
+ (SPI) for such functions.
+
+ 5.1. Administrative Interfaces
+
+ Each set of PAM transactions starts with `pam_start()' and ends with
+ the `pam_end()' function. The interfaces `pam_get_item()' and
+ `pam_set_item()' are used to read and write the state information
+ associated with the PAM transaction.
+
+ If there is any error with any of the PAM interfaces, the error
+ message can be printed with `pam_strerror()'.
+
+ 5.2. Application-Module Communication
+
+ During application initialization, certain data such as the user name
+ is saved in the PAM framework layer through `pam_start()' so that it
+ can be used by the underlying modules. The application can also pass
+ opaque data to the module which the modules will pass back while
+ communicating with the user.
+
+ 5.3. User-Module Communication
+
+ The `pam_start()' function also passes conversation function that has
+ to be used by the underlying modules to read and write module
+ specific authentication information. For example, these functions
+ can be used to prompt the user for the password in a way determined
+ by the application. PAM can thus be used by graphical, non-
+ graphical, or networked applications.
+
+
+
+
+
+
+
+
+
+ Samar, Schemers Page 7
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ 5.4. Inter-Module Communication
+
+ Though the modules are independent, they can share certain common
+ information about the authentication session such as user name,
+ service name, password, and conversation function through the
+ `pam_get_item()' and `pam_set_item()' interfaces. These API's can
+ also be used by the application to change the state information after
+ having called `pam_start()' once.
+
+ 5.5. Module State Information
+
+ The PAM service modules may want to keep certain module-specific
+ state information about the session. The interfaces `pam_get_data()'
+ and `pam_set_data()' can be used by the service modules to access and
+ update module-specific information as needed from the PAM handle.
+ The modules can also attach a cleanup function with the data. The
+ cleanup function is executed when `pam_end()' is called to indicate
+ the end of the current authentication activity.
+
+ Since the PAM modules are loaded upon demand, there is no direct
+ module initialization support in the PAM framework. If there are
+ certain initialization tasks that the PAM service modules have to do,
+ they should be done upon the first invocation. However, if there are
+ certain clean-up tasks to be done when the authentication session
+ ends, the modules should use `pam_set_data()' to specify the clean-up
+ functions, which would be called when `pam_end()' is called by the
+ application.
+
+
+ 6. MODULE CONFIGURATION MANAGEMENT
+
+ Table 2 shows an example of a configuration file `pam.conf' with
+ support for authentication, session, account, and password management
+ modules. `login' has three entries: one each for authentication
+ processing, session management and account management. Each entry
+ specifies the module name that should be loaded for the given module
+ type. In this example, the `ftp' service uses the authentication and
+ session modules. Note that all services here share the same session
+ management module, while having different authentication modules.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Samar, Schemers Page 8
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ Table 2: Configuration File (pam.conf) with Different Modules
+ and Control Flow
+
+ service module_type control_flag module_path options
+ ------- ----------- ------------ ----------- -------
+ login auth required pam_unix_auth.so nowarn
+ login session required pam_unix_session.so
+ login account required pam_unix_account.so
+ ftp auth required pam_skey_auth.so debug
+ ftp session required pam_unix_session.so
+ telnet session required pam_unix_session.so
+ login password required pam_unix_passwd.so
+ passwd password required pam_unix_passwd.so
+ OTHER auth required pam_unix_auth.so
+ OTHER session required pam_unix_session.so
+ OTHER account required pam_unix_account.so
+
+ The first field, _service_, denotes the service (for example,
+ `login', `passwd', `rlogin'). The name `OTHER' indicates the module
+ used by all other applications that have not been specified in this
+ file. This name can also be used if all services have the same
+ requirements. In the example, since all the services use the same
+ session module, we could have replaced those lines with a single
+ `OTHER' line.
+
+ The second field, _module_type_, indicates the type of the PAM
+ functional module. It can be one of `auth', `account', `session', or
+ `password' modules.
+
+ The third field, _control_flag_ determines the behavior of stacking
+ multiple modules by specifying whether any particular module is
+ _required_, _sufficient_, or _optional_. The next section describes
+ stacking in more detail.
+
+ The fourth field, _module_path_, specifies the location of the
+ module. The PAM framework loads this module upon demand to invoke
+ the required function.
+
+ The fifth field, _options_, is used by the PAM framework layer to
+ pass module specific options to the modules. It is up to the module
+ to parse and interpret the options. This field can be used by the
+ modules to turn on debugging or to pass any module specific
+ parameters such as a timeout value. It is also used to support
+ unified login as described below. The options field can be used by
+ the system administrator to fine-tune the PAM modules.
+
+ If any of the fields are invalid, or if a module is not found, that
+ line is ignored and the error is logged as a critical error via
+ `syslog(3)'. If no entries are found for the given module type, then
+ the PAM framework returns an error to the application.
+
+
+
+
+ Samar, Schemers Page 9
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ 7. INTEGRATING MULTIPLE AUTHENTICATION SERVICES WITH STACKING
+
+ In the world of heterogeneous systems, the system administrator often
+ has to deal with the problem of integrating multiple authentication
+ mechanisms. The user is often required to know about the
+ authentication command of the new authentication module (for example,
+ `kinit', `dce_login') after logging into the system. This is not
+ user-friendly because it forces people to remember to type the new
+ command and enter the new password. This functionality should be
+ invisible instead of burdening the user with it.
+
+ There are two problems to be addressed here:
+
+ (a) Supporting multiple authentication mechanisms.
+
+ (b) Providing unified login in the presence of multiple mechanisms.
+
+ In the previous section, we described how one could replace the
+ default authentication module with any other module of choice. Now
+ we demonstrate how the same model can be extended to provide support
+ for multiple modules.
+
+ 7.1. Design for Stacked Modules
+
+ One possibility was to provide hard-coded rules in `login' or other
+ applications requiring authentication services [Adamson 95]. But
+ this becomes very specific to the particular combination of
+ authentication protocols, and also requires the source code of the
+ application. Digital's Security Integration Architecture [SIA 95]
+ addresses this problem by specifying the same list of authentication
+ modules for all applications. Since requirements for various
+ applications can vary, it is essential that the configuration be on a
+ per-application basis.
+
+ To support multiple authentication mechanisms, the PAM framework was
+ extended to support _stacking_. When any API is called, the back
+ ends for the stacked modules are invoked in the order listed, and the
+ result returned to the caller. In Figure 2, the authentication
+ service of `login' is stacked and the user is authenticated by UNIX,
+ Kerberos, and RSA authentication mechanisms. Note that in this
+ example, there is no stacking for session or account management
+ modules.
+
+
+
+
+
+
+
+
+
+
+
+
+ Samar, Schemers Page 10
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ login
+ |
+ +--------+--------+
+ | | |
+ session auth account
+ | | |
+ +--+--+ +--+--+ +--+--+
+ | PAM | | PAM | | PAM |
+ +--+--+ +--+--+ +--+--+
+ | | |
+ UNIX UNIX UNIX
+ session auth account
+ |
+ Kerberos
+ auth
+ |
+ RSA
+ auth
+
+ Figure 2: Stacking With the PAM Architecture
+
+ Stacking is specified through additional entries in the configuration
+ file shown earlier. As shown in Table 2, for each application (such
+ as `login') the configuration file can specify multiple mechanisms
+ that have to be invoked in the specified order. When mechanisms
+ fail, the _control_flag_ decides which error should be returned to
+ the application. Since the user should not know which authentication
+ module failed when a bad password was typed, the PAM framework
+ continues to call other authentication modules on the stack even on
+ failure. The semantics of the control flag are as follows:
+
+ (a) `required': With this flag, the module failure results in the
+ PAM framework returning the error to the caller _after_
+ executing all other modules on the stack. For the function to
+ be able to return success to the application all `required'
+ modules have to report success. This flag is normally set when
+ authentication by this module is a _must_.
+
+ (b) `optional': With this flag, the PAM framework ignores the
+ module failure and continues with the processing of the next
+ module in sequence. This flag is used when the user is allowed
+ to login even if that particular module has failed.
+
+ (c) `sufficient': With this flag, if the module succeeds the PAM
+ framework returns success to the application immediately
+ without trying any other modules. For failure cases, the
+ _sufficient_ modules are treated as `optional'.
+
+ Table 3 shows a sample configuration file that stacks the `login'
+ command. Here the user is authenticated by UNIX, Kerberos, and RSA
+ authentication services. The `required' key word for _control_flag_
+
+
+
+ Samar, Schemers Page 11
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ enforces that the user is allowed to login only if he/she is
+ authenticated by _both_ UNIX and Kerberos services. RSA
+ authentication is optional by virtue of the `optional' key word in
+ the _control_flag_ field. The user can still log in even if RSA
+ authentication fails.
+
+ Table 3: PAM Configuration File with Support for Stacking
+
+ service module_type control_flag module_path options
+ ------- ----------- ------------ ----------- -------
+ login auth required pam_unix.so debug
+ login auth required pam_kerb.so use_mapped_pass
+ login auth optional pam_rsa.so use_first_pass
+
+ Table 4 illustrates the use of the sufficient flag for the `rlogin'
+ service. The Berkeley `rlogin' protocol specifies that if the remote
+ host is trusted (as specified in the `/etc/hosts.equiv' file or in
+ the `.rhosts' file in the home directory of the user), then the
+ `rlogin' daemon should not require the user to type the password. If
+ this is not the case, then the user is required to type the password.
+ Instead of hard coding this policy in the `rlogin' daemon, this can
+ be expressed with the `pam.conf' file in Table 4. The PAM module
+ `pam_rhosts_auth.so.1' implements the `.rhosts' policy described
+ above. If a site administrator wants to enable remote login with
+ only passwords, then the first line should be deleted.
+
+ Table 4: PAM Configuration File for the rlogin service
+
+ service module_type control_flag module_path options
+ ------- ----------- ------------ ----------- -------
+ rlogin auth sufficient pam_rhosts_auth.so
+ rlogin auth required pam_unix.so
+
+ 7.2. Password-Mapping
+
+ Multiple authentication mechanisms on a machine can lead to multiple
+ passwords that users have to remember. One attractive solution from
+ the ease-of-use viewpoint is to use the same password for all
+ mechanisms. This, however, can also weaken the security because if
+ that password were to be compromised in any of the multiple
+ mechanisms, all mechanisms would be compromised at the same time.
+ Furthermore, different authentication mechanisms may have their own
+ distinctive password requirements in regards to its length, allowed
+ characters, time interval between updates, aging, locking, and so
+ forth. These requirements make it problematic to use the same
+ password for multiple authentication mechanisms.
+
+ The solution we propose, while not precluding use of the same
+ password for every mechanism, allows for a different password for
+ each mechanism through what we call _password-mapping_. This
+ basically means using the user's _primary_ password to encrypt the
+
+
+
+ Samar, Schemers Page 12
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ user's other (_secondary_) passwords, and storing these encrypted
+ passwords in a place where they are available to the user. Once the
+ primary password is verified, the authentication modules would obtain
+ the other passwords for their own mechanisms by decrypting the
+ mechanism-specific encrypted password with the primary password, and
+ passing it to the authentication service. The security of this
+ design for password-mapping assumes that the primary password is the
+ user's strongest password, in terms of its unguessability (length,
+ type and mix of characters used, etc.).
+
+ If there is any error in password-mapping, or if the mapping does not
+ exist, the user will be prompted for the password by each
+ authentication module.
+
+ To support password-mapping, the PAM framework saves the primary
+ password and provides it to stacked authentication modules. The
+ password is cleared out before the `pam_authenticate' function
+ returns.
+
+ How the password is encrypted depends completely on the module
+ implementation. The encrypted secondary password (also called a
+ "mapped password") can be stored in a trusted or untrusted place,
+ such as a smart card, a local file, or a directory service. If the
+ encrypted passwords are stored in an untrusted publicly accessible
+ place, this does provide an intruder with opportunities for potential
+ dictionary attack.
+
+ Though password-mapping is voluntary, it is recommended that all
+ module providers add support for the following four mapping options:
+
+ (a) `use_first_pass': Use the same password used by the first
+ mechanism that asked for a password. The module should not ask
+ for the password if the user cannot be authenticated by the
+ first password. This option is normally used when the system
+ administrator wants to enforce the same password across
+ multiple modules.
+
+ (b) `try_first_pass': This is the same as `use_first_pass', except
+ that if the primary password is not valid, it should prompt the
+ user for the password.
+
+ (c) `use_mapped_pass': Use the password-mapping scheme to get the
+ actual password for this module. One possible implementation
+ is to get the mapped-password using the XFN API [XFN 94], and
+ decrypt it with the primary password to get the module-specific
+ password. The module should not ask for the password if the
+ user cannot be authenticated by the first password. The XFN
+ API allows user-defined attributes (such as _mapped-password_)
+ to be stored in the _user-context_. Using the XFN API is
+ particularly attractive because support for the XFN may be
+ found on many systems in the future.
+
+
+
+ Samar, Schemers Page 13
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ (d) `try_mapped_pass': This is the same as `use_mapped_pass',
+ except that if the primary password is not valid, it should
+ prompt the user for the password.
+
+ When passwords get updated, the PAM framework stores both the old as
+ well as the new password to be able to inform other dependent
+ authentication modules about the change. Other modules can use this
+ information to update the encrypted password without forcing the user
+ to type the sequence of passwords again. The PAM framework clears
+ out the passwords before returning to the application.
+
+ Table 3 illustrates how the same password can be used by `login' for
+ authenticating to the standard UNIX login, Kerberos and RSA services.
+ Once the user has been authenticated to the primary authentication
+ service (UNIX `login' in this example) with the primary password, the
+ option `use_mapped_pass' indicates to the Kerberos module that it
+ should use the primary password to decrypt the stored Kerberos
+ password and then use the Kerberos password to get the ticket for the
+ ticket-granting-service. After that succeeds, the option
+ `use_first_pass' indicates to the RSA module that instead of
+ prompting the user for a password, it should use the primary password
+ typed earlier for authenticating the user. Note that in this
+ scenario, the user has to enter the password just once.
+
+ Note that if a one-time password scheme (e.g., S/Key) is used,
+ password mapping cannot apply.
+
+ 7.3. Implications of Stacking on the PAM Design
+
+ Because of the stacking capability of PAM, we have designed the PAM
+ API's to not return any data to the application, except status. If
+ this were not the case, it would be difficult for the PAM framework
+ to decide which module should return data to the application. When
+ there is any error, the application does not know which of the
+ modules failed. This behavior enables (even requires) the
+ application to be completely independent from the modules.
+
+ Another design decision we have made is that PAM gives only the user
+ name to all the underlying PAM modules, hence it is the
+ responsibility of the PAM modules to convert the name to their own
+ internal format. For example, the Kerberos module may have to
+ convert the UNIX user name to a Kerberos principal name.
+
+ Stacking also forces the modules to be designed such that they can
+ occur anywhere in the stack without any side-effects.
+
+ Since modules such as the authentication and the password module are
+ very closely related, it is important they be configured in the same
+ order and with compatible options.
+
+
+
+
+
+ Samar, Schemers Page 14
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ 8. INTEGRATION WITH SMART CARDS
+
+ Many networking authentication protocols require possession of a long
+ key to establish the user identity. For ease-of-use reasons, that
+ long key is normally encrypted with the user's password so that the
+ user is not required to memorize it. However, weak passwords can be
+ compromised through a dictionary attack and thus undermine the
+ stronger network authentication mechanism. Furthermore, the
+ encrypted data is normally stored in a centrally accessible service
+ whose availability depends upon the reliability of the associated
+ service. Solutions have been proposed to use a pass-phrase or one-
+ time-password, but those are much longer than the regular eight
+ character passwords traditionally used with UNIX `login'. This makes
+ the solution user-unfriendly because it requires longer strings to be
+ remembered and typed.
+
+ For most authentication protocol implementations, the trust boundary
+ is the local machine. This assumption may not be valid in cases
+ where the user is mobile and has to use publicly available networked
+ computers. In such cases, it is required that the clear text of the
+ key or the password never be made available to the machine.
+
+ Smart cards solve the above problems by reducing password exposure by
+ supporting a _two factor_ authentication mechanism: the first with
+ the possession of the card, and the second with the knowledge of the
+ PIN associated with the card. Not only can the smart cards be a
+ secure repository of multiple passwords, they can also provide the
+ encryption and authentication functions such that the long (private)
+ key is never exposed outside the card.
+
+ The PAM framework allows for integrating smart cards to the system by
+ providing a smart card specific module for authentication.
+ Furthermore, the unified login problem is simplified because the
+ multiple passwords for various authentication mechanisms can be
+ stored on the smart card itself. This can be enabled by adding a
+ suitable key-word such as `use_smart_card' in the _options_ field.
+
+
+ 9. SECURITY ISSUES
+
+ It is important to understand the impact of PAM on the security of
+ any system so that the site-administrator can make an informed
+ decision.
+
+ (a) Sharing of passwords with multiple authentication mechanisms.
+
+ If there are multiple authentication modules, one possibility
+ is to use the same password for all of them. If the password
+ for any of the multiple authentication system is compromised,
+ the user's password in all systems would be compromised. If
+ this is a concern, then multiple passwords might be considered
+
+
+
+ Samar, Schemers Page 15
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ at the cost of ease-of-use.
+
+ (b) Password-mapping.
+
+ This technique of encrypting all other passwords with the
+ primary password assumes that it is lot more difficult to crack
+ the primary password and that reasonable steps have been taken
+ to ensure limited availability of the encrypted primary
+ password. If this is not done, an intruder could target the
+ primary password as the first point of dictionary attack. If
+ one of the other modules provide stronger security than the
+ password based security, the site would be negating the strong
+ security by using password-mapping. If this is a concern, then
+ multiple passwords might be considered at the cost of ease-of-
+ use. If smart cards are used, they obviate the need for
+ password-mapping completely.
+
+ (c) Security of the configuration file.
+
+ Since the policy file dictates how the user is authenticated,
+ this file should be protected from unauthorized modifications.
+
+ (d) Stacking various PAM modules.
+
+ The system administrator should fully understand the
+ implications of stacking various modules that will be installed
+ on the system and their respective orders and interactions.
+ The composition of various authentication modules should be
+ carefully examined. The trusted computing base of the machine
+ now includes the PAM modules.
+
+
+ 10. EXPERIENCE WITH PAM
+
+ The PAM framework was first added in Solaris 2.3 release as a private
+ internal interface. PAM is currently being used by several system
+ entry applications such as `login', `passwd', `su', `dtlogin',
+ `rlogind', `rshd', `telnetd', `ftpd', `in.rexecd', `uucpd', `init',
+ `sac', and `ttymon'. We have found that PAM provides an excellent
+ framework to encapsulate the authentication-related tasks for the
+ entire system. The Solaris 2.3 PAM API's were hence enhanced and
+ simplified to support stacking.
+
+ PAM modules have been developed for UNIX, DCE, Kerberos, S/Key,
+ remote user authentication, and dialpass authentication. Other PAM
+ modules are under development, and integration with smart cards is
+ being planned.
+
+ Some third parties have used the PAM interface to extend the security
+ mechanisms offered by the Solaris environment.
+
+
+
+
+ Samar, Schemers Page 16
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ The PAM API has been accepted by Common Desktop Environment (CDE)
+ vendors as the API to be used for integrating the graphical interface
+ for login, `dtlogin' with multiple authentication mechanisms.
+
+
+ 11. FUTURE WORK
+
+ Amongst the various components of PAM, the password component needs
+ to be carefully examined to see whether the stacking semantics are
+ particularly applicable, and how PAM should deal with partial
+ failures when changing passwords.
+
+ The _control_flag_ of the configuration file can be extended to
+ include other semantics. For example, if the error is "name service
+ not available", one may want to retry. It is also possible to offer
+ semantics of "return success if any of the modules return success".
+
+ In an earlier section, we had mentioned integration of smart cards
+ with PAM. Though we feel that integration should be straight forward
+ from the PAM architecture point of view, there may be some issues
+ with implementation because the interfaces to the smart cards have
+ not yet been standardized.
+
+ One possible extension to PAM is to allow the passing of module-
+ specific data between applications and PAM modules. For example, the
+ `login' program likes to build its new environment from a select list
+ of variables, yet the DCE module needs the `KRB5CCNAME' variable to
+ be exported to the child process. For now we have modified the
+ `login' program to explicitly export the `KRB5CCNAME' variable.
+
+ Administrative tools are needed to help system administrators modify
+ `pam.conf', and perform sanity checks on it (i.e., a `pam_check'
+ utility).
+
+
+ 12. CONCLUSION
+
+ The PAM framework and the module interfaces provide pluggability for
+ user authentication, as well as for account, session and password
+ management. The PAM architecture can be used by `login' and by all
+ other system-entry services, and thus ensure that all entry points
+ for the system have been secured. This architecture enables
+ replacement and modification of authentication modules in the field
+ to secure the system against the newly found weaknesses without
+ changing any of the system services.
+
+ The PAM framework can be used to integrate `login' and `dtlogin' with
+ different authentication mechanisms such as RSA and Kerberos.
+ Multiple authentication systems can be accessed with the same
+ password. The PAM framework also provides easy integration of smart
+ cards into the system.
+
+
+
+ Samar, Schemers Page 17
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ PAM provides complementary functionality to GSS-API, in that it
+ provides mechanisms through which the user gets authenticated to any
+ new system-level authentication service on the machine. GSS-API then
+ uses the credentials for authenticated and secure communications with
+ other application-level service entities on the network.
+
+
+ 13. ACKNOWLEDGEMENTS
+
+ PAM development has spanned several release cycles at SunSoft.
+ Shau-Ping Lo, Chuck Hickey, and Alex Choy did the first design and
+ implementation. Bill Shannon and Don Stephenson helped with the PAM
+ architecture. Rocky Wu prototyped stacking of multiple modules.
+ Paul Fronberg, Charlie Lai, and Roland Schemers made very significant
+ enhancements to the PAM interfaces and took the project to completion
+ within a very short time. Kathy Slattery wrote the PAM
+ documentation. John Perry integrated PAM within the CDE framework.
+
+
+ APPENDIX A. PAM API'S
+
+ This appendix gives an informal description of the various interfaces
+ of PAM. Since the goal here is just for the reader to get a working
+ knowledge about the PAM interfaces, not all flags and options have
+ been fully defined and explained. The API's described here are
+ subject to change.
+
+ The PAM Service Provider Interface is very similar to the PAM API,
+ except for one extra parameter to pass module-specific options to the
+ underlying modules.
+
+ A.1. Framework Layer API's
+
+ int
+ pam_start(
+ char *service_name,
+ char *user,
+ struct pam_conv *pam_conversation,
+ pam_handle_t **pamh
+ );
+
+ `pam_start()' is called to initiate an authentication transaction.
+ `pam_start()' takes as arguments the name of the service, the name of
+ the user to be authenticated, the address of the conversation
+ structure. `pamh' is later used as a handle for subsequent calls to
+ the PAM library.
+
+ The PAM modules do not communicate directly with the user; instead
+ they rely on the application to perform all such interaction. The
+ application needs to provide the conversation functions, `conv()',
+ and associated application data pointers through a `pam_conv'
+
+
+
+ Samar, Schemers Page 18
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ structure when it initiates an authentication transaction. The
+ module uses the `conv()' function to prompt the user for data,
+ display error messages, or text information.
+
+ int
+ pam_end(
+ pam_handle_t *pamh,
+ int pam_status
+ );
+
+ `pam_end()' is called to terminate the PAM transaction as specified
+ by `pamh', and to free any storage area allocated by the PAM modules
+ with `pam_set_item()'.
+
+ int
+ pam_set_item(
+ pam_handle_t *pamh,
+ int item_type,
+ void *item
+ );
+
+ int
+ pam_get_item(
+ pam_handle_t *pamh,
+ int item_type,
+ void **item);
+
+ `pam_get_item()' and `pam_set_item()' allow the parameters specified
+ in the initial call to `pam_start()' to be read and updated. This is
+ useful when a particular parameter is not available when
+ `pam_start()' is called or must be modified after the initial call to
+ `pam_start()'. `pam_set_item()' is passed a pointer to the object,
+ `item', and its type, `item_type'. `pam_get_item()' is passed the
+ address of the pointer, `item', which is assigned the address of the
+ requested object.
+
+ The `item_type' is one of the following:
+
+ Table 5: Possible Values for Item_type
+
+ Item Name Description
+ --------- -----------
+ PAM_SERVICE The service name
+ PAM_USER The user name
+ PAM_TTY The tty name
+ PAM_RHOST The remote host name
+ PAM_CONV The pam_conv structure
+ PAM_AUTHTOK The authentication token (password)
+ PAM_OLDAUTHTOK The old authentication token
+ PAM_RUSER The remote user name
+
+
+
+
+ Samar, Schemers Page 19
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ Note that the values of `PAM_AUTHTOK' and `PAM_OLDAUTHTOK' are only
+ available to PAM modules and not to the applications. They are
+ explicitly cleared out by the framework before returning to the
+ application.
+
+ char *
+ pam_strerror(
+ int errnum
+ );
+
+ `pam_strerror()' maps the error number to a PAM error message string,
+ and returns a pointer to that string.
+
+ int
+ pam_set_data(
+ pam_handle_t *pamh,
+ char *module_data_name,
+ char *data,
+ (*cleanup)(pam_handle_t *pamh, char *data,
+ int error_status)
+ );
+
+ The `pam_set_data()' function stores module specific data within the
+ PAM handle. The `module_data_name' uniquely specifies the name to
+ which some data and cleanup callback function can be attached. The
+ cleanup function is called when `pam_end()' is invoked.
+
+ int
+ pam_get_data(
+ pam_handle_t *pamh,
+ char *module_data_name,
+ void **datap
+ );
+
+ The `pam_get_data()' function obtains module-specific data from the
+ PAM handle stored previously by the `pam_get_data()' function. The
+ `module_data_name' uniquely specifies the name for which data has to
+ be obtained. This function is normally used to retrieve module
+ specific state information.
+
+ A.2. Authentication API's
+
+ int
+ pam_authenticate(
+ pam_handle_t *pamh,
+ int flags
+ );
+
+ The `pam_authenticate()' function is called to verify the identity of
+ the current user. The user is usually required to enter a password
+ or similar authentication token, depending upon the authentication
+
+
+
+ Samar, Schemers Page 20
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ module configured with the system. The user in question is specified
+ by a prior call to `pam_start()', and is referenced by the
+ authentication handle, `pamh'.
+
+ int
+ pam_setcred(
+ pam_handle_t *pamh,
+ int flags
+ );
+
+ The `pam_setcred()' function is called to set the credentials of the
+ current process associated with the authentication handle, `pamh'.
+ The actions that can be denoted through `flags' include credential
+ initialization, refresh, reinitialization and deletion.
+
+ A.3. Account Management API
+
+ int
+ pam_acct_mgmt(
+ pam_handle_t *pamh,
+ int flags
+ );
+
+ The function `pam_acct_mgmt()' is called to determine whether the
+ current user's account and password are valid. This typically
+ includes checking for password and account expiration, valid login
+ times, etc. The user in question is specified by a prior call to
+ `pam_start()', and is referenced by the authentication handle,
+ `pamh'.
+
+ A.4. Session Management API's
+
+ int
+ pam_open_session(
+ pam_handle_t *pamh,
+ int flags
+ );
+
+ `pam_open_session()' is called to inform the session modules that a
+ new session has been initialized. All programs which use PAM should
+ invoke `pam_open_session()' when beginning a new session.
+
+ int
+ pam_close_session(
+ pam_handle_t *pamh,
+ int flags
+ );
+
+ Upon termination of this session, the `pam_close_session()' function
+ should be invoked to inform the underlying modules that the session
+ has terminated.
+
+
+
+ Samar, Schemers Page 21
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ A.5. Password Management API's
+
+ int
+ pam_chauthtok(
+ pam_handle_t *pamh,
+ int flags
+ );
+
+ `pam_chauthtok()' is called to change the authentication token
+ associated with the user referenced by the authentication handle
+ `pamh'. After the call, the authentication token of the user will be
+ changed in accordance with the authentication module configured on
+ the system.
+
+
+ APPENDIX B. SAMPLE PAM APPLICATION
+
+ This appendix shows a sample `login' application which uses the PAM
+ API's. It is not meant to be a fully functional login program, as
+ some functionality has been left out in order to emphasize the use of
+ PAM API's.
+
+ #include <security/pam_appl.h>
+
+ static int login_conv(int num_msg, struct pam_message **msg,
+ struct pam_response **response, void *appdata_ptr);
+
+ static struct pam_conv pam_conv = {login_conv, NULL};
+
+ static pam_handle_t *pamh; /* Authentication handle */
+
+ void
+ main(int argc, char *argv[], char **renvp)
+ {
+
+ /*
+ * Call pam_start to initiate a PAM authentication operation
+ */
+
+ if ((pam_start("login", user_name, &pam_conv, &pamh))
+ != PAM_SUCCESS)
+ login_exit(1);
+
+ pam_set_item(pamh, PAM_TTY, ttyn);
+ pam_set_item(pamh, PAM_RHOST, remote_host);
+
+ while (!authenticated && retry < MAX_RETRIES) {
+ status = pam_authenticate(pamh, 0);
+ authenticated = (status == PAM_SUCCESS);
+ }
+
+
+
+
+ Samar, Schemers Page 22
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ if (status != PAM_SUCCESS) {
+ fprintf(stderr,"error: %s\n", pam_strerror(status));
+ login_exit(1);
+ }
+
+ /* now check if the authenticated user is allowed to login. */
+
+ if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
+ if (status == PAM_AUTHTOK_EXPIRED) {
+ status = pam_chauthtok(pamh, 0);
+ if (status != PAM_SUCCESS)
+ login_exit(1);
+ } else {
+ login_exit(1);
+ }
+ }
+
+ /*
+ * call pam_open_session to open the authenticated session
+ * pam_close_session gets called by the process that
+ * cleans up the utmp entry (i.e., init)
+ */
+ if (status = pam_open_session(pamh, 0) != PAM_SUCCESS) {
+ login_exit(status);
+ }
+
+ /* set up the process credentials */
+ setgid(pwd->pw_gid);
+
+ /*
+ * Initialize the supplementary group access list.
+ * This should be done before pam_setcred because
+ * the PAM modules might add groups during the pam_setcred call
+ */
+ initgroups(user_name, pwd->pw_gid);
+
+ status = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (status != PAM_SUCCESS) {
+ login_exit(status);
+ }
+
+ /* set the real (and effective) UID */
+ setuid(pwd->pw_uid);
+
+ pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
+
+ /*
+ * Add DCE/Kerberos cred name, if any.
+ * XXX - The module specific stuff should be removed from login
+ * program eventually. This is better placed in DCE module and
+ * will be once PAM has routines for "exporting" environment
+
+
+
+ Samar, Schemers Page 23
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ * variables.
+ */
+ krb5p = getenv("KRB5CCNAME");
+ if (krb5p != NULL) {
+ ENVSTRNCAT(krb5ccname, krb5p);
+ envinit[basicenv++] = krb5ccname;
+ }
+ environ = envinit; /* Switch to the new environment. */
+ exec_the_shell();
+
+ /* All done */
+ }
+
+ /*
+ * login_exit - Call exit() and terminate.
+ * This function is here for PAM so cleanup can
+ * be done before the process exits.
+ */
+ static void
+ login_exit(int exit_code)
+ {
+ if (pamh)
+ pam_end(pamh, PAM_ABORT);
+ exit(exit_code);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * login_conv():
+ * This is the conv (conversation) function called from
+ * a PAM authentication module to print error messages
+ * or garner information from the user.
+ */
+
+ static int
+ login_conv(int num_msg, struct pam_message **msg,
+ struct pam_response **response, void *appdata_ptr)
+ {
+
+ while (num_msg--) {
+ switch (m->msg_style) {
+
+ case PAM_PROMPT_ECHO_OFF:
+ r->resp = strdup(getpass(m->msg));
+ break;
+
+ case PAM_PROMPT_ECHO_ON:
+ (void) fputs(m->msg, stdout);
+ r->resp = malloc(PAM_MAX_RESP_SIZE);
+ fgets(r->resp, PAM_MAX_RESP_SIZE, stdin);
+ /* add code here to remove \n from fputs */
+
+
+
+ Samar, Schemers Page 24
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ break;
+
+ case PAM_ERROR_MSG:
+ (void) fputs(m->msg, stderr);
+ break;
+
+ case PAM_TEXT_INFO:
+ (void) fputs(m->msg, stdout);
+ break;
+
+ default:
+ /* add code here to log error message, etc */
+ break;
+ }
+ }
+ return (PAM_SUCCESS);
+ }
+
+
+ APPENDIX C. DCE MODULE
+
+ This appendix describes a sample implementation of a DCE PAM module.
+ In order to simplify the description, we do not address the issues
+ raised by password-mapping or stacking. The intent is to show which
+ DCE calls are being made by the DCE module.
+
+ The `pam_sm_*()' functions implement the PAM SPI functions which are
+ called from the PAM API functions.
+
+ C.1. DCE Authentication Management
+
+ The algorithm for authenticating with DCE (not including error
+ checking, prompting for passwords, etc.) is as follows:
+
+ pam_sm_authenticate()
+ {
+ sec_login_setup_identity(...);
+ pam_set_data(...);
+ sec_login_valid_and_cert_ident(...);
+ }
+
+ pam_sm_setcred()
+ {
+ pam_get_data(...);
+ sec_login_set_context(...);
+ }
+
+ The `pam_sm_authenticate()' function for DCE uses the
+ `pam_set_data()' and `pam_get_data()' functions to keep state (like
+ the `sec_login_handle_t' context) between calls. The following
+ cleanup function is also registered and gets called when `pam_end()'
+
+
+
+ Samar, Schemers Page 25
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ is called:
+
+ dce_cleanup()
+ {
+ if (/* PAM_SUCCESS and
+ sec_login_valid_and_cert_ident success */) {
+ sec_login_release_context(...);
+ } else {
+ sec_login_purge_context(...);
+ }
+ }
+
+ If everything was successful we release the login context, but leave
+ the credentials file intact. If the status passed to `pam_end()' was
+ not `PAM_SUCCESS' (i.e., a required module failed) we purge the login
+ context which also removes the credentials file.
+
+ C.2. DCE Account Management
+
+ The algorithm for DCE account management is as follows:
+
+ pam_sm_acct_mgmt()
+ {
+ pam_get_data(...);
+ sec_login_inquire_net_info(...);
+ /* check for expired password and account */
+ sec_login_free_net_info(...);
+ }
+
+ The `sec_login_inquire_net_info()' function is called to obtain
+ information about when the user's account and/or password are going
+ to expire. A warning message is displayed (using the conversation
+ function) if the user's account or password is going to expire in the
+ near future, or has expired. These warning messages can be disabled
+ using the `nowarn' option in the `pam.conf' file.
+
+ C.3. DCE Session Management
+
+ The DCE session management functions are currently empty. They could
+ be modified to optionally remove the DCE credentials file upon
+ logout, etc.
+
+ C.4. DCE Password Management
+
+ The algorithm for DCE password management is as follows:
+
+
+
+
+
+
+
+
+
+ Samar, Schemers Page 26
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ pam_sm_chauthtok
+ {
+ sec_rgy_site_open(...);
+ sec_rgy_acct_lookup(...);
+ sec_rgy_acct_passwd(...);
+ sec_rgy_site_close(...);
+ }
+
+ The `sec_rgy_acct_passwd()' function is called to change the user's
+ password in the DCE registry.
+
+
+ REFERENCES
+
+ [Adamson 95] W. A. Adamson, J. Rees, and P. Honeyman, "Joining
+ Security Realms: A Single Login for Netware and
+ Kerberos", CITI Technical Report 95-1, Center for
+ Information Technology Integration, University of
+ Michigan, Ann Arbor, MI, February 1995.
+
+ [Diffie 76] W. Diffie and M. E. Hellman, "New Directions in
+ Cryptography", IEEE Transactions on Information
+ Theory, November 1976.
+
+ [Linn 93] J. Linn, "Generic Security Service Application
+ Programming Interface", Internet RFC 1508, 1509, 1993.
+
+ [Rivest 78] R. L. Rivest, A. Shamir, and L. Adleman., "A Method
+ for Obtaining Digital Signatures and Pubic-key
+ Cryptosystems", Communications of the ACM, 21(2),
+ 1978.
+
+ [SIA 95] "Digital UNIX Security", Digital Equipment
+ Corporation, Order Number AA-Q0R2C-TE, July 1995.
+
+ [Skey 94] N. M. Haller, "The S/Key One-Time Password System",
+ ISOC Symposium on Network and Distributed Security,
+ 1994.
+
+ [Steiner 88] J.G. Steiner, B. C. Neuman, and J. I. Schiller,
+ "Kerberos, An Authentication Service for Open Network
+ Systems", in Proceedings of the Winter USENIX
+ Conference, Dallas, Jan 1988.
+
+ [Taylor 88] B. Taylor and D. Goldberg, "Secure Networking in the
+ Sun Environment", Sun Microsystems Technical Paper,
+ 1988.
+
+ [XFN 94] "Federated Naming: the XFN Specifications", X/Open
+ Preliminary Specification, X/Open Document #P403,
+ ISBN:1-85912-045-8, X/Open Co. Ltd., July 1994.
+
+
+
+ Samar, Schemers Page 27
+
+
+
+
+
+
+
+ OSF-RFC 86.0 PAM October 1995
+
+
+
+ AUTHOR'S ADDRESS
+
+ Vipin Samar Internet email: vipin@eng.sun.com
+ SunSoft, Inc. Telephone: +1-415-336-1002
+ 2550 Garcia Avenue
+ Mountain View, CA 94043
+ USA
+
+ Roland J. Schemers III Internet email: schemers@eng.sun.com
+ SunSoft, Inc. Telephone: +1-415-336-1035
+ 2550 Garcia Avenue
+ Mountain View, CA 94043
+ USA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Samar, Schemers Page 28
+
+
+
+
+
+
diff --git a/contrib/libpam/doc/txts/README b/contrib/libpam/doc/txts/README
new file mode 100644
index 000000000000..b62bc2d7448a
--- /dev/null
+++ b/contrib/libpam/doc/txts/README
@@ -0,0 +1,3 @@
+$Id: README,v 1.1 1996/11/10 19:18:06 morgan Exp $
+
+This is a directory for text versions of the pam documentation
diff --git a/contrib/libpam/examples/Makefile b/contrib/libpam/examples/Makefile
new file mode 100644
index 000000000000..063f24d0df03
--- /dev/null
+++ b/contrib/libpam/examples/Makefile
@@ -0,0 +1,42 @@
+#
+# $Id: Makefile,v 1.10 1996/11/10 19:50:59 morgan Exp $
+#
+
+dummy:
+
+ @echo "*** This is not a top level Makefile!"
+
+PROGS = blank xsh check_user
+SRCS = blank.c xsh.c check_user.c
+
+# have removed the following pair since they no longer conform to
+# any recognized conventions: vpass test
+# ditto: vpass.c test.c
+
+PROGSUID =
+
+all: $(PROGS)
+
+check_user: check_user.o
+ $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES)
+
+blank: blank.o
+ $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES)
+
+xsh: xsh.o
+ $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES)
+
+install: all
+ if [ -n "$(PROGS)" ]; then cp $(PROGS) ../bin ; fi
+ if [ -n "$(PROGSUID)" ]; then \
+ $(INSTALL) -m 4555 -o root -g bin $(PROGSUID) ../bin ; fi
+
+clean:
+ rm -f *.a *.so *.o *~ $(PROGS) $(PROGSUID)
+
+remove:
+ cd ../bin ; rm -f $(PROGS) $(PROGSUID)
+
+extraclean: clean
+ rm -f *.a *.out *.o *.so
+ for x in $(PROGS) $(PROGSUID) ; do rm -f ../bin/$$x ; done
diff --git a/contrib/libpam/examples/blank.c b/contrib/libpam/examples/blank.c
new file mode 100644
index 000000000000..3808e5589f80
--- /dev/null
+++ b/contrib/libpam/examples/blank.c
@@ -0,0 +1,173 @@
+/*
+ * $Id: blank.c,v 1.7 1996/12/01 03:16:53 morgan Exp morgan $
+ *
+ * $Log: blank.c,v $
+ * Revision 1.7 1996/12/01 03:16:53 morgan
+ * added setcred closing function
+ *
+ * Revision 1.6 1996/11/10 19:51:40 morgan
+ * minor change to avoid gcc warning
+ *
+ * Revision 1.5 1996/07/07 23:53:05 morgan
+ * added optional fail delay (non-standard Linux-PAM)
+ *
+ * Revision 1.4 1996/05/02 04:44:18 morgan
+ * moved conversation to a libmisc library routine.
+ *
+ *
+ */
+
+/* Andrew Morgan (morgan@parc.power.net) -- a self contained `blank'
+ * application
+ *
+ * I am not very proud of this code. It makes use of a possibly ill-
+ * defined pamh pointer to call pam_strerror() with. The reason that
+ * I was sloppy with this is historical (pam_strerror, prior to 0.59,
+ * did not require a pamh argument) and if this program is used as a
+ * model for anything, I should wish that you will take this error into
+ * account.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+/* ------ some local (static) functions ------- */
+
+static void bail_out(pam_handle_t *pamh, int really, int code, const char *fn)
+{
+ fprintf(stderr,"==> called %s()\n got: `%s'\n", fn,
+ pam_strerror(pamh, code));
+ if (really && code)
+ exit (1);
+}
+
+/* ------ some static data objects ------- */
+
+static struct pam_conv conv = {
+ misc_conv,
+ NULL
+};
+
+/* ------- the application itself -------- */
+
+void main(int argc, char **argv)
+{
+ pam_handle_t *pamh=NULL;
+ char *username=NULL;
+ int retcode;
+
+ /* did the user call with a username as an argument ? */
+
+ if (argc > 2) {
+ fprintf(stderr,"usage: %s [username]\n",argv[0]);
+ } else if (argc == 2) {
+ username = argv[1];
+ }
+
+ /* initialize the Linux-PAM library */
+ retcode = pam_start("blank", username, &conv, &pamh);
+ bail_out(pamh,1,retcode,"pam_start");
+
+ /* test the environment stuff */
+ {
+#define MAXENV 15
+ const char *greek[MAXENV] = {
+ "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon",
+ "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu",
+ "l=zeta", "h=", "d", "k=xi"
+ };
+ char **env;
+ int i;
+
+ for (i=0; i<MAXENV; ++i) {
+ retcode = pam_putenv(pamh,greek[i]);
+ bail_out(pamh,0,retcode,"pam_putenv");
+ }
+ env = pam_getenvlist(pamh);
+ if (env)
+ env = pam_misc_drop_env(env);
+ else
+ fprintf(stderr,"???\n");
+ fprintf(stderr,"a test: c=[%s], j=[%s]\n"
+ , pam_getenv(pamh, "c"), pam_getenv(pamh, "j"));
+ }
+
+ /* to avoid using goto we abuse a loop here */
+ for (;;) {
+ /* authenticate the user --- `0' here, could have been PAM_SILENT
+ * | PAM_DISALLOW_NULL_AUTHTOK */
+
+ retcode = pam_authenticate(pamh, 0);
+ bail_out(pamh,0,retcode,"pam_authenticate");
+
+ /* has the user proved themself valid? */
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: invalid request\n",argv[0]);
+ break;
+ }
+
+ /* the user is valid, but should they have access at this
+ time? */
+
+ retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */
+ bail_out(pamh,0,retcode,"pam_acct_mgmt");
+
+ if (retcode == PAM_NEW_AUTHTOK_REQD) {
+ fprintf(stderr,"Application must request new password...\n");
+ retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK);
+ bail_out(pamh,0,retcode,"pam_chauthtok");
+ }
+
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: invalid request\n",argv[0]);
+ break;
+ }
+
+ /* `0' could be as above */
+ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ bail_out(pamh,0,retcode,"pam_setcred1");
+
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: problem setting user credentials\n"
+ ,argv[0]);
+ break;
+ }
+
+ /* open a session for the user --- `0' could be PAM_SILENT */
+ retcode = pam_open_session(pamh,0);
+ bail_out(pamh,0,retcode,"pam_open_session");
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: problem opening a session\n",argv[0]);
+ break;
+ }
+
+ fprintf(stderr,"The user has been authenticated and `logged in'\n");
+
+ /* close a session for the user --- `0' could be PAM_SILENT
+ * it is possible that this pam_close_call is in another program..
+ */
+
+ retcode = pam_close_session(pamh,0);
+ bail_out(pamh,0,retcode,"pam_close_session");
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: problem closing a session\n",argv[0]);
+ break;
+ }
+
+ retcode = pam_setcred(pamh, PAM_DELETE_CRED);
+ bail_out(pamh,0,retcode,"pam_setcred2");
+
+ break; /* don't go on for ever! */
+ }
+
+ /* close the Linux-PAM library */
+ retcode = pam_end(pamh, PAM_SUCCESS);
+ pamh = NULL;
+
+ bail_out(pamh,1,retcode,"pam_end");
+
+ exit(0);
+}
diff --git a/contrib/libpam/examples/check_user.c b/contrib/libpam/examples/check_user.c
new file mode 100644
index 000000000000..6a64c22d7ad9
--- /dev/null
+++ b/contrib/libpam/examples/check_user.c
@@ -0,0 +1,65 @@
+/*
+ $Id: check_user.c,v 1.1 1996/11/10 21:19:30 morgan Exp morgan $
+
+ This program was contributed by Shane Watts <shane@icarus.bofh.asn.au>
+ slight modifications by AGM.
+
+ You need to add the following (or equivalent) to the /etc/pam.conf file.
+ # check authorization
+ check auth required pam_unix_auth.so
+ check account required pam_unix_acct.so
+
+ $Log: check_user.c,v $
+ Revision 1.1 1996/11/10 21:19:30 morgan
+ Initial revision
+
+ */
+
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#include <stdio.h>
+
+static struct pam_conv conv = {
+ misc_conv,
+ NULL
+};
+
+int main(int argc, char *argv[])
+{
+ pam_handle_t *pamh=NULL;
+ int retval;
+ const char *user="nobody";
+
+ if(argc == 2) {
+ user = argv[1];
+ }
+
+ if(argc > 2) {
+ fprintf(stderr, "Usage: check_user [username]\n");
+ exit(1);
+ }
+
+ retval = pam_start("check", user, &conv, &pamh);
+
+ if (retval == PAM_SUCCESS)
+ retval = pam_authenticate(pamh, 0); /* is user really user? */
+
+ if (retval == PAM_SUCCESS)
+ retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
+
+ /* This is where we have been authorized or not. */
+
+ if (retval == PAM_SUCCESS) {
+ fprintf(stdout, "Authenticated\n");
+ } else {
+ fprintf(stdout, "Not Authenticated\n");
+ }
+
+ if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
+ pamh = NULL;
+ fprintf(stderr, "check_user: failed to release authenticator\n");
+ exit(1);
+ }
+
+ return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */
+}
diff --git a/contrib/libpam/examples/test.c b/contrib/libpam/examples/test.c
new file mode 100644
index 000000000000..0a1f5a6168fb
--- /dev/null
+++ b/contrib/libpam/examples/test.c
@@ -0,0 +1,99 @@
+/*
+ * $Log: test.c,v $
+ * Revision 1.3 1996/03/10 00:14:20 morgan
+ * made lines less than 80 chars long.
+ *
+ * Revision 1.2 1996/03/09 09:16:26 morgan
+ * changed the header file that it includes.
+ *
+ * Revision 1.1 1996/03/09 09:13:34 morgan
+ * Initial revision
+ */
+
+/* Marc Ewing (marc@redhat.com) - original test code
+ * Alexander O. Yuriev (alex@bach.cis.temple.edu)
+ * Andrew Morgan (morgan@physics.ucla.edu)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+
+#include <security/pam_appl.h>
+
+/* this program is not written to the PAM spec: it tests the
+ * pam_[sg]et_data() functions. Which is usually reserved for modules */
+
+#include <security/pam_modules.h>
+#include <security/pam_misc.h>
+
+#define USERNAMESIZE 1024
+
+static int test_conv( int num_msg,
+ const struct pam_message **msgm,
+ struct pam_response **response,
+ void *appdata_ptr )
+{
+ return 0;
+}
+
+static struct pam_conv conv = {
+ test_conv,
+ NULL
+};
+
+static int cleanup_func(pam_handle_t *pamh, void *data, int error_status)
+{
+ printf("Cleaning up!\n");
+ return PAM_SUCCESS;
+}
+
+void main( void )
+{
+ pam_handle_t *pamh;
+ char *name = ( char *) malloc( USERNAMESIZE + 1 );
+ char *p = NULL;
+ char *s = NULL;
+
+ if (! name )
+ {
+ perror( "Ouch, don't have enough memory");
+ exit( -1 );
+ }
+
+
+
+
+ fprintf( stdout, "Enter a name of a user to authenticate : ");
+ name = fgets( name , USERNAMESIZE, stdin );
+ if ( !name )
+ {
+ perror ( "Hey, how can authenticate "
+ "someone whos name I don't know?" );
+ exit ( -1 );
+ }
+
+ *( name + strlen ( name ) - 1 ) = 0;
+
+ pam_start( "login", name, &conv, &pamh );
+
+ p = x_strdup( getpass ("Password: ") );
+ if ( !p )
+ {
+ perror ( "You love NULL pointers, "
+ "don't you? I don't ");
+ exit ( -1 );
+ }
+ pam_set_item ( pamh, PAM_AUTHTOK, p );
+ pam_get_item ( pamh, PAM_USER, (void**) &s);
+ pam_set_data(pamh, "DATA", "Hi there! I'm data!", cleanup_func);
+ pam_get_data(pamh, "DATA", (void **) &s);
+ printf("%s\n", s);
+
+ fprintf( stdout, "*** Attempting to perform "
+ "PAM authentication...\n");
+ fprintf( stdout, "%s\n",
+ pam_strerror( pam_authenticate( pamh, 0 ) ) ) ;
+
+ pam_end(pamh, PAM_SUCCESS);
+}
diff --git a/contrib/libpam/examples/vpass.c b/contrib/libpam/examples/vpass.c
new file mode 100644
index 000000000000..617a5f2e8241
--- /dev/null
+++ b/contrib/libpam/examples/vpass.c
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <security/pam_appl.h>
+
+static int test_conv(int num_msg, const struct pam_message **msgm,
+ struct pam_response **response, void *appdata_ptr)
+{
+ return 0;
+}
+
+static struct pam_conv conv = {
+ test_conv,
+ NULL
+};
+
+int main(void)
+{
+ char *user;
+ pam_handle_t *pamh;
+ struct passwd *pw;
+ uid_t uid;
+ int res;
+
+ uid = geteuid();
+ pw = getpwuid(uid);
+ if (pw) {
+ user = pw->pw_name;
+ } else {
+ fprintf(stderr, "Invalid userid: %d\n", uid);
+ exit(1);
+ }
+
+ pam_start("vpass", user, &conv, &pamh);
+ pam_set_item(pamh, PAM_TTY, "/dev/tty");
+ if ((res = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
+ fprintf(stderr, "Oops: %s\n", pam_strerror(res));
+ exit(1);
+ }
+
+ pam_end(pamh, res);
+ exit(0);
+}
+
+
diff --git a/contrib/libpam/examples/xsh.c b/contrib/libpam/examples/xsh.c
new file mode 100644
index 000000000000..ad134f6217ba
--- /dev/null
+++ b/contrib/libpam/examples/xsh.c
@@ -0,0 +1,139 @@
+/*
+ * $Id: xsh.c,v 1.4 1996/11/10 21:09:45 morgan Exp morgan $
+ *
+ * $Log: xsh.c,v $
+ * Revision 1.4 1996/11/10 21:09:45 morgan
+ * no gcc warnings
+ *
+ * Revision 1.3 1996/07/07 23:53:36 morgan
+ * added support for non standard pam_fail_delay
+ *
+ * Revision 1.2 1996/05/02 04:44:48 morgan
+ * moved conversaation to a libmisc routine.
+ *
+ * Revision 1.1 1996/04/07 08:18:55 morgan
+ * Initial revision
+ *
+ */
+
+/* Andrew Morgan (morgan@parc.power.net) -- an example application
+ * that invokes a shell, based on blank.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+/* ------ some local (static) functions ------- */
+
+static void bail_out(pam_handle_t *pamh,int really, int code, const char *fn)
+{
+ fprintf(stderr,"==> called %s()\n got: `%s'\n", fn,
+ pam_strerror(pamh,code));
+ if (really && code)
+ exit (1);
+}
+
+/* ------ some static data objects ------- */
+
+static struct pam_conv conv = {
+ misc_conv,
+ NULL
+};
+
+/* ------- the application itself -------- */
+
+void main(int argc, char **argv, char **envp)
+{
+ pam_handle_t *pamh=NULL;
+ char *username=NULL;
+ int retcode;
+
+ /* did the user call with a username as an argument ? */
+
+ if (argc > 2) {
+ fprintf(stderr,"usage: %s [username]\n",argv[0]);
+ } else if (argc == 2) {
+ username = argv[1];
+ }
+
+ /* initialize the Linux-PAM library */
+ retcode = pam_start("xsh", username, &conv, &pamh);
+ bail_out(pamh,1,retcode,"pam_start");
+
+ /* to avoid using goto we abuse a loop here */
+ for (;;) {
+ /* authenticate the user --- `0' here, could have been PAM_SILENT
+ * | PAM_DISALLOW_NULL_AUTHTOK */
+
+ retcode = pam_authenticate(pamh, 0);
+ bail_out(pamh,0,retcode,"pam_authenticate");
+
+ /* has the user proved themself valid? */
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: invalid request\n",argv[0]);
+ break;
+ }
+
+ /* the user is valid, but should they have access at this
+ time? */
+
+ retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */
+ bail_out(pamh,0,retcode,"pam_acct_mgmt");
+
+ if (retcode == PAM_NEW_AUTHTOK_REQD) {
+ fprintf(stderr,"Application must request new password...\n");
+ retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK);
+ bail_out(pamh,0,retcode,"pam_chauthtok");
+ }
+
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: invalid request\n",argv[0]);
+ break;
+ }
+
+ /* `0' could be as above */
+ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ bail_out(pamh,0,retcode,"pam_setcred");
+
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: problem setting user credentials\n"
+ ,argv[0]);
+ break;
+ }
+
+ /* open a session for the user --- `0' could be PAM_SILENT */
+ retcode = pam_open_session(pamh,0);
+ bail_out(pamh,0,retcode,"pam_open_session");
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: problem opening a session\n",argv[0]);
+ break;
+ }
+
+ fprintf(stderr,"The user has been authenticated and `logged in'\n");
+
+ /* this is always a really bad thing for security! */
+ system("/bin/sh");
+
+ /* close a session for the user --- `0' could be PAM_SILENT
+ * it is possible that this pam_close_call is in another program..
+ */
+
+ retcode = pam_close_session(pamh,0);
+ bail_out(pamh,0,retcode,"pam_close_session");
+ if (retcode != PAM_SUCCESS) {
+ fprintf(stderr,"%s: problem closing a session\n",argv[0]);
+ break;
+ }
+
+ break; /* don't go on for ever! */
+ }
+
+ /* close the Linux-PAM library */
+ retcode = pam_end(pamh, PAM_SUCCESS);
+ pamh = NULL;
+ bail_out(pamh,1,retcode,"pam_end");
+
+ exit(0);
+}
diff --git a/contrib/libpam/libpam/Makefile b/contrib/libpam/libpam/Makefile
new file mode 100644
index 000000000000..f3914a478b9a
--- /dev/null
+++ b/contrib/libpam/libpam/Makefile
@@ -0,0 +1,177 @@
+#
+# $Id: Makefile,v 1.19 1997/04/05 06:58:43 morgan Exp morgan $
+#
+# $Log: Makefile,v $
+# Revision 1.19 1997/04/05 06:58:43 morgan
+# fakeroot
+#
+# Revision 1.18 1997/02/15 15:56:09 morgan
+# inherit major and minor numbers
+#
+# Revision 1.17 1997/01/04 20:03:09 morgan
+# update for .55
+#
+# Revision 1.16 1996/12/01 03:14:13 morgan
+# update for .54
+#
+# Revision 1.15 1996/11/10 20:07:51 morgan
+# updated for .53
+#
+# Revision 1.14 1996/09/05 06:06:53 morgan
+# added local flag for locking, slight reorganization too.
+#
+
+# need to tell libpam about the default directory for PAMs
+MOREFLAGS=-D"DEFAULT_MODULE_PATH=\"$(SECUREDIR)/\""
+
+# you may uncomment the following to build libpam in modified ways
+
+# lots of debugging information goes to /tmp/pam-debug.log
+#MOREFLAGS += -D"DEBUG"
+
+# pay attention to locked /etc/pam.conf or /etc/pam.d/* files
+#MOREFLAGS += -D"PAM_LOCKING"
+
+# read both the /etc/pam.d/ and pam.conf files specific to the deisred service
+#MOREFLAGS += -D"PAM_READ_BOTH_CONFS"
+
+# make a kludge attempt to be compatible with the old pam_strerror
+# calling convention
+#MOREFLAGS += -D"UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT"
+
+ifeq ($(DEBUG_REL),yes)
+ LIBNAME=libpamd
+else
+ LIBNAME=libpam
+endif
+VERSION=.$(MAJOR_REL)
+MODIFICATION=.$(MINOR_REL)
+
+# ---------------------------------------------
+
+dummy:
+ @echo "*** This is not a top-level Makefile!"
+
+# ---------------------------------------------
+
+CFLAGS += $(DYNAMIC) $(STATIC) $(MOREFLAGS)
+
+# dynamic library names
+
+LIBPAM = $(LIBNAME).$(DYNTYPE)
+LIBPAMNAME = $(LIBPAM)$(VERSION)
+LIBPAMFULL = $(LIBPAMNAME)$(MODIFICATION)
+
+# static library name
+
+LIBPAMSTATIC = $(LIBNAME).a
+
+ifdef STATIC
+MODULES = $(shell cat ../modules/_static_module_objects)
+STATICOBJ = pam_static.o
+endif
+
+ifdef MEMORY_DEBUG
+EXTRAS += pam_malloc.o
+endif
+
+LIBOBJECTS = pam_item.o pam_strerror.o pam_end.o pam_start.o pam_data.o \
+ pam_delay.o pam_dispatch.o pam_handlers.o pam_misc.o \
+ pam_account.o pam_auth.o pam_session.o pam_password.o \
+ pam_env.o pam_log.o $(EXTRAS)
+
+ifdef DYNAMIC_LIBPAM
+DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS) $(STATICOBJ))
+ifdef STATICOBJ
+dynamic/pam_static.o: pam_static.c ../modules/_static_module_objects
+ $(CC) $(CFLAGS) -c pam_static.c -o $@
+endif
+endif
+
+ifdef STATIC_LIBPAM
+SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ))
+ifdef STATICOBJ
+static/pam_static.o: pam_static.c ../modules/_static_module_objects
+ $(CC) $(CFLAGS) -c pam_static.c -o $@
+endif
+endif
+
+# ---------------------------------------------
+## rules
+
+all: dirs $(LIBPAM) $(LIBPAMSTATIC)
+
+dirs:
+ifdef DYNAMIC_LIBPAM
+ mkdir -p dynamic
+endif
+ifdef STATIC_LIBPAM
+ mkdir -p static
+endif
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+$(LIBPAM): $(DLIBOBJECTS)
+ifdef DYNAMIC_LIBPAM
+ ifeq ($(USESONAME),yes)
+ $(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) $(MODULES)
+ else
+ $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
+ endif
+ ifeq ($(NEEDSONAME),yes)
+ rm -f $(LIBPAMFULL)
+ ln -s $(LIBPAM) $(LIBPAMFULL)
+ rm -f $(LIBPAMNAME)
+ ln -s $(LIBPAM) $(LIBPAMNAME)
+ endif
+endif
+
+$(LIBPAMSTATIC): $(SLIBOBJECTS)
+ifdef STATIC_LIBPAM
+ $(AR) $@ $(SLIBOBJECTS) $(MODULES)
+ $(RANLIB) $@
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/pam_appl.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/pam_modules.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/_pam_macros.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/_pam_types.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/_pam_compat.h $(FAKEROOT)$(INCLUDED)
+ifdef MEMORY_DEBUG
+ $(INSTALL) -m 644 include/security/pam_malloc.h $(FAKEROOT)$(INCLUDED)
+endif
+ifdef DYNAMIC_LIBPAM
+ $(INSTALL) -m $(SHLIBMODE) $(LIBPAM) $(FAKEROOT)$(LIBDIR)/$(LIBPAMFULL)
+ $(LDCONFIG)
+ ifneq ($(DYNTYPE),"sl")
+ ( cd $(FAKEROOT)$(LIBDIR) ; rm -f $(LIBPAM) ; ln -s $(LIBPAMNAME) $(LIBPAM) )
+ endif
+endif
+ifdef STATIC_LIBPAM
+ $(INSTALL) -m 644 $(LIBPAMSTATIC) $(FAKEROOT)$(LIBDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(INCLUDED)/_pam_types.h
+ rm -f $(FAKEROOT)$(INCLUDED)/_pam_macros.h
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_appl.h
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_modules.h
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_malloc.h
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAM).*
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAM)
+ $(LDCONFIG)
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAMSTATIC)
+
+clean:
+ rm -f a.out core *~ static/*.o dynamic/*.o
+
+extraclean: clean
+ rm -f *.a *.out *.o *.so ./include/security/*~
+ if [ -d dynamic ]; then rmdir dynamic ; fi
+ if [ -d static ]; then rmdir static ; fi
diff --git a/contrib/libpam/libpam/include/security/_pam_compat.h b/contrib/libpam/libpam/include/security/_pam_compat.h
new file mode 100644
index 000000000000..acfc59231af0
--- /dev/null
+++ b/contrib/libpam/libpam/include/security/_pam_compat.h
@@ -0,0 +1,109 @@
+#ifndef _PAM_COMPAT_H
+#define _PAM_COMPAT_H
+
+/*
+ * This file was contributed by Derrick J Brashear <shadow@dementia.org>
+ *
+ * A number of operating systems have started to implement PAM.
+ * unfortunately, they have a different set of numeric values for
+ * certain constants. This file is included for compatibility's sake.
+ */
+
+/* Solaris uses different constants. We redefine to those here */
+#if defined(solaris) || (defined(__SVR4) && defined(sun))
+
+/* generic for pam_* functions */
+# undef PAM_SILENT
+# define PAM_SILENT 0x80000000
+
+/* flags for pam_chauthtok() */
+# undef PAM_PRELIM_CHECK
+# define PAM_PRELIM_CHECK 0x1
+
+# undef PAM_UPDATE_AUTHTOK
+# define PAM_UPDATE_AUTHTOK 0x2
+
+/* flags for pam_setcred() */
+# undef PAM_ESTABLISH_CRED
+# define PAM_ESTABLISH_CRED 0x1
+
+# undef PAM_DELETE_CRED
+# define PAM_DELETE_CRED 0x2
+
+# undef PAM_REINITIALIZE_CRED
+# define PAM_REINITIALIZE_CRED 0x4
+
+# define PAM_REFRESH_CRED 0x8
+# undef PAM_REFRESH_CRED
+
+/* another binary incompatibility comes from the return codes! */
+
+# undef PAM_CONV_ERR
+# define PAM_CONV_ERR 6
+
+# undef PAM_PERM_DENIED
+# define PAM_PERM_DENIED 7
+
+# undef PAM_MAXTRIES
+# define PAM_MAXTRIES 8
+
+# undef PAM_AUTH_ERR
+# define PAM_AUTH_ERR 9
+
+# undef PAM_NEW_AUTHTOK_REQD
+# define PAM_NEW_AUTHTOK_REQD 10
+
+# undef PAM_CRED_INSUFFICIENT
+# define PAM_CRED_INSUFFICIENT 11
+
+# undef PAM_AUTHINFO_UNAVAIL
+# define PAM_AUTHINFO_UNAVAIL 12
+
+# undef PAM_USER_UNKNOWN
+# define PAM_USER_UNKNOWN 13
+
+# undef PAM_CRED_UNAVAIL
+# define PAM_CRED_UNAVAIL 14
+
+# undef PAM_CRED_EXPIRED
+# define PAM_CRED_EXPIRED 15
+
+# undef PAM_CRED_ERR
+# define PAM_CRED_ERR 16
+
+# undef PAM_ACCT_EXPIRED
+# define PAM_ACCT_EXPIRED 17
+
+# undef PAM_AUTHTOK_EXPIRED
+# define PAM_AUTHTOK_EXPIRED 18
+
+# undef PAM_SESSION_ERR
+# define PAM_SESSION_ERR 19
+
+# undef PAM_AUTHTOK_ERR
+# define PAM_AUTHTOK_ERR 20
+
+# undef PAM_AUTHTOK_RECOVERY_ERR
+# define PAM_AUTHTOK_RECOVERY_ERR 21
+
+# undef PAM_AUTHTOK_LOCK_BUSY
+# define PAM_AUTHTOK_LOCK_BUSY 22
+
+# undef PAM_AUTHTOK_DISABLE_AGING
+# define PAM_AUTHTOK_DISABLE_AGING 23
+
+# undef PAM_NO_MODULE_DATA
+# define PAM_NO_MODULE_DATA 24
+
+# undef PAM_IGNORE
+# define PAM_IGNORE 25
+
+# undef PAM_ABORT
+# define PAM_ABORT 26
+
+# undef PAM_TRY_AGAIN
+# define PAM_TRY_AGAIN 27
+
+#endif /* defined(solaris) || (defined(__SVR4) && defined(sun)) */
+
+#endif /* _PAM_COMPAT_H */
diff --git a/contrib/libpam/libpam/include/security/_pam_macros.h b/contrib/libpam/libpam/include/security/_pam_macros.h
new file mode 100644
index 000000000000..b033aa63fab6
--- /dev/null
+++ b/contrib/libpam/libpam/include/security/_pam_macros.h
@@ -0,0 +1,165 @@
+#ifndef PAM_MACROS_H
+#define PAM_MACROS_H
+
+/*
+ * All kind of macros used by PAM, but usable in some other
+ * programs too.
+ * Organized by Cristian Gafton <gafton@redhat.com>
+ */
+
+/* a 'safe' version of strdup */
+
+extern char *strdup(const char *s);
+#define x_strdup(s) ( (s) ? strdup(s):NULL )
+
+/* Good policy to strike out passwords with some characters not just
+ free the memory */
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) \
+do { \
+ if (X) { \
+ free(X); \
+ X=NULL; \
+ } \
+} while (0)
+
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+/* some debugging code */
+
+#ifdef DEBUG
+
+/*
+ * This provides the necessary function to do debugging in PAM.
+ * Cristian Gafton <gafton@redhat.com>
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/*
+ * This is for debugging purposes ONLY. DO NOT use on live systems !!!
+ * You have been warned :-) - CG
+ *
+ * to get automated debugging to the log file, it must be created manually.
+ * _PAM_LOGFILE must exist, mode 666
+ */
+
+#ifndef _PAM_LOGFILE
+#define _PAM_LOGFILE "/tmp/pam-debug.log"
+#endif
+
+static void _pam_output_debug_info(const char *file, const char *fn
+ , const int line)
+{
+ FILE *logfile;
+ int must_close = 1;
+
+ if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
+ logfile = stderr;
+ must_close = 0;
+ }
+ fprintf(logfile,"[%s:%s(%d)] ",file, fn, line);
+ if (must_close) {
+ fflush(logfile);
+ fclose(logfile);
+ }
+}
+
+static void _pam_output_debug(const char *format, ...)
+{
+ va_list args;
+ FILE *logfile;
+ int must_close = 1;
+
+ va_start(args, format);
+
+ if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
+ logfile = stderr;
+ must_close = 0;
+ }
+ vfprintf(logfile, format, args);
+ fprintf(logfile, "\n");
+ if (must_close) {
+ fflush(logfile);
+ fclose(logfile);
+ }
+
+ va_end(args);
+}
+
+#define D(x) do { \
+ _pam_output_debug_info(__FILE__, __FUNCTION__, __LINE__); \
+ _pam_output_debug x ; \
+} while (0)
+
+#define _pam_show_mem(X,XS) do { \
+ int i; \
+ register unsigned char *x; \
+ x = (unsigned char *)X; \
+ fprintf(stderr, " <start at %p>\n", X); \
+ for (i = 0; i < XS ; ++x, ++i) { \
+ fprintf(stderr, " %02X. <%p:%02X>\n", i, x, *x); \
+ } \
+ fprintf(stderr, " <end for %p after %d bytes>\n", X, XS); \
+} while (0)
+
+#define _pam_show_reply(/* struct pam_response * */reply, /* int */replies) \
+do { \
+ int reply_i; \
+ setbuf(stderr, NULL); \
+ fprintf(stderr, "array at %p of size %d\n",reply,replies); \
+ fflush(stderr); \
+ if (reply) { \
+ for (reply_i = 0; reply_i < replies; reply_i++) { \
+ fprintf(stderr, " elem# %d at %p: resp = %p, retcode = %d\n", \
+ reply_i, reply+reply_i, reply[reply_i].resp, \
+ reply[reply_i].resp, _retcode); \
+ fflush(stderr); \
+ if (reply[reply_i].resp) { \
+ fprintf(stderr, " resp[%d] = '%s'\n", \
+ strlen(reply[reply_i].resp), reply[reply_i].resp); \
+ fflush(stderr); \
+ } \
+ } \
+ } \
+ fprintf(stderr, "done here\n"); \
+ fflush(stderr); \
+} while (0)
+
+#else
+
+#define D(x) do { } while (0)
+#define _pam_show_mem(X,XS) do { } while (0)
+#define _pam_show_reply(reply, replies) do { } while (0)
+
+#endif /* DEBUG */
+
+#endif /* PAM_MACROS_H */
diff --git a/contrib/libpam/libpam/include/security/_pam_types.h b/contrib/libpam/libpam/include/security/_pam_types.h
new file mode 100644
index 000000000000..b68368b0c8e2
--- /dev/null
+++ b/contrib/libpam/libpam/include/security/_pam_types.h
@@ -0,0 +1,356 @@
+/*
+ * <security/_pam_types.h>
+ *
+ * $Id: _pam_types.h,v 1.10 1997/04/05 06:52:50 morgan Exp morgan $
+ *
+ * This file defines all of the types common to the Linux-PAM library
+ * applications and modules.
+ *
+ * Note, the copyright+license information is at end of file.
+ *
+ * Created: 1996/3/5 by AGM
+ *
+ * $Log$
+ */
+
+#ifndef _SECURITY__PAM_TYPES_H
+#define _SECURITY__PAM_TYPES_H
+
+/*
+ * include local definition for POSIX - NULL
+ */
+
+#include <locale.h>
+
+/* This is a blind structure; users aren't allowed to see inside a
+ * pam_handle_t, so we don't define struct pam_handle here. This is
+ * defined in a file private to the PAM library. (i.e., it's private
+ * to PAM service modules, too!) */
+
+typedef struct pam_handle pam_handle_t;
+
+/* ----------------- The Linux-PAM return values ------------------ */
+
+#define PAM_SUCCESS 0 /* Successful function return */
+#define PAM_OPEN_ERR 1 /* dlopen() failure when dynamically */
+ /* loading a service module */
+#define PAM_SYMBOL_ERR 2 /* Symbol not found */
+#define PAM_SERVICE_ERR 3 /* Error in service module */
+#define PAM_SYSTEM_ERR 4 /* System error */
+#define PAM_BUF_ERR 5 /* Memory buffer error */
+#define PAM_PERM_DENIED 6 /* Permission denied */
+#define PAM_AUTH_ERR 7 /* Authentication failure */
+#define PAM_CRED_INSUFFICIENT 8 /* Can not access authentication data */
+ /* due to insufficient credentials */
+#define PAM_AUTHINFO_UNAVAIL 9 /* Underlying authentication service */
+ /* can not retrieve authenticaiton */
+ /* information */
+#define PAM_USER_UNKNOWN 10 /* User not known to the underlying */
+ /* authenticaiton module */
+#define PAM_MAXTRIES 11 /* An authentication service has */
+ /* maintained a retry count which has */
+ /* been reached. No further retries */
+ /* should be attempted */
+#define PAM_NEW_AUTHTOK_REQD 12 /* New authentication token required. */
+ /* This is normally returned if the */
+ /* machine security policies require */
+ /* that the password should be changed */
+ /* beccause the password is NULL or it */
+ /* has aged */
+#define PAM_ACCT_EXPIRED 13 /* User account has expired */
+#define PAM_SESSION_ERR 14 /* Can not make/remove an entry for */
+ /* the specified session */
+#define PAM_CRED_UNAVAIL 15 /* Underlying authentication service */
+ /* can not retrieve user credentials */
+ /* unavailable */
+#define PAM_CRED_EXPIRED 16 /* User credentials expired */
+#define PAM_CRED_ERR 17 /* Failure setting user credentials */
+#define PAM_NO_MODULE_DATA 18 /* No module specific data is present */
+#define PAM_CONV_ERR 19 /* Conversation error */
+#define PAM_AUTHTOK_ERR 20 /* Authentication token manipulation error */
+#define PAM_AUTHTOK_RECOVER_ERR 21 /* Authentication information */
+ /* cannot be recovered */
+#define PAM_AUTHTOK_LOCK_BUSY 22 /* Authentication token lock busy */
+#define PAM_AUTHTOK_DISABLE_AGING 23 /* Authentication token aging disabled */
+#define PAM_TRY_AGAIN 24 /* Preliminary check by password service */
+#define PAM_IGNORE 25 /* Ingore underlying account module */
+ /* regardless of whether the control */
+ /* flag is required, optional, or sufficient */
+#define PAM_ABORT 26 /* Critical error (?module fail now request) */
+#define PAM_AUTHTOK_EXPIRED 27 /* user's authentication token has expired */
+#define PAM_MODULE_UNKNOWN 28 /* module is not known */
+
+#define PAM_BAD_ITEM 29 /* Bad item passed to pam_*_item() */
+#define PAM_CONV_AGAIN 30 /* conversation function is event driven
+ and data is not available yet */
+#define PAM_INCOMPLETE 31 /* please call this function again to
+ complete authentication stack. Before
+ calling again, verify that conversation
+ is completed */
+
+/* Add new #define's here */
+
+#define _PAM_RETURN_VALUES 32 /* this is the number of return values */
+
+
+/* ---------------------- The Linux-PAM flags -------------------- */
+
+/* Authentication service should not generate any messages */
+#define PAM_SILENT 0x8000U
+
+/* Note: these flags are used by pam_authenticate{,_secondary}() */
+
+/* The authentication service should return PAM_AUTH_ERROR if the
+ * user has a null authentication token */
+#define PAM_DISALLOW_NULL_AUTHTOK 0x0001U
+
+/* Note: these flags are used for pam_setcred() */
+
+/* Set user credentials for an authentication service */
+#define PAM_ESTABLISH_CRED 0x0002U
+
+/* Delete user credentials associated with an authentication service */
+#define PAM_DELETE_CRED 0x0004U
+
+/* Reinitialize user credentials */
+#define PAM_REINITIALIZE_CRED 0x0008U
+
+/* Extend lifetime of user credentials */
+#define PAM_REFRESH_CRED 0x0010U
+
+/* Note: these flags are used by pam_chauthtok */
+
+/* The password service should only update those passwords that have
+ * aged. If this flag is not passed, the password service should
+ * update all passwords. */
+#define PAM_CHANGE_EXPIRED_AUTHTOK 0x0020U
+
+/* ------------------ The Linux-PAM item types ------------------- */
+
+/* these defines are used by pam_set_item() and pam_get_item() */
+
+#define PAM_SERVICE 1 /* The service name */
+#define PAM_USER 2 /* The user name */
+#define PAM_TTY 3 /* The tty name */
+#define PAM_RHOST 4 /* The remote host name */
+#define PAM_CONV 5 /* The pam_conv structure */
+
+/* missing entries found in <security/pam_modules.h> for modules only! */
+
+#define PAM_RUSER 8 /* The remote user name */
+#define PAM_USER_PROMPT 9 /* the prompt for getting a username */
+#define PAM_FAIL_DELAY 10 /* app supplied function to override failure
+ delays */
+#define PAM_LOG_STATE 11 /* ident, facility etc. logging info */
+
+/* ---------- Common Linux-PAM application/module PI ----------- */
+
+extern int pam_set_item(pam_handle_t *pamh, int item_type, const void *item);
+extern int pam_get_item(const pam_handle_t *pamh, int item_type,
+ const void **item);
+extern const char *pam_strerror(pam_handle_t *pamh, int errnum);
+
+extern int pam_putenv(pam_handle_t *pamh, const char *name_value);
+extern const char *pam_getenv(pam_handle_t *pamh, const char *name);
+extern char **pam_getenvlist(pam_handle_t *pamh);
+
+/* ---------- Common Linux-PAM application/module PI ----------- */
+
+/*
+ * here are some proposed error status definitions for the
+ * 'error_status' argument used by the cleanup function associated
+ * with data items they should be logically OR'd with the error_status
+ * of the latest return from libpam -- new with .52 and positive
+ * impression from Sun although not official as of 1996/9/4
+ * [generally the other flags are to be found in pam_modules.h]
+ */
+
+#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */
+
+/*
+ * here we define an externally (by apps or modules) callable function
+ * that primes the libpam library to delay when a stacked set of
+ * modules results in a failure. In the case of PAM_SUCCESS this delay
+ * is ignored.
+ *
+ * Note, the pam_[gs]et_item(... PAM_FAIL_DELAY ...) can be used to set
+ * a function pointer which can override the default fail-delay behavior.
+ * This item was added to accommodate event driven programs that need to
+ * manage delays more carefully. The function prototype for this data
+ * item is
+ * void (*fail_delay)(int status, unsigned int delay);
+ */
+
+#define HAVE_PAM_FAIL_DELAY
+extern int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay);
+
+/*
+ * the standard libc interface for syslog suffers from some problems.
+ * The first is that it is not thread safe. It is also three functions
+ * where PAM only really needs a "log this" function. It also does
+ * not provide modules and applications with information about whether
+ * the log is currently open or not etc... All of these things mean
+ * that we need to centralize PAM's logging facility. These two functions
+ * provide this centralization. They are, however, just a gateway to
+ * libc's openlog/syslog/closelog functions. Please note, your apps/modules
+ * will likely start to segfault if you do not use this function for
+ * system logging.
+ */
+
+struct pam_log_state {
+ char *ident;
+ int option;
+ int facility;
+};
+
+#ifndef LOG_ERR
+# include <syslog.h> /* this is a sad HACK. But we need LOG_CRIT etc.. */
+#endif
+
+#define PAM_LOG_STATE_IDENT "PAM"
+#define PAM_LOG_STATE_OPTION LOG_PID
+#define PAM_LOG_STATE_FACILITY LOG_AUTHPRIV
+
+#ifndef va_start
+# include <stdarg.h>
+#endif
+
+#define HAVE_PAM_SYSTEM_LOG
+extern void pam_vsystem_log(const pam_handle_t *pamh,
+ const struct pam_log_state *log_state,
+ int priority, const char *format, va_list args);
+extern void pam_system_log(const pam_handle_t *pamh,
+ const struct pam_log_state *log_state,
+ int priority, const char *format, ... );
+
+#ifdef MEMORY_DEBUG
+/*
+ * this defines some macros that keep track of what memory has been
+ * allocated and indicates leakage etc... It should not be included in
+ * production application/modules.
+ */
+#include <security/pam_malloc.h>
+#endif
+
+/* ------------ The Linux-PAM conversation structures ------------ */
+
+/* Message styles */
+
+#define PAM_PROMPT_ECHO_OFF 1
+#define PAM_PROMPT_ECHO_ON 2
+#define PAM_ERROR_MSG 3
+#define PAM_TEXT_INFO 4
+
+/* Linux-PAM specific types */
+
+#define PAM_RADIO_TYPE 5 /* yes/no/maybe conditionals */
+
+/* This is for server client non-human interaction.. these are NOT
+ part of the X/Open PAM specification (yet although Vipin has hinted
+ that they may well be 1997/7/8) but are currently included for
+ exploritory reasons. Basically, they are for the module to obtain a
+ binary chunk of data from the client (via the server). Such data
+ is intercepted by the server and unpacked in preparation for the
+ module */
+
+#define PAM_BINARY_MSG 6
+#define PAM_BINARY_PROMPT 7
+
+/* maximum size of messages/responses etc.. (these are mostly
+ arbitrary so Linux-PAM should handle longer values). */
+
+#define PAM_MAX_NUM_MSG 32
+#define PAM_MAX_MSG_SIZE 512
+#define PAM_MAX_RESP_SIZE 512
+
+/* Used to pass prompting text, error messages, or other informatory
+ * text to the user. This structure is allocated and freed by the PAM
+ * library (or loaded module). */
+
+struct pam_message {
+ int msg_style;
+ const char *msg;
+};
+
+/* if the pam_message.msg_style = PAM_BINARY_PROMPT
+ the 'pam_message.msg' is a pointer to a 'const *' for the following
+ pseudo-structure. When used with a PAM_BINARY_PROMPT, the returned
+ pam_response.resp pointer points to an object with the following
+ structure:
+
+ struct {
+ u32 length; # network byte order
+ unsigned char data[length];
+ };
+
+ The 'libpam_client' library is designed around this flavor of
+ message and should be used to handle this flavor of msg_style.
+ */
+
+/* Used to return the user's response to the PAM library. This
+ structure is allocated by the application program, and free()'d by
+ the Linux-PAM library (or calling module). */
+
+struct pam_response {
+ char *resp;
+ int resp_retcode; /* currently un-used, zero expected */
+};
+
+/* The actual conversation structure itself */
+
+struct pam_conv {
+ int (*conv)(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr);
+ void *appdata_ptr;
+};
+
+#ifndef LINUX_PAM
+/*
+ * the following few lines represent a hack. They are there to make
+ * the Linux-PAM headers more compatible with the Sun ones, which have a
+ * less strictly separated notion of module specific and application
+ * specific definitions.
+ */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#endif
+
+
+/* ... adapted from the pam_appl.h file created by Theodore Ts'o and
+ *
+ * Copyright Theodore Ts'o, 1996. All rights reserved.
+ * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org>, 1996-8
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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. */
+
+#endif /* _SECURITY__PAM_TYPES_H */
+
diff --git a/contrib/libpam/libpam/include/security/pam_appl.h b/contrib/libpam/libpam/include/security/pam_appl.h
new file mode 100644
index 000000000000..d9c5eddd145b
--- /dev/null
+++ b/contrib/libpam/libpam/include/security/pam_appl.h
@@ -0,0 +1,99 @@
+/*
+ * <security/pam_appl.h>
+ *
+ * This header file collects definitions for the PAM API --- that is,
+ * public interface between the PAM library and an application program
+ * that wishes to use it.
+ *
+ * Note, the copyright information is at end of file.
+ *
+ * Created: 15-Jan-96 by TYT
+ * Last modified: 1996/3/5 by AGM
+ *
+ * $Log: pam_appl.h,v $
+ * Revision 1.5 1996/11/10 19:56:11 morgan
+ * minor prototype change
+ *
+ * Revision 1.4 1996/03/16 22:38:17 morgan
+ * made all of the pam_start input arguments constant
+ *
+ * Revision 1.3 1996/03/16 20:22:59 morgan
+ * changed name comment at top of file.
+ *
+ * Revision 1.2 1996/03/09 20:39:06 morgan
+ * added RCS information
+ *
+ *
+ * $Id: pam_appl.h,v 1.5 1996/11/10 19:56:11 morgan Exp $
+ *
+ */
+
+#ifndef _SECURITY_PAM_APPL_H
+#define _SECURITY_PAM_APPL_H
+
+#include <security/_pam_types.h> /* Linux-PAM common defined types */
+
+/* -------------- The Linux-PAM Framework layer API ------------- */
+
+extern int pam_start(const char *service_name, const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh);
+extern int pam_end(pam_handle_t *pamh, int pam_status);
+
+/* Authentication API's */
+
+extern int pam_authenticate(pam_handle_t *pamh, int flags);
+extern int pam_setcred(pam_handle_t *pamh, int flags);
+
+/* Account Management API's */
+
+extern int pam_acct_mgmt(pam_handle_t *pamh, int flags);
+
+/* Session Management API's */
+
+extern int pam_open_session(pam_handle_t *pamh, int flags);
+extern int pam_close_session(pam_handle_t *pamh, int flags);
+
+/* Password Management API's */
+
+extern int pam_chauthtok(pam_handle_t *pamh, int flags);
+
+/* take care of any compatibility issues */
+#include <security/_pam_compat.h>
+
+/*
+ * Copyright Theodore Ts'o, 1996. All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+#endif /* _SECURITY_PAM_APPL_H */
diff --git a/contrib/libpam/libpam/include/security/pam_malloc.h b/contrib/libpam/libpam/include/security/pam_malloc.h
new file mode 100644
index 000000000000..b5865cd305ad
--- /dev/null
+++ b/contrib/libpam/libpam/include/security/pam_malloc.h
@@ -0,0 +1,73 @@
+/* $Id: pam_malloc.h,v 1.1 1996/11/10 21:23:14 morgan Exp $
+ *
+ * $Log: pam_malloc.h,v $
+ * Revision 1.1 1996/11/10 21:23:14 morgan
+ * Initial revision
+ *
+ */
+
+/*
+ * This file (via the use of macros) defines a wrapper for the malloc
+ * family of calls. It logs where the memory was requested and also
+ * where it was free()'d and keeps a list of currently requested memory.
+ *
+ * It is hoped that it will provide some help in locating memory leaks.
+ */
+
+#ifndef PAM_MALLOC_H
+#define PAM_MALLOC_H
+
+/* these are the macro definitions for the stdlib.h memory functions */
+
+#define malloc(s) pam_malloc(s,__FILE__,__FUNCTION__,__LINE__)
+#define calloc(n,s) pam_calloc(n,s,__FILE__,__FUNCTION__,__LINE__)
+#define free(x) pam_free(x,__FILE__,__FUNCTION__,__LINE__)
+/* #define memalign(a,s) pam_memalign(a,s,__FILE__,__FUNCTION__,__LINE__) */
+#define realloc(x,s) pam_realloc(x,s,__FILE__,__FUNCTION__,__LINE__)
+/* #define valloc(s) pam_valloc(s,__FILE__,__FUNCTION__,__LINE__) */
+/* #define alloca(s) pam_alloca(s,__FILE__,__FUNCTION__,__LINE__) */
+#define exit(i) pam_exit(i,__FILE__,__FUNCTION__,__LINE__)
+
+/* these are the prototypes for the wrapper functions */
+
+#include <sys/types.h>
+
+extern void *pam_malloc(size_t s,const char *,const char *,const int);
+extern void *pam_calloc(size_t n,size_t s,const char *,const char *,const int);
+extern void pam_free(void *x,const char *,const char *,const int);
+extern void *pam_memalign(size_t a,size_t s
+ ,const char *,const char *,const int);
+extern void *pam_realloc(void *x,size_t s,const char *,const char *,const int);
+extern void *pam_valloc(size_t s,const char *,const char *,const int);
+extern void *pam_alloca(size_t s,const char *,const char *,const int);
+extern void pam_exit(int i,const char *,const char *,const int);
+
+/* these are the flags used to turn on and off diagnostics */
+
+#define PAM_MALLOC_LEAKED 01
+#define PAM_MALLOC_REQUEST 02
+#define PAM_MALLOC_FREE 04
+#define PAM_MALLOC_EXCH (PAM_MALLOC_FREED|PAM_MALLOC_EXCH)
+#define PAM_MALLOC_RESIZE 010
+#define PAM_MALLOC_FAIL 020
+#define PAM_MALLOC_NULL 040
+#define PAM_MALLOC_VERIFY 0100
+#define PAM_MALLOC_FUNC 0200
+#define PAM_MALLOC_PAUSE 0400
+#define PAM_MALLOC_STOP 01000
+
+#define PAM_MALLOC_ALL 0777
+
+#define PAM_MALLOC_DEFAULT \
+ (PAM_MALLOC_LEAKED|PAM_MALLOC_PAUSE|PAM_MALLOC_FAIL)
+
+#include <stdio.h>
+
+extern FILE *pam_malloc_outfile; /* defaults to stdout */
+
+/* how much output do you want? */
+
+extern int pam_malloc_flags;
+extern int pam_malloc_delay_length; /* how long to pause on errors */
+
+#endif /* PAM_MALLOC_H */
diff --git a/contrib/libpam/libpam/include/security/pam_modules.h b/contrib/libpam/libpam/include/security/pam_modules.h
new file mode 100644
index 000000000000..6ba9cc66588a
--- /dev/null
+++ b/contrib/libpam/libpam/include/security/pam_modules.h
@@ -0,0 +1,189 @@
+/*
+ * <security/pam_modules.h>
+ *
+ * $Id: pam_modules.h,v 1.8 1997/01/04 20:14:42 morgan Exp morgan $
+ *
+ * This header file documents the PAM SPI --- that is, interface
+ * between the PAM library and a PAM service library which is called
+ * by the PAM library.
+ *
+ * Note, the copyright information is at end of file.
+ *
+ * $Log: pam_modules.h,v $
+ * Revision 1.8 1997/01/04 20:14:42 morgan
+ * moved PAM_DATA_SILENT to _pam_types.h so applications can use it too
+ *
+ * Revision 1.7 1996/11/10 19:57:08 morgan
+ * pam_get_user prototype.
+ *
+ * Revision 1.6 1996/09/05 06:18:45 morgan
+ * added some data error_status masks, changed prototype for cleanup()
+ *
+ * Revision 1.5 1996/06/02 07:58:37 morgan
+ * altered the way in which modules obtain static prototypes for
+ * functions
+ *
+ */
+
+#ifndef _SECURITY_PAM_MODULES_H
+#define _SECURITY_PAM_MODULES_H
+
+#include <security/_pam_types.h> /* Linux-PAM common defined types */
+
+/* these defines are used by pam_set_item() and pam_get_item() and are
+ * in addition to those found in <security/_pam_types.h> */
+
+#define PAM_AUTHTOK 6 /* The authentication token (password) */
+#define PAM_OLDAUTHTOK 7 /* The old authentication token */
+
+/* -------------- The Linux-PAM Module PI ------------- */
+
+extern int pam_set_data(pam_handle_t *pamh, const char *module_data_name,
+ void *data,
+ void (*cleanup)(pam_handle_t *pamh, void *data,
+ int error_status));
+extern int pam_get_data(const pam_handle_t *pamh,
+ const char *module_data_name, const void **data);
+
+extern int pam_get_user(pam_handle_t *pamh, const char **user
+ , const char *prompt);
+
+#ifdef PAM_STATIC
+
+#define PAM_EXTERN static
+
+struct pam_module {
+ const char *name; /* Name of the module */
+
+ /* These are function pointers to the module's key functions. */
+
+ int (*pam_sm_authenticate)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_setcred)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_acct_mgmt)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_open_session)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_close_session)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_chauthtok)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+};
+
+#else /* !PAM_STATIC */
+
+#define PAM_EXTERN extern
+
+#endif /* PAM_STATIC */
+
+/* Lots of files include pam_modules.h that don't need these
+ * declared. However, when they are declared static, they
+ * need to be defined later. So we have to protect C files
+ * that include these without wanting these functions defined.. */
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_AUTH)) || !defined(PAM_STATIC)
+
+/* Authentication API's */
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_AUTH))
+ || !defined(PAM_STATIC)*/
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) || !defined(PAM_STATIC)
+
+/* Account Management API's */
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT))
+ || !defined(PAM_STATIC)*/
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_SESSION)) || !defined(PAM_STATIC)
+
+/* Session Management API's */
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_SESSION))
+ || !defined(PAM_STATIC)*/
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) || !defined(PAM_STATIC)
+
+/* Password Management API's */
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_PASSWORD))
+ || !defined(PAM_STATIC)*/
+
+/* The following two flags are for use across the Linux-PAM/module
+ * interface only. The Application is not permitted to use these
+ * tokens.
+ *
+ * The password service should only perform preliminary checks. No
+ * passwords should be updated. */
+#define PAM_PRELIM_CHECK 0x4000
+
+/* The password service should update passwords Note: PAM_PRELIM_CHECK
+ * and PAM_UPDATE_AUTHTOK can not both be set simultaneously! */
+#define PAM_UPDATE_AUTHTOK 0x2000
+
+
+/*
+ * here are some proposed error status definitions for the
+ * 'error_status' argument used by the cleanup function associated
+ * with data items they should be logically OR'd with the error_status
+ * of the latest return from libpam -- new with .52 and positive
+ * impression from Sun although not official as of 1996/9/4 there are
+ * others in _pam_types.h -- they are for common module/app use.
+ */
+
+#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */
+
+/* take care of any compatibility issues */
+#include <security/_pam_compat.h>
+
+/* Copyright (C) Theodore Ts'o, 1996.
+ * Copyright (C) Andrew Morgan, 1996-8.
+ * All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the
+ * GNU GPL are required INSTEAD OF the above restrictions. (This
+ * clause is necessary due to a potential bad interaction between the
+ * GNU GPL and the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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. */
+
+#endif /* _SECURITY_PAM_MODULES_H */
+
diff --git a/contrib/libpam/libpam/pam_account.c b/contrib/libpam/libpam/pam_account.c
new file mode 100644
index 000000000000..ffc01acd2a1b
--- /dev/null
+++ b/contrib/libpam/libpam/pam_account.c
@@ -0,0 +1,13 @@
+/* pam_account.c - PAM Account Management */
+
+#include <stdio.h>
+
+#include "pam_private.h"
+
+int pam_acct_mgmt(pam_handle_t *pamh, int flags)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_acct_mgmt",pamh,PAM_SYSTEM_ERR);
+ return _pam_dispatch(pamh, flags, PAM_ACCOUNT);
+}
diff --git a/contrib/libpam/libpam/pam_auth.c b/contrib/libpam/libpam/pam_auth.c
new file mode 100644
index 000000000000..ac461f5ba863
--- /dev/null
+++ b/contrib/libpam/libpam/pam_auth.c
@@ -0,0 +1,61 @@
+/*
+ * pam_auth.c -- PAM authentication
+ *
+ * $Id: pam_auth.c,v 1.7 1997/04/05 06:53:52 morgan Exp morgan $
+ *
+ * $Log: pam_auth.c,v $
+ * Revision 1.7 1997/04/05 06:53:52 morgan
+ * fail-delay changes
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+int pam_authenticate(pam_handle_t *pamh, int flags)
+{
+ int retval;
+
+ D(("pam_authenticate called"));
+
+ if (pamh->former.choice == PAM_NOT_STACKED) {
+ _pam_sanitize(pamh);
+ _pam_start_timer(pamh); /* we try to make the time for a failure
+ independent of the time it takes to
+ fail */
+ }
+
+ IF_NO_PAMH("pam_authenticate",pamh,PAM_SYSTEM_ERR);
+ retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE);
+
+ if (retval != PAM_INCOMPLETE) {
+ _pam_sanitize(pamh);
+ _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
+ D(("pam_authenticate exit"));
+ } else {
+ D(("will resume when ready"));
+ }
+
+ return retval;
+}
+
+int pam_setcred(pam_handle_t *pamh, int flags)
+{
+ int retval;
+
+ IF_NO_PAMH("pam_setcred", pamh, PAM_SYSTEM_ERR);
+
+ D(("pam_setcred called"));
+
+ if (! flags) {
+ flags = PAM_ESTABLISH_CRED;
+ }
+
+ retval = _pam_dispatch(pamh, flags, PAM_SETCRED);
+
+ D(("pam_setcred exit"));
+
+ return retval;
+}
diff --git a/contrib/libpam/libpam/pam_data.c b/contrib/libpam/libpam/pam_data.c
new file mode 100644
index 000000000000..397fb9d820d1
--- /dev/null
+++ b/contrib/libpam/libpam/pam_data.c
@@ -0,0 +1,123 @@
+/* pam_data.c */
+
+/*
+ * $Id: pam_data.c,v 1.5 1996/12/01 03:14:13 morgan Exp $
+ *
+ * $Log: pam_data.c,v $
+ * Revision 1.5 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.4 1996/11/10 19:59:56 morgan
+ * internalized strdup for malloc debugging
+ *
+ * Revision 1.3 1996/09/05 06:10:31 morgan
+ * changed type of cleanup(), added PAM_DATA_REPLACE to replacement
+ * cleanup() call.
+ *
+ * Revision 1.2 1996/03/16 21:33:05 morgan
+ * removed const from cleanup argument, also deleted comment about SUN stuff
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pam_private.h"
+
+struct pam_data *_pam_locate_data(const pam_handle_t *pamh, const char *name);
+
+int pam_set_data(
+ pam_handle_t *pamh,
+ const char *module_data_name,
+ void *data,
+ void (*cleanup)(pam_handle_t *pamh, void *data, int error_status))
+{
+ struct pam_data *data_entry;
+
+ IF_NO_PAMH("pam_set_data",pamh,PAM_SYSTEM_ERR);
+
+ /* first check if there is some data already. If so clean it up */
+
+ if ((data_entry = _pam_locate_data(pamh, module_data_name))) {
+ if (data_entry->cleanup) {
+ data_entry->cleanup(pamh, data_entry->data
+ , PAM_DATA_REPLACE | PAM_SUCCESS );
+ }
+ } else if ((data_entry = malloc(sizeof(*data_entry)))) {
+ char *tname;
+
+ if ((tname = _pam_strdup(module_data_name)) == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "pam_set_data: no memory for data name");
+ _pam_drop(data_entry);
+ return PAM_BUF_ERR;
+ }
+ data_entry->next = pamh->data;
+ pamh->data = data_entry;
+ data_entry->name = tname;
+ } else {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "pam_set_data: cannot allocate data entry");
+ return PAM_BUF_ERR;
+ }
+
+ data_entry->data = data; /* note this could be NULL */
+ data_entry->cleanup = cleanup;
+
+ return PAM_SUCCESS;
+}
+
+int pam_get_data(
+ const pam_handle_t *pamh,
+ const char *module_data_name,
+ const void **datap)
+{
+ struct pam_data *data;
+
+ IF_NO_PAMH("pam_get_data",pamh,PAM_SYSTEM_ERR);
+
+ data = _pam_locate_data(pamh, module_data_name);
+ if (data) {
+ *datap = data->data;
+ return PAM_SUCCESS;
+ }
+
+ return PAM_NO_MODULE_DATA;
+}
+
+struct pam_data *_pam_locate_data(const pam_handle_t *pamh, const char *name)
+{
+ struct pam_data *data;
+
+ IF_NO_PAMH("_pam_locate_data",pamh,NULL);
+ data = pamh->data;
+
+ while (data) {
+ if (!strcmp(data->name, name)) {
+ return data;
+ }
+ data = data->next;
+ }
+
+ return NULL;
+}
+
+void _pam_free_data(pam_handle_t *pamh, int status)
+{
+ struct pam_data *last;
+ struct pam_data *data;
+
+ IF_NO_PAMH("_pam_free_data",pamh,/* no return value for void fn */);
+ data = pamh->data;
+
+ while (data) {
+ last = data;
+ data = data->next;
+ if (last->cleanup) {
+ last->cleanup(pamh, last->data, status);
+ }
+ _pam_drop(last->name);
+ _pam_drop(last);
+ }
+}
diff --git a/contrib/libpam/libpam/pam_delay.c b/contrib/libpam/libpam/pam_delay.c
new file mode 100644
index 000000000000..e6950e2a966b
--- /dev/null
+++ b/contrib/libpam/libpam/pam_delay.c
@@ -0,0 +1,152 @@
+/*
+ * pam_delay.c
+ *
+ * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org> 1996-8
+ * All rights reserved.
+ *
+ * $Id: pam_delay.c,v 1.5 1997/04/05 06:54:19 morgan Exp $
+ *
+ * $Log: pam_delay.c,v $
+ */
+
+/*
+ * This is a simple implementation of a delay on failure mechanism; an
+ * attempt to overcome authentication-time attacks in a simple manner.
+ */
+
+#include <unistd.h>
+#include "pam_private.h"
+
+/* **********************************************************************
+ * initialize the time as unset, this is set on the return from the
+ * authenticating pair of of the libpam pam_XXX calls.
+ */
+
+void _pam_reset_timer(pam_handle_t *pamh)
+{
+ D(("setting pamh->fail_delay.set to FALSE"));
+ pamh->fail_delay.set = PAM_FALSE;
+}
+
+/* **********************************************************************
+ * this function sets the start time for possible delayed failing.
+ *
+ * Eventually, it may set the timer so libpam knows how long the program
+ * has already been executing. Currently, this value is used to seed
+ * a pseudo-random number generator...
+ */
+
+void _pam_start_timer(pam_handle_t *pamh)
+{
+ pamh->fail_delay.begin = time(NULL);
+ D(("starting timer..."));
+}
+
+/* *******************************************************************
+ * Compute a pseudo random time. The value is base*(1 +/- 1/5) where
+ * the distribution is pseudo gausian (the sum of three evenly
+ * distributed random numbers -- central limit theorem and all ;^) The
+ * linear random numbers are based on a formulae given in Knuth's
+ * Seminumerical recipies that was reproduced in `Numerical Recipies
+ * in C'. It is *not* a cryptographically strong generator, but it is
+ * probably "good enough" for our purposes here.
+ *
+ * /dev/random might be a better place to look for some numbers...
+ */
+
+static unsigned int _pam_rand(unsigned int seed)
+{
+#define N1 1664525
+#define N2 1013904223
+ return N1*seed + N2;
+}
+
+static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base)
+{
+ int i;
+ double sum;
+ unsigned int ans;
+
+ for (sum=i=0; i<3; ++i) {
+ seed = _pam_rand(seed);
+ sum += (double) ((seed / 10) % 1000000);
+ }
+ sum = (sum/3.)/1e6 - .5; /* rescale */
+ ans = (unsigned int) ( base*(1.+sum) );
+ D(("random number: base=%u -> ans=%u\n", base, ans));
+
+ return ans;
+}
+
+/* **********************************************************************
+ * the following function sleeps for a random time. The actual time
+ * slept is computed above.. It is based on the requested time but will
+ * differ by up to +/- 25%.
+ */
+
+void _pam_await_timer(pam_handle_t *pamh, int status)
+{
+ unsigned int delay;
+ D(("waiting?..."));
+
+ delay = _pam_compute_delay(pamh->fail_delay.begin,
+ pamh->fail_delay.delay);
+ if (pamh->fail_delay.delay_fn_ptr) {
+ union {
+ const void *value;
+ void (*fn)(int, unsigned);
+ } hack_fn_u;
+
+ /* always call the applications delay function, even if
+ the delay is zero - indicate status */
+ hack_fn_u.value = pamh->fail_delay.delay_fn_ptr;
+ hack_fn_u.fn(status, delay);
+
+ } else if (status != PAM_SUCCESS && pamh->fail_delay.set) {
+
+ D(("will wait %u usec", delay));
+
+ if (delay > 0) {
+ struct timeval tval;
+
+ tval.tv_sec = delay / 1000000;
+ tval.tv_usec = delay % 1000000;
+ select(0, NULL, NULL, NULL, &tval);
+ }
+ }
+
+ _pam_reset_timer(pamh);
+ D(("waiting done"));
+}
+
+/* **********************************************************************
+ * this function is known to both the module and the application, it
+ * keeps a running score of the largest-requested delay so far, as
+ * specified by either modules or an application.
+ */
+
+int pam_fail_delay(pam_handle_t *pamh, unsigned int usec)
+{
+ int largest;
+
+ IF_NO_PAMH("pam_fail_delay", pamh, PAM_SYSTEM_ERR);
+
+ D(("setting delay to %u",usec));
+
+ if (pamh->fail_delay.set) {
+ largest = pamh->fail_delay.delay;
+ } else {
+ pamh->fail_delay.set = PAM_TRUE;
+ largest = 0;
+ }
+
+ D(("largest = %u",largest));
+
+ if (largest < usec) {
+ D(("resetting largest delay"));
+ pamh->fail_delay.delay = usec;
+ }
+
+ return PAM_SUCCESS;
+}
+
diff --git a/contrib/libpam/libpam/pam_dispatch.c b/contrib/libpam/libpam/pam_dispatch.c
new file mode 100644
index 000000000000..d0bbc3872103
--- /dev/null
+++ b/contrib/libpam/libpam/pam_dispatch.c
@@ -0,0 +1,286 @@
+/* pam_dispatch.c - handles module function dispatch */
+
+/*
+ * $Id: pam_dispatch.c,v 1.8 1997/01/04 20:04:09 morgan Exp morgan $
+ *
+ * last modified by AGM
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "pam_private.h"
+
+/*
+ * this is the return code we return when a function pointer is NULL
+ * or, the handler structure indicates a broken module config line
+ */
+#define PAM_MUST_FAIL_CODE PAM_PERM_DENIED
+
+/* impression codes - this gives some sense to the logical choices */
+#define _PAM_UNDEF 0
+#define _PAM_POSITIVE +1
+#define _PAM_NEGATIVE -1
+
+/*
+ * walk a stack of modules. Interpret the administrator's instructions
+ * when combining the return code of each module.
+ */
+
+static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
+ _pam_boolean resumed)
+{
+ int depth, impression, status, skip_depth;
+
+ IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR);
+
+ if (h == NULL) {
+ const char *service=NULL;
+
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service);
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "no modules loaded for `%s' service",
+ service ? service:"<unknown>" );
+ service = NULL;
+ return PAM_MUST_FAIL_CODE;
+ }
+
+ /* if we are recalling this module stack because a former call did
+ not complete, we restore the state of play from pamh. */
+ if (resumed) {
+ skip_depth = pamh->former.depth;
+ status = pamh->former.status;
+ impression = pamh->former.impression;
+ /* forget all that */
+ pamh->former.impression = _PAM_UNDEF;
+ pamh->former.status = PAM_MUST_FAIL_CODE;
+ pamh->former.depth = 0;
+ } else {
+ skip_depth = 0;
+ impression = _PAM_UNDEF;
+ status = PAM_MUST_FAIL_CODE;
+ }
+
+ /* Loop through module logic stack */
+ for (depth=0 ; h != NULL ; h = h->next, ++depth) {
+ int retval, action;
+
+ /* skip leading modules if they have already returned */
+ if (depth < skip_depth) {
+ continue;
+ }
+
+ /* attempt to call the module */
+ if (h->func == NULL) {
+ D(("module function is not defined, indicating failure"));
+ retval = PAM_MODULE_UNKNOWN;
+ } else {
+ D(("passing control to module..."));
+ retval = h->func(pamh, flags, h->argc, h->argv);
+ D(("module returned: %s", pam_strerror(pamh, retval)));
+ if (h->must_fail) {
+ D(("module poorly listed in pam.conf; forcing failure"));
+ retval = PAM_MUST_FAIL_CODE;
+ }
+ }
+
+ /*
+ * PAM_INCOMPLETE return is special. It indicates that the
+ * module wants to wait for the application before continuing.
+ * In order to return this, the module will have saved its
+ * state so it can resume from an equivalent position when it
+ * is called next time. (This was added as of 0.65)
+ */
+ if (retval == PAM_INCOMPLETE) {
+ pamh->former.impression = impression;
+ pamh->former.status = status;
+ pamh->former.depth = depth;
+
+ D(("module %d returned PAM_INCOMPLETE", depth));
+ return retval;
+ }
+
+ /* verify that the return value is a valid one */
+ if (retval < PAM_SUCCESS || retval >= _PAM_RETURN_VALUES) {
+ retval = PAM_MUST_FAIL_CODE;
+ action = _PAM_ACTION_BAD;
+ } else {
+ action = h->actions[retval];
+ }
+
+ /* decide what to do */
+ switch (action) {
+ case _PAM_ACTION_RESET:
+ impression = _PAM_UNDEF;
+ status = PAM_MUST_FAIL_CODE;
+ break;
+
+ case _PAM_ACTION_OK:
+ case _PAM_ACTION_DONE:
+ if ( impression == _PAM_UNDEF
+ || (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) {
+ impression = _PAM_POSITIVE;
+ status = retval;
+ }
+ if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) {
+ goto decision_made;
+ }
+ break;
+
+ case _PAM_ACTION_BAD:
+ case _PAM_ACTION_DIE:
+#ifdef PAM_FAIL_NOW_ON
+ if ( retval == PAM_ABORT ) {
+ impression = _PAM_NEGATIVE;
+ status = PAM_PERM_DENIED;
+ goto decision_made;
+ }
+#endif /* PAM_FAIL_NOW_ON */
+ if ( impression != _PAM_NEGATIVE ) {
+ impression = _PAM_NEGATIVE;
+ status = retval;
+ }
+ if ( action == _PAM_ACTION_DIE ) {
+ goto decision_made;
+ }
+ break;
+
+ case _PAM_ACTION_IGNORE:
+ break;
+
+ /* if we get here, we expect action is a positive number --
+ this is what the ...JUMP macro checks. */
+
+ default:
+ if ( _PAM_ACTION_IS_JUMP(action) ) {
+ /* this means that we need to skip #action stacked modules */
+ do {
+ h = h->next;
+ } while ( --action > 0 && h != NULL );
+
+ /* note if we try to skip too many modules action is
+ still non-zero and we snag the next if. */
+ }
+
+ /* this case is a syntax error: we can't succeed */
+ if (action) {
+ D(("action syntax error"));
+ impression = _PAM_NEGATIVE;
+ status = PAM_MUST_FAIL_CODE;
+ }
+ }
+ }
+
+decision_made: /* by getting here we have made a decision */
+
+ /* Sanity check */
+ if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) {
+ D(("caught on sanity check -- this is probably a config error!"));
+ status = PAM_MUST_FAIL_CODE;
+ }
+
+ /* We have made a decision about the modules executed */
+ return status;
+}
+
+/*
+ * This function translates the module dispatch request into a pointer
+ * to the stack of modules that will actually be run. the
+ * _pam_dispatch_aux() function (above) is responsible for walking the
+ * module stack.
+ */
+
+int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
+{
+ struct handler *h = NULL;
+ int retval;
+ _pam_boolean resumed;
+
+ IF_NO_PAMH("_pam_dispatch",pamh,PAM_SYSTEM_ERR);
+
+ /* Load all modules, resolve all symbols */
+
+ if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) {
+ pam_system_log(pamh, NULL, LOG_ERR, "unable to dispatch function");
+ return retval;
+ }
+
+ switch (choice) {
+ case PAM_AUTHENTICATE:
+ h = pamh->handlers.conf.authenticate;
+ break;
+ case PAM_SETCRED:
+ h = pamh->handlers.conf.setcred;
+ break;
+ case PAM_ACCOUNT:
+ h = pamh->handlers.conf.acct_mgmt;
+ break;
+ case PAM_OPEN_SESSION:
+ h = pamh->handlers.conf.open_session;
+ break;
+ case PAM_CLOSE_SESSION:
+ h = pamh->handlers.conf.close_session;
+ break;
+ case PAM_CHAUTHTOK:
+ h = pamh->handlers.conf.chauthtok;
+ break;
+ default:
+ pam_system_log(pamh, NULL, LOG_ERR, "undefined fn choice; %d", choice);
+ return PAM_ABORT;
+ }
+
+ if (h == NULL) { /* there was no handlers.conf... entry; will use
+ * handlers.other... */
+ switch (choice) {
+ case PAM_AUTHENTICATE:
+ h = pamh->handlers.other.authenticate;
+ break;
+ case PAM_SETCRED:
+ h = pamh->handlers.other.setcred;
+ break;
+ case PAM_ACCOUNT:
+ h = pamh->handlers.other.acct_mgmt;
+ break;
+ case PAM_OPEN_SESSION:
+ h = pamh->handlers.other.open_session;
+ break;
+ case PAM_CLOSE_SESSION:
+ h = pamh->handlers.other.close_session;
+ break;
+ case PAM_CHAUTHTOK:
+ h = pamh->handlers.other.chauthtok;
+ break;
+ }
+ }
+
+ /* Did a module return an "incomplete state" last time? */
+ if (pamh->former.choice != PAM_NOT_STACKED) {
+ if (pamh->former.choice != choice) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "application failed to re-exec stack [%d:%d]",
+ pamh->former.choice, choice);
+ return PAM_ABORT;
+ }
+ resumed = PAM_TRUE;
+ } else {
+ resumed = PAM_FALSE;
+ }
+
+ /* call the list of module functions */
+ retval = _pam_dispatch_aux(pamh, flags, h, resumed);
+ resumed = PAM_FALSE;
+
+ /* Should we recall where to resume next time? */
+ if (retval == PAM_INCOMPLETE) {
+ D(("module [%d] returned PAM_INCOMPLETE"));
+ pamh->former.choice = choice;
+ } else {
+ pamh->former.choice = PAM_NOT_STACKED;
+ }
+
+ return retval;
+}
+
+/*
+ * $Log: pam_dispatch.c,v $
+ */
diff --git a/contrib/libpam/libpam/pam_end.c b/contrib/libpam/libpam/pam_end.c
new file mode 100644
index 000000000000..34f98f579779
--- /dev/null
+++ b/contrib/libpam/libpam/pam_end.c
@@ -0,0 +1,77 @@
+/* pam_end.c */
+
+/*
+ * $Id: pam_end.c,v 1.5 1996/12/01 03:14:13 morgan Exp $
+ *
+ * $Log: pam_end.c,v $
+ */
+
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+int pam_end(pam_handle_t *pamh, int pam_status)
+{
+ int ret;
+
+ IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR);
+
+ D(("entering pam_end()"));
+
+ /* first liberate the modules (it is not inconcevible that the
+ modules may need to use the service_name etc. to clean up) */
+
+ _pam_free_data(pamh, pam_status);
+
+ /* now drop all modules */
+
+ if ((ret = _pam_free_handlers(pamh)) != PAM_SUCCESS) {
+ return ret; /* error occurred */
+ }
+
+ /* from this point we cannot call the modules any more. Free the remaining
+ memory used by the Linux-PAM interface */
+
+ _pam_drop_env(pamh); /* purge the environment */
+
+ _pam_overwrite(pamh->authtok); /* blank out old token */
+ _pam_drop(pamh->authtok);
+
+ _pam_overwrite(pamh->oldauthtok); /* blank out old token */
+ _pam_drop(pamh->oldauthtok);
+
+ _pam_overwrite(pamh->former.prompt);
+ _pam_drop(pamh->former.prompt); /* drop saved prompt */
+
+ _pam_overwrite(pamh->service_name);
+ _pam_drop(pamh->service_name);
+
+ _pam_overwrite(pamh->user);
+ _pam_drop(pamh->user);
+
+ _pam_overwrite(pamh->prompt);
+ _pam_drop(pamh->prompt); /* prompt for pam_get_user() */
+
+ _pam_overwrite(pamh->tty);
+ _pam_drop(pamh->tty);
+
+ _pam_overwrite(pamh->rhost);
+ _pam_drop(pamh->rhost);
+
+ _pam_overwrite(pamh->ruser);
+ _pam_drop(pamh->ruser);
+
+ _pam_drop(pamh->pam_conversation);
+ pamh->fail_delay.delay_fn_ptr = NULL;
+
+ _pam_overwrite(pamh->pam_default_log.ident);
+ _pam_drop(pamh->pam_default_log.ident);
+
+ /* and finally liberate the memory for the pam_handle structure */
+
+ _pam_drop(pamh);
+
+ D(("exiting pam_end() successfully"));
+
+ return PAM_SUCCESS;
+}
diff --git a/contrib/libpam/libpam/pam_env.c b/contrib/libpam/libpam/pam_env.c
new file mode 100644
index 000000000000..2632b81342a2
--- /dev/null
+++ b/contrib/libpam/libpam/pam_env.c
@@ -0,0 +1,403 @@
+/*
+ * pam_env.c
+ *
+ * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997
+ * All rights reserved.
+ *
+ * This file was written from a "hint" provided by the people at SUN.
+ * and the X/Open XSSO draft of March 1997.
+ *
+ * $Id: pam_env.c,v 1.2 1997/02/15 15:56:48 morgan Exp morgan $
+ *
+ * $Log: pam_env.c,v $
+ * Revision 1.2 1997/02/15 15:56:48 morgan
+ * liberate pamh->env structure too!
+ *
+ * Revision 1.1 1996/12/01 03:14:13 morgan
+ * Initial revision
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#ifdef sunos
+#define memmove(x,y,z) bcopy(y,x,z)
+#endif
+
+#include "pam_private.h"
+
+/* helper functions */
+
+#ifdef DEBUG
+static void _pam_dump_env(pam_handle_t *pamh)
+{
+ int i;
+
+ D(("Listing environment of pamh=%p", pamh));
+ D(("pamh->env = %p", pamh->env));
+ D(("environment entries used = %d [of %d allocated]"
+ , pamh->env->requested, pamh->env->entries));
+
+ for (i=0; i<pamh->env->requested; ++i) {
+ _pam_output_debug(">%-3d [%9p]:[%s]"
+ , i, pamh->env->list[i], pamh->env->list[i]);
+ }
+ _pam_output_debug("*NOTE* the last item should be (nil)");
+}
+#else
+#define _pam_dump_env(x)
+#endif
+
+/*
+ * Create the environment
+ */
+
+int _pam_make_env(pam_handle_t *pamh)
+{
+ D(("called."));
+ IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
+
+ /*
+ * get structure memory
+ */
+
+ pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
+ if (pamh->env == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT, "_pam_make_env: out of memory");
+ return PAM_BUF_ERR;
+ }
+
+ /*
+ * get list memory
+ */
+
+ pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
+ if (pamh->env->list == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "_pam_make_env: no memory for list");
+ _pam_drop(pamh->env);
+ return PAM_BUF_ERR;
+ }
+
+ /*
+ * fill entries in pamh->env
+ */
+
+ pamh->env->entries = PAM_ENV_CHUNK;
+ pamh->env->requested = 1;
+ pamh->env->list[0] = NULL;
+
+ _pam_dump_env(pamh); /* only active when debugging */
+
+ return PAM_SUCCESS;
+}
+
+/*
+ * purge the environment
+ */
+
+void _pam_drop_env(pam_handle_t *pamh)
+{
+ D(("called."));
+ IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
+
+ if (pamh->env != NULL) {
+ int i;
+ /* we will only purge the pamh->env->requested number of elements */
+
+ for (i=pamh->env->requested-1; i-- > 0; ) {
+ D(("dropping #%3d>%s<", i, pamh->env->list[i]));
+ _pam_overwrite(pamh->env->list[i]); /* clean */
+ _pam_drop(pamh->env->list[i]); /* forget */
+ }
+ pamh->env->requested = 0;
+ pamh->env->entries = 0;
+ _pam_drop(pamh->env->list); /* forget */
+ _pam_drop(pamh->env); /* forget */
+ } else {
+ D(("no environment present in pamh?"));
+ }
+}
+
+/*
+ * Return the item number of the given variable = first 'length' chars
+ * of 'name_value'. Since this is a static function, it is safe to
+ * assume its supplied arguments are well defined.
+ */
+
+static int _pam_search_env(const struct pam_environ *env
+ , const char *name_value, int length)
+{
+ int i;
+
+ for (i=env->requested-1; i-- > 0; ) {
+ if (strncmp(name_value,env->list[i],length) == 0
+ && env->list[i][length] == '=') {
+
+ return i; /* Got it! */
+
+ }
+ }
+
+ return -1; /* no luck */
+}
+
+/*
+ * externally visible functions
+ */
+
+/*
+ * pam_putenv(): Add/replace/delete a PAM-environment variable.
+ *
+ * Add/replace:
+ * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
+ *
+ * delete:
+ * name_value = "NAME"
+ */
+
+int pam_putenv(pam_handle_t *pamh, const char *name_value)
+{
+ int l2eq, item, retval;
+
+ D(("called."));
+ IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
+
+ if (name_value == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_putenv: no variable indicated");
+ return PAM_PERM_DENIED;
+ }
+
+ /*
+ * establish if we are setting or deleting; scan for '='
+ */
+
+ for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
+ if (l2eq <= 0) {
+ pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: bad variable");
+ return PAM_BAD_ITEM;
+ }
+
+ /*
+ * Look first for environment.
+ */
+
+ if (pamh->env == NULL || pamh->env->list == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: no env%s found"
+ , pamh->env == NULL ? "":"-list");
+ return PAM_ABORT;
+ }
+
+ /* find the item to replace */
+
+ item = _pam_search_env(pamh->env, name_value, l2eq);
+
+ if (name_value[l2eq]) { /* (re)setting */
+
+ if (item == -1) { /* new variable */
+ D(("adding item: %s", name_value));
+ /* enough space? */
+ if (pamh->env->entries <= pamh->env->requested) {
+ register int i;
+ register char **tmp;
+
+ /* get some new space */
+ tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
+ , sizeof(char *) );
+ if (tmp == NULL) {
+ /* nothing has changed - old env intact */
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "pam_putenv: cannot grow environment");
+ return PAM_BUF_ERR;
+ }
+
+ /* copy old env-item pointers/forget old */
+ for (i=0; i<pamh->env->requested; ++i) {
+ tmp[i] = pamh->env->list[i];
+ pamh->env->list[i] = NULL;
+ }
+
+ /* drop old list and replace with new */
+ _pam_drop(pamh->env->list);
+ pamh->env->list = tmp;
+ pamh->env->entries += PAM_ENV_CHUNK;
+
+ D(("resized env list"));
+ _pam_dump_env(pamh); /* only when debugging */
+ }
+
+ item = pamh->env->requested-1; /* old last item (NULL) */
+
+ /* add a new NULL entry at end; increase counter */
+ pamh->env->list[pamh->env->requested++] = NULL;
+
+ } else { /* replace old */
+ D(("replacing item: %s\n with: %s"
+ , pamh->env->list[item], name_value));
+ _pam_overwrite(pamh->env->list[item]);
+ _pam_drop(pamh->env->list[item]);
+ }
+
+ /*
+ * now we have a place to put the new env-item, insert at 'item'
+ */
+
+ pamh->env->list[item] = _pam_strdup(name_value);
+ if (pamh->env->list[item] != NULL) {
+ _pam_dump_env(pamh); /* only when debugging */
+ return PAM_SUCCESS;
+ }
+
+ /* something went wrong; we should delete the item - fall through */
+
+ retval = PAM_BUF_ERR; /* an error occurred */
+ } else {
+ retval = PAM_SUCCESS; /* we requested delete */
+ }
+
+ /* getting to here implies we are deleting an item */
+
+ if (item < 0) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_putenv: delete non-existent entry; %s",
+ name_value);
+ return PAM_BAD_ITEM;
+ }
+
+ /*
+ * remove item: purge memory; reset counter; resize [; display-env]
+ */
+
+ D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
+ _pam_overwrite(pamh->env->list[item]);
+ _pam_drop(pamh->env->list[item]);
+ --(pamh->env->requested);
+ D(("mmove: item[%d]+%d -> item[%d]"
+ , item+1, ( pamh->env->requested - item ), item));
+ (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
+ , ( pamh->env->requested - item )*sizeof(char *) );
+
+ _pam_dump_env(pamh); /* only when debugging */
+
+ /*
+ * deleted.
+ */
+
+ return retval;
+}
+
+/*
+ * Return the value of the requested environment variable
+ */
+
+const char *pam_getenv(pam_handle_t *pamh, const char *name)
+{
+ int item;
+
+ D(("called."));
+ IF_NO_PAMH("pam_getenv", pamh, NULL);
+
+ if (name == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_getenv: no variable indicated");
+ return NULL;
+ }
+
+ if (pamh->env == NULL || pamh->env->list == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR, "pam_getenv: no env%s found",
+ pamh->env == NULL ? "":"-list" );
+ return NULL;
+ }
+
+ /* find the requested item */
+
+ item = _pam_search_env(pamh->env, name, strlen(name));
+ if (item != -1) {
+
+ D(("env-item: %s, found!", name));
+ return (pamh->env->list[item] + 1 + strlen(name));
+
+ } else {
+
+ D(("env-item: %s, not found", name));
+ return NULL;
+
+ }
+}
+
+static char **_copy_env(pam_handle_t *pamh)
+{
+ char **dump;
+ int i = pamh->env->requested; /* reckon size of environment */
+ char *const *env = pamh->env->list;
+
+ D(("now get some memory for dump"));
+
+ /* allocate some memory for this (plus the null tail-pointer) */
+ dump = (char **) calloc(i, sizeof(char *));
+ D(("dump = %p", dump));
+ if (dump == NULL) {
+ return NULL;
+ }
+
+ /* now run through entries and copy the variables over */
+ dump[--i] = NULL;
+ while (i-- > 0) {
+ D(("env[%d]=`%s'", i,env[i]));
+ dump[i] = _pam_strdup(env[i]);
+ D(("->dump[%d]=`%s'", i,dump[i]));
+ if (dump[i] == NULL) {
+ /* out of memory */
+
+ while (dump[++i]) {
+ _pam_overwrite(dump[i]);
+ _pam_drop(dump[i]);
+ }
+ return NULL;
+ }
+ }
+
+ env = NULL; /* forget now */
+
+ /* return transcribed environment */
+ return dump;
+}
+
+char **pam_getenvlist(pam_handle_t *pamh)
+{
+ int i;
+
+ D(("called."));
+ IF_NO_PAMH("pam_getenvlist", pamh, NULL);
+
+ if (pamh->env == NULL || pamh->env->list == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_getenvlist: no env%s found",
+ pamh->env == NULL ? "":"-list" );
+ return NULL;
+ }
+
+ /* some quick checks */
+
+ if (pamh->env->requested > pamh->env->entries) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_getenvlist: environment corruption");
+ _pam_dump_env(pamh); /* only active when debugging */
+ return NULL;
+ }
+
+ for (i=pamh->env->requested-1; i-- > 0; ) {
+ if (pamh->env->list[i] == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_getenvlist: environment broken");
+ _pam_dump_env(pamh); /* only active when debugging */
+ return NULL; /* somehow we've broken the environment!? */
+ }
+ }
+
+ /* Seems fine; copy environment */
+
+ _pam_dump_env(pamh); /* only active when debugging */
+
+ return _copy_env(pamh);
+}
diff --git a/contrib/libpam/libpam/pam_handlers.c b/contrib/libpam/libpam/pam_handlers.c
new file mode 100644
index 000000000000..53d77158edf5
--- /dev/null
+++ b/contrib/libpam/libpam/pam_handlers.c
@@ -0,0 +1,901 @@
+/* pam_handlers.c -- pam config file parsing and module loading */
+
+/*
+ * created by Marc Ewing.
+ * Currently maintained by Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * $Id: pam_handlers.c,v 1.17 1997/04/05 06:55:24 morgan Exp morgan $
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef PAM_SHL
+# include <dl.h>
+#else
+# include <dlfcn.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "pam_private.h"
+
+/* FreeBSD doesn't define this */
+#ifndef RTLD_NOW
+# define RTLD_NOW 1
+#endif
+
+/* If not required, define as nothing - FreeBSD needs it to be "_"... */
+#ifndef SHLIB_SYM_PREFIX
+# define SHLIB_SYM_PREFIX ""
+#endif
+
+#define BUF_SIZE 1024
+#define MODULE_CHUNK 4
+
+static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
+
+static void _pam_free_handlers_aux(struct handler **hp);
+
+static int _pam_add_handler(pam_handle_t *pamh
+ , int must_fail, int other, int type
+ , int *actions, const char *mod_path
+ , int argc, char **argv, int argvlen);
+
+/* Values for module type */
+
+#define PAM_T_AUTH 1
+#define PAM_T_SESS 2
+#define PAM_T_ACCT 4
+#define PAM_T_PASS 8
+
+static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
+ , const char *known_service /* specific file */
+#ifdef PAM_READ_BOTH_CONFS
+ , int not_other
+#endif /* PAM_READ_BOTH_CONFS */
+ )
+{
+ char buf[BUF_SIZE];
+ int x; /* read a line from the FILE *f ? */
+ /*
+ * read a line from the configuration (FILE *) f
+ */
+ while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
+ char *tok, *nexttok=NULL;
+ const char *this_service;
+ const char *mod_path;
+ int module_type, actions[_PAM_RETURN_VALUES];
+ int other; /* set if module is for PAM_DEFAULT_SERVICE */
+ int res; /* module added successfully? */
+ int must_fail=0; /* a badly formatted line must fail when used */
+ int argc;
+ char **argv;
+ int argvlen;
+
+ D(("_pam_init_handler: LINE: %s", buf));
+ if (known_service != NULL) {
+ nexttok = buf;
+ /* No service field: all lines are for the known service. */
+ this_service = known_service;
+ } else {
+ this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
+ }
+
+#ifdef PAM_READ_BOTH_CONFS
+ if (not_other)
+ other = 0;
+ else
+#endif /* PAM_READ_BOTH_CONFS */
+ other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
+
+ /* accept "service name" or PAM_DEFAULT_SERVICE modules */
+ if (!_pam_strCMP(this_service, pamh->service_name) || other) {
+ /* This is a service we are looking for */
+ D(("_pam_init_handlers: Found PAM config entry for: %s"
+ , this_service));
+
+ tok = _pam_StrTok(NULL, " \n\t", &nexttok);
+ if (!_pam_strCMP("auth", tok)) {
+ module_type = PAM_T_AUTH;
+ } else if (!_pam_strCMP("session", tok)) {
+ module_type = PAM_T_SESS;
+ } else if (!_pam_strCMP("account", tok)) {
+ module_type = PAM_T_ACCT;
+ } else if (!_pam_strCMP("password", tok)) {
+ module_type = PAM_T_PASS;
+ } else {
+ /* Illegal module type */
+ D(("_pam_init_handlers: bad module type: %s", tok));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "(%s) illegal module type: %s"
+ , this_service, tok);
+ module_type = PAM_T_AUTH; /* most sensitive */
+ must_fail = 1; /* install as normal but fail when dispatched */
+ }
+ D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
+
+ /* reset the actions to .._UNDEF's -- this is so that
+ we can work out which entries are not yet set (for default). */
+ {
+ int i;
+ for (i=0; i<_PAM_RETURN_VALUES;
+ actions[i++] = _PAM_ACTION_UNDEF);
+ }
+ tok = _pam_StrTok(NULL, " \n\t", &nexttok);
+ if (!_pam_strCMP("required", tok)) {
+ D(("*PAM_F_REQUIRED*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_OK;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
+ actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
+ _pam_set_default_control(actions, _PAM_ACTION_BAD);
+ } else if (!_pam_strCMP("requisite", tok)) {
+ D(("*PAM_F_REQUISITE*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_OK;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
+ actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
+ _pam_set_default_control(actions, _PAM_ACTION_DIE);
+ } else if (!_pam_strCMP("optional", tok)) {
+ D(("*PAM_F_OPTIONAL*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_OK;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
+ _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
+ } else if (!_pam_strCMP("sufficient", tok)) {
+ D(("*PAM_F_SUFFICIENT*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
+ _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
+ } else {
+ D(("will need to parse %s", tok));
+ _pam_parse_control(actions, tok);
+ /* by default the default is to treat as failure */
+ _pam_set_default_control(actions, _PAM_ACTION_BAD);
+ }
+
+ tok = _pam_StrTok(NULL, " \n\t", &nexttok);
+ if (tok != NULL) {
+ mod_path = tok;
+ D(("mod_path = %s",mod_path));
+ } else {
+ /* no module name given */
+ D(("_pam_init_handlers: no module name supplied"));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "(%s) no module name supplied", this_service);
+ mod_path = NULL;
+ must_fail = 1;
+ }
+
+ /* nexttok points to remaining arguments... */
+
+ if (nexttok != NULL) {
+ D(("list: %s",nexttok));
+ argvlen = _pam_mkargv(nexttok, &argv, &argc);
+ D(("argvlen = %d",argvlen));
+ } else { /* there are no arguments so fix by hand */
+ D(("_pam_init_handlers: empty argument list"));
+ argvlen = argc = 0;
+ argv = NULL;
+ }
+
+#ifdef DEBUG
+ {
+ int y;
+
+ D(("CONF%s: %s%s %d %s %d"
+ , must_fail?"<*will fail*>":""
+ , this_service, other ? "(backup)":""
+ , module_type
+ , mod_path, argc));
+ for (y = 0; y < argc; y++) {
+ D(("CONF: %s", argv[y]));
+ }
+ for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
+ D(("RETURN %s(%d) -> %d %s",
+ _pam_token_returns[y], y, actions[y],
+ actions[y]>0 ? "jump":
+ _pam_token_actions[-actions[y]]));
+ }
+ fprintf(stderr, "pause to look at debugging: ");
+ getchar();
+ }
+#endif
+
+ res = _pam_add_handler(pamh, must_fail, other
+ , module_type, actions, mod_path
+ , argc, argv, argvlen);
+ if (res != PAM_SUCCESS) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "error loading %s", mod_path);
+ D(("failed to load module - aborting"));
+ return PAM_ABORT;
+ }
+ }
+ }
+
+ return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
+}
+
+/* Parse config file, allocate handler structures, dlopen() */
+int _pam_init_handlers(pam_handle_t *pamh)
+{
+ FILE *f;
+ int retval;
+
+ D(("_pam_init_handlers called"));
+ IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
+
+ /* Return immediately if everything is already loaded */
+ if (pamh->handlers.handlers_loaded) {
+ return PAM_SUCCESS;
+ }
+
+ D(("_pam_init_handlers: initializing"));
+
+ /* First clean the service structure */
+
+ _pam_free_handlers(pamh);
+ if (! pamh->handlers.module) {
+ if ((pamh->handlers.module =
+ malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "_pam_init_handlers: no memory loading module");
+ return PAM_BUF_ERR;
+ }
+ pamh->handlers.modules_allocated = MODULE_CHUNK;
+ pamh->handlers.modules_used = 0;
+ }
+
+ if (pamh->service_name == NULL) {
+ return PAM_BAD_ITEM; /* XXX - better error? */
+ }
+
+#ifdef PAM_LOCKING
+ /* Is the PAM subsystem locked? */
+ {
+ int fd_tmp;
+
+ if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: PAM lockfile ("
+ PAM_LOCK_FILE ") exists - aborting");
+ (void) close(fd_tmp);
+ /*
+ * to avoid swamping the system with requests
+ */
+ _pam_start_timer(pamh);
+ pam_fail_delay(pamh, 5000000);
+ _pam_await_timer(pamh, PAM_ABORT);
+
+ return PAM_ABORT;
+ }
+ }
+#endif /* PAM_LOCKING */
+
+ /*
+ * Now parse the config file(s) and add handlers
+ */
+ {
+ struct stat test_d;
+
+ /* Is there a PAM_CONFIG_D directory? */
+ if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
+ char *filename;
+ int read_something=0;
+
+ D(("searching " PAM_CONFIG_D " for config files"));
+ filename = malloc(sizeof(PAM_CONFIG_DF)
+ +strlen(pamh->service_name));
+ if (filename == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: no memory; service %s",
+ pamh->service_name);
+ return PAM_BUF_ERR;
+ }
+ sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
+ D(("opening %s", filename));
+ f = fopen(filename, "r");
+ if (f != NULL) {
+ /* would test magic here? */
+ retval = _pam_parse_conf_file(pamh, f, pamh->service_name
+#ifdef PAM_READ_BOTH_CONFS
+ , 0
+#endif /* PAM_READ_BOTH_CONFS */
+ );
+ fclose(f);
+ if (retval != PAM_SUCCESS) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: error reading %s",
+ filename);
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: [%s]",
+ pam_strerror(pamh, retval));
+ } else {
+ read_something = 1;
+ }
+ } else {
+ D(("unable to open %s", filename));
+#ifdef PAM_READ_BOTH_CONFS
+ D(("checking %s", PAM_CONFIG));
+
+ if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
+ retval = _pam_parse_conf_file(pamh, f, NULL, 1);
+ fclose(f);
+ } else
+#endif /* PAM_READ_BOTH_CONFS */
+ retval = PAM_SUCCESS;
+ /*
+ * XXX - should we log an error? Some people want to always
+ * use "other"
+ */
+ }
+ _pam_drop(filename);
+
+ if (retval == PAM_SUCCESS) {
+ /* now parse the PAM_DEFAULT_SERVICE_FILE */
+
+ D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
+ f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
+ if (f != NULL) {
+ /* would test magic here? */
+ retval = _pam_parse_conf_file(pamh, f
+ , PAM_DEFAULT_SERVICE
+#ifdef PAM_READ_BOTH_CONFS
+ , 0
+#endif /* PAM_READ_BOTH_CONFS */
+ );
+ fclose(f);
+ if (retval != PAM_SUCCESS) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: error reading %s",
+ PAM_DEFAULT_SERVICE_FILE);
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: [%s]",
+ pam_strerror(pamh, retval));
+ } else {
+ read_something = 1;
+ }
+ } else {
+ D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: no default config %s",
+ PAM_DEFAULT_SERVICE_FILE);
+ }
+ if (!read_something) { /* nothing read successfully */
+ retval = PAM_ABORT;
+ }
+ }
+ } else {
+ if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "_pam_init_handlers: could not open "
+ PAM_CONFIG );
+ return PAM_ABORT;
+ }
+
+ retval = _pam_parse_conf_file(pamh, f, NULL
+#ifdef PAM_READ_BOTH_CONFS
+ , 0
+#endif /* PAM_READ_BOTH_CONFS */
+ );
+
+ D(("closing configuration file"));
+ fclose(f);
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ /* Read error */
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "error reading PAM configuration file");
+ return PAM_ABORT;
+ }
+
+ pamh->handlers.handlers_loaded = 1;
+
+ D(("_pam_init_handlers exiting"));
+ return PAM_SUCCESS;
+}
+
+/*
+ * This is where we read a line of the PAM config file. The line may be
+ * preceeded by lines of comments and also extended with "\\\n"
+ */
+
+int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
+{
+ char *p = buffer;
+ char *s, *os;
+ int used = 0;
+
+ /* loop broken with a 'break' when a non-'\\n' ended line is read */
+
+ D(("called."));
+ for (;;) {
+ if (used >= buf_len) {
+ /* Overflow */
+ D(("_pam_assemble_line: overflow"));
+ return -1;
+ }
+ if (fgets(p, buf_len - used, f) == NULL) {
+ if (used) {
+ /* Incomplete read */
+ return -1;
+ } else {
+ /* EOF */
+ return 0;
+ }
+ }
+
+ /* skip leading spaces --- line may be blank */
+
+ s = p + strspn(p, " \n\t");
+ if (*s && (*s != '#')) {
+ os = s;
+
+ /*
+ * we are only interested in characters before the first '#'
+ * character
+ */
+
+ while (*s && *s != '#')
+ ++s;
+ if (*s == '#') {
+ *s = '\0';
+ used += strlen(os);
+ break; /* the line has been read */
+ }
+
+ s = os;
+
+ /*
+ * Check for backslash by scanning back from the end of
+ * the entered line, the '\n' has been included since
+ * normally a line is terminated with this
+ * character. fgets() should only return one though!
+ */
+
+ s += strlen(s);
+ while (s > os && ((*--s == ' ') || (*s == '\t')
+ || (*s == '\n')));
+
+ /* check if it ends with a backslash */
+ if (*s == '\\') {
+ *s++ = ' '; /* replace backslash with ' ' */
+ *s = '\0'; /* truncate the line here */
+ used += strlen(os);
+ p = s; /* there is more ... */
+ } else {
+ /* End of the line! */
+ used += strlen(os);
+ break; /* this is the complete line */
+ }
+
+ } else {
+ /* Nothing in this line */
+ /* Don't move p */
+ }
+ }
+
+ return used;
+}
+
+typedef int (*servicefn)(pam_handle_t *, int, int, char **);
+
+int _pam_add_handler(pam_handle_t *pamh
+ , int must_fail, int other, int type
+ , int *actions, const char *mod_path
+ , int argc, char **argv, int argvlen)
+{
+ struct loaded_module *mod;
+ int x = 0;
+ struct handler **handler_p;
+ struct handler **handler_p2;
+ struct handlers *the_handlers;
+ const char *sym, *sym2;
+#ifdef PAM_SHL
+ const char *_sym, *_sym2;
+#endif
+ char *mod_full_path=NULL;
+ servicefn func, func2;
+ int success;
+
+ D(("called."));
+ IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
+
+ /* if NULL set to something that can be searched for */
+ if (mod_path == NULL) {
+ mod_path = "<*unknown module path*>";
+ } else if (mod_path[0] != '/') {
+ mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path));
+ sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
+ mod_path = mod_full_path;
+ }
+
+ D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
+ mod = pamh->handlers.module;
+
+ /* First, ensure the module is loaded */
+ while (x < pamh->handlers.modules_used) {
+ if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
+ break;
+ }
+ x++;
+ }
+ if (x == pamh->handlers.modules_used) {
+ /* Not found */
+ if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
+ /* will need more memory */
+ void *tmp = realloc(pamh->handlers.module,
+ (pamh->handlers.modules_allocated+MODULE_CHUNK)
+ *sizeof(struct loaded_module));
+ if (tmp == NULL) {
+ D(("cannot enlarge module pointer memory"));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "realloc returned NULL in _pam_add_handler");
+ _pam_drop(mod_full_path);
+ return PAM_ABORT;
+ }
+ pamh->handlers.module = tmp;
+ pamh->handlers.modules_allocated += MODULE_CHUNK;
+ }
+ mod = &(pamh->handlers.module[x]);
+ /* Be pessimistic... */
+ success = PAM_ABORT;
+
+#ifdef PAM_DYNAMIC
+ D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle));
+ mod->dl_handle =
+# ifdef PAM_SHL
+ shl_load(mod_path, BIND_IMMEDIATE, 0L);
+# else /* PAM_SHL */
+ dlopen(mod_path, RTLD_NOW);
+# endif /* PAM_SHL */
+ D(("_pam_add_handler: dlopen'ed"));
+ if (mod->dl_handle == NULL) {
+ D(("_pam_add_handler: dlopen(%s) failed", mod_path));
+ pam_system_log(pamh, NULL, LOG_ERR, "unable to dlopen(%s)",
+ mod_path);
+# ifndef PAM_SHL
+ pam_system_log(pamh, NULL, LOG_ERR, "[dlerror: %s]", dlerror());
+# endif /* PAM_SHL */
+ /* Don't abort yet; static code may be able to find function.
+ * But defaults to abort if nothing found below... */
+ } else {
+ D(("module added successfully"));
+ success = PAM_SUCCESS;
+ mod->type = PAM_MT_DYNAMIC_MOD;
+ pamh->handlers.modules_used++;
+ }
+#endif
+#ifdef PAM_STATIC
+ /* Only load static function if function was not found dynamically.
+ * This code should work even if no dynamic loading is available. */
+ if (success != PAM_SUCCESS) {
+ D(("_pam_add_handler: open static handler %s", mod_path));
+ mod->dl_handle = _pam_open_static_handler(mod_path);
+ if (mod->dl_handle == NULL) {
+ D(("_pam_add_handler: unable to find static handler %s",
+ mod_path));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "unable to open static handler %s", mod_path);
+ /* Didn't find module in dynamic or static..will mark bad */
+ } else {
+ D(("static module added successfully"));
+ success = PAM_SUCCESS;
+ mod->type = PAM_MT_STATIC_MOD;
+ pamh->handlers.modules_used++;
+ }
+ }
+#endif
+
+ if (success != PAM_SUCCESS) { /* add a malformed module */
+ mod->dl_handle = NULL;
+ mod->type = PAM_MT_FAULTY_MOD;
+ pamh->handlers.modules_used++;
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "adding faulty module: %s", mod_path);
+ success = PAM_SUCCESS; /* We have successfully added a module */
+ }
+
+ /* indicate its name - later we will search for it by this */
+ if ((mod->name = _pam_strdup(mod_path)) == NULL) {
+ D(("_pam_handler: couldn't get memory for mod_path"));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "no memory for module path", mod_path);
+ success = PAM_ABORT;
+ }
+
+ } else { /* x != pamh->handlers.modules_used */
+ mod += x; /* the located module */
+ success = PAM_SUCCESS;
+ }
+
+ _pam_drop(mod_full_path);
+ mod_path = NULL; /* no longer needed or trusted */
+
+ /* Now return error if necessary after trying all possible ways... */
+ if (success != PAM_SUCCESS)
+ return(success);
+
+ /*
+ * At this point 'mod' points to the stored/loaded module. If its
+ * dl_handle is unknown, then we must be able to indicate dispatch
+ * failure with 'must_fail'
+ */
+
+ /* Now define the handler(s) based on mod->dlhandle and type */
+
+ /* decide which list of handlers to use */
+ the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
+
+ handler_p = handler_p2 = NULL;
+ func = func2 = NULL;
+#ifdef PAM_SHL
+ _sym2 =
+#endif /* PAM_SHL */
+ sym2 = NULL;
+
+ /* point handler_p's at the root addresses of the function stacks */
+ switch (type) {
+ case PAM_T_AUTH:
+ handler_p = &the_handlers->authenticate;
+ sym = SHLIB_SYM_PREFIX "pam_sm_authenticate";
+ handler_p2 = &the_handlers->setcred;
+ sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_authenticate";
+ _sym2 = "_pam_sm_setcred";
+#endif
+ break;
+ case PAM_T_SESS:
+ handler_p = &the_handlers->open_session;
+ sym = SHLIB_SYM_PREFIX "pam_sm_open_session";
+ handler_p2 = &the_handlers->close_session;
+ sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_open_session";
+ _sym2 = "_pam_sm_close_session";
+#endif
+ break;
+ case PAM_T_ACCT:
+ handler_p = &the_handlers->acct_mgmt;
+ sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_acct_mgmt";
+#endif
+ break;
+ case PAM_T_PASS:
+ handler_p = &the_handlers->chauthtok;
+ sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_chauthtok";
+#endif
+ break;
+ default:
+ /* Illegal module type */
+ D(("_pam_add_handler: illegal module type %d", type));
+ return PAM_ABORT;
+ }
+
+ /* are the modules reliable? */
+ if (
+#ifdef PAM_DYNAMIC
+ mod->type != PAM_MT_DYNAMIC_MOD
+ &&
+#endif /* PAM_DYNAMIC */
+#ifdef PAM_STATIC
+ mod->type != PAM_MT_STATIC_MOD
+ &&
+#endif /* PAM_STATIC */
+ mod->type != PAM_MT_FAULTY_MOD
+ ) {
+ D(("_pam_add_handlers: illegal module library type; %d", mod->type));
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "internal error: module library type not known: %s;%d",
+ sym, mod->type);
+ return PAM_ABORT;
+ }
+
+ /* now identify this module's functions - for non-faulty modules */
+
+#ifdef PAM_DYNAMIC
+ if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
+# ifdef PAM_SHL
+ (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) &&
+ shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func))
+# else /* PAM_SHL */
+ (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
+# endif /* PAM_SHL */
+ ) {
+ pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
+ sym);
+ }
+#endif
+#ifdef PAM_STATIC
+ if ((mod->type == PAM_MT_STATIC_MOD) &&
+ (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "unable to resolve static symbol: %s", sym);
+ }
+#endif
+ if (sym2) {
+#ifdef PAM_DYNAMIC
+ if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
+# ifdef PAM_SHL
+ (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&&
+ shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2))
+# else /* PAM_SHL */
+ (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
+# endif /* PAM_SHL */
+ ) {
+ pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
+ sym2);
+ }
+#endif
+#ifdef PAM_STATIC
+ if ((mod->type == PAM_MT_STATIC_MOD) &&
+ (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
+ == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
+ sym2);
+ }
+#endif
+ }
+
+ /* here func (and perhaps func2) point to the appropriate functions */
+
+ /* add new handler to end of existing list */
+ while (*handler_p != NULL) {
+ handler_p = &((*handler_p)->next);
+ }
+
+ if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "cannot malloc struct handler #1");
+ return (PAM_ABORT);
+ }
+
+ (*handler_p)->must_fail = must_fail; /* failure forced? */
+ (*handler_p)->func = func;
+ memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
+ (*handler_p)->argc = argc;
+ (*handler_p)->argv = argv; /* not a copy */
+ (*handler_p)->next = NULL;
+
+ /* some of the modules have a second calling function */
+ if (handler_p2) {
+ /* add new handler to end of existing list */
+ while (*handler_p2) {
+ handler_p2 = &((*handler_p2)->next);
+ }
+
+ if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "cannot malloc struct handler #2");
+ return (PAM_ABORT);
+ }
+
+ (*handler_p2)->must_fail = must_fail; /* failure forced? */
+ (*handler_p2)->func = func2;
+ memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
+ (*handler_p2)->argc = argc;
+ if (argv) {
+ if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "cannot malloc argv for handler #2");
+ return (PAM_ABORT);
+ }
+ memcpy((*handler_p2)->argv, argv, argvlen);
+ } else {
+ (*handler_p2)->argv = NULL; /* no arguments */
+ }
+ (*handler_p2)->next = NULL;
+ }
+
+ D(("_pam_add_handler: returning successfully"));
+
+ return PAM_SUCCESS;
+}
+
+/* Free various allocated structures and dlclose() the libs */
+int _pam_free_handlers(pam_handle_t *pamh)
+{
+ struct loaded_module *mod;
+
+ D(("called."));
+ IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
+
+ mod = pamh->handlers.module;
+
+ /* Close all loaded modules */
+
+ while (pamh->handlers.modules_used) {
+ D(("_pam_free_handlers: dlclose(%s)", mod->name));
+ free(mod->name);
+#ifdef PAM_DYNAMIC
+# ifdef PAM_SHL
+ if (mod->type == PAM_MT_DYNAMIC_MOD) shl_unload(mod->dl_handle);
+# else
+ if (mod->type == PAM_MT_DYNAMIC_MOD) dlclose(mod->dl_handle);
+# endif
+#endif
+ mod++;
+ pamh->handlers.modules_used--;
+ }
+
+ /* Free all the handlers */
+
+ _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
+
+ _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
+ _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
+ _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
+ _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
+ _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
+ _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
+
+ /* no more loaded modules */
+
+ _pam_drop(pamh->handlers.module);
+
+ /* Indicate that handlers are not initialized for this pamh */
+
+ pamh->handlers.handlers_loaded = 0;
+
+ return PAM_SUCCESS;
+}
+
+void _pam_start_handlers(pam_handle_t *pamh)
+{
+ D(("called."));
+ /* NB. There is no check for a NULL pamh here, since no return
+ * value to communicate the fact! */
+
+ /* Indicate that handlers are not initialized for this pamh */
+ pamh->handlers.handlers_loaded = 0;
+
+ pamh->handlers.modules_allocated = 0;
+ pamh->handlers.modules_used = 0;
+ pamh->handlers.module = NULL;
+
+ /* initialize the .conf and .other entries */
+
+ pamh->handlers.conf.authenticate = NULL;
+ pamh->handlers.conf.setcred = NULL;
+ pamh->handlers.conf.acct_mgmt = NULL;
+ pamh->handlers.conf.open_session = NULL;
+ pamh->handlers.conf.close_session = NULL;
+ pamh->handlers.conf.chauthtok = NULL;
+
+ pamh->handlers.other.authenticate = NULL;
+ pamh->handlers.other.setcred = NULL;
+ pamh->handlers.other.acct_mgmt = NULL;
+ pamh->handlers.other.open_session = NULL;
+ pamh->handlers.other.close_session = NULL;
+ pamh->handlers.other.chauthtok = NULL;
+}
+
+void _pam_free_handlers_aux(struct handler **hp)
+{
+ struct handler *h = *hp;
+ struct handler *last;
+
+ D(("called."));
+ while (h) {
+ last = h;
+ _pam_drop(h->argv); /* This is all alocated in a single chunk */
+ h = h->next;
+ memset(last, 0, sizeof(*last));
+ free(last);
+ }
+
+ *hp = NULL;
+}
diff --git a/contrib/libpam/libpam/pam_item.c b/contrib/libpam/libpam/pam_item.c
new file mode 100644
index 000000000000..0e8142bf5ce4
--- /dev/null
+++ b/contrib/libpam/libpam/pam_item.c
@@ -0,0 +1,313 @@
+/* pam_item.c */
+
+/*
+ * $Id: pam_item.c,v 1.8 1997/02/15 15:58:49 morgan Exp morgan $
+ *
+ * $Log: pam_item.c,v $
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "pam_private.h"
+
+#define RESET(X, Y) \
+{ \
+ char *_TMP_ = (X); \
+ if (_TMP_ != (Y)) { \
+ (X) = (Y) ? _pam_strdup(Y) : NULL; \
+ if (_TMP_) \
+ free(_TMP_); \
+ } \
+}
+
+/* functions */
+
+int pam_set_item (
+ pam_handle_t *pamh,
+ int item_type,
+ const void *item)
+{
+ int retval;
+
+ D(("called"));
+
+ IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
+
+ retval = PAM_SUCCESS;
+
+ switch (item_type) {
+ case PAM_SERVICE:
+ /* Setting handlers_loaded to 0 will cause the handlers
+ * to be reloaded on the next call to a service module.
+ */
+ pamh->handlers.handlers_loaded = 0;
+ RESET(pamh->service_name, item);
+ {
+ char *tmp;
+ for (tmp=pamh->service_name; *tmp; ++tmp)
+ *tmp = tolower(*tmp); /* require lower case */
+ }
+ break;
+ case PAM_USER:
+ RESET(pamh->user, item);
+ break;
+ case PAM_USER_PROMPT:
+ RESET(pamh->prompt, item);
+ break;
+ case PAM_TTY:
+ D(("setting tty to %s", item));
+ RESET(pamh->tty, item);
+ break;
+ case PAM_RUSER:
+ RESET(pamh->ruser, item);
+ break;
+ case PAM_RHOST:
+ RESET(pamh->rhost, item);
+ break;
+ case PAM_AUTHTOK:
+ /*
+ * The man page says this is only supposed to be available to
+ * the module providers. In order to use this item the app
+ * has to #include <security/pam_modules.h>. This is something
+ * it is *not* supposed to do with "Linux-"PAM! - AGM.
+ */
+ {
+ char *_TMP_ = pamh->authtok;
+ if (_TMP_ == item) /* not changed so leave alone */
+ break;
+ pamh->authtok = (item) ? _pam_strdup(item) : NULL;
+ if (_TMP_) {
+ _pam_overwrite(_TMP_);
+ free(_TMP_);
+ }
+ break;
+ }
+ case PAM_OLDAUTHTOK:
+ /* See note above. */
+ {
+ char *_TMP_ = pamh->oldauthtok;
+ if (_TMP_ == item) /* not changed so leave alone */
+ break;
+ pamh->oldauthtok = (item) ? _pam_strdup(item) : NULL;
+ if (_TMP_) {
+ _pam_overwrite(_TMP_);
+ free(_TMP_);
+ }
+ break;
+ }
+ case PAM_CONV: /* want to change the conversation function */
+ if (item == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_set_item: attempt to set conv() to NULL");
+ retval = PAM_PERM_DENIED;
+ } else {
+ struct pam_conv *tconv;
+
+ if ((tconv=
+ (struct pam_conv *) malloc(sizeof(struct pam_conv))
+ ) == NULL) {
+ pam_system_log(pamh, NULL, LOG_CRIT,
+ "pam_set_item: malloc failed for pam_conv");
+ retval = PAM_BUF_ERR;
+ } else {
+ memcpy(tconv, item, sizeof(struct pam_conv));
+ _pam_drop(pamh->pam_conversation);
+ pamh->pam_conversation = tconv;
+ }
+ }
+ break;
+ case PAM_FAIL_DELAY:
+ pamh->fail_delay.delay_fn_ptr = item;
+ break;
+ case PAM_LOG_STATE:
+ {
+ char *old_ident = pamh->pam_default_log.ident;
+
+ if (item == NULL) {
+ /* reset the default state */
+ pamh->pam_default_log.ident = x_strdup(PAM_LOG_STATE_IDENT);
+ pamh->pam_default_log.option = PAM_LOG_STATE_OPTION;
+ pamh->pam_default_log.facility = PAM_LOG_STATE_FACILITY;
+ } else {
+ const struct pam_log_state *state = item;
+
+ pamh->pam_default_log.ident = x_strdup(state->ident);
+ pamh->pam_default_log.option = state->option;
+ pamh->pam_default_log.facility = state->facility;
+ }
+ _pam_overwrite(old_ident);
+ _pam_drop(old_ident);
+
+ break;
+ }
+ default:
+ retval = PAM_BAD_ITEM;
+ }
+
+ return (retval);
+}
+
+int pam_get_item (
+ const pam_handle_t *pamh,
+ int item_type,
+ const void **item)
+{
+ D(("called."));
+ IF_NO_PAMH("pam_get_item",pamh,PAM_SYSTEM_ERR);
+
+ if (item == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_get_item: nowhere to place requested item");
+ return PAM_PERM_DENIED;
+ }
+
+ switch (item_type) {
+ case PAM_SERVICE:
+ *item = pamh->service_name;
+ break;
+ case PAM_USER:
+ *item = pamh->user;
+ break;
+ case PAM_USER_PROMPT:
+ *item = pamh->prompt;
+ break;
+ case PAM_TTY:
+ D(("returning tty=%s", pamh->tty));
+ *item = pamh->tty;
+ break;
+ case PAM_RUSER:
+ *item = pamh->ruser;
+ break;
+ case PAM_RHOST:
+ *item = pamh->rhost;
+ break;
+ case PAM_AUTHTOK:
+ *item = pamh->authtok;
+ break;
+ case PAM_OLDAUTHTOK:
+ *item = pamh->oldauthtok;
+ break;
+ case PAM_CONV:
+ *item = pamh->pam_conversation;
+ break;
+ case PAM_FAIL_DELAY:
+ *item = pamh->fail_delay.delay_fn_ptr;
+ break;
+ case PAM_LOG_STATE:
+ *item = &(pamh->pam_default_log);
+ break;
+ default:
+ /* XXX - I made this up */
+ return PAM_BAD_ITEM;
+ }
+
+ return PAM_SUCCESS;
+}
+
+/* added by AGM 1996/3/2 */
+
+int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
+{
+ const char *use_prompt;
+ int retval;
+ struct pam_message msg,*pmsg;
+ struct pam_response *resp;
+
+ D(("called."));
+ IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);
+
+ if (pamh->pam_conversation == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_get_user: no conv element in pamh");
+ return PAM_SERVICE_ERR;
+ }
+
+ if (user == NULL) { /* ensure the the module has suplied a destination */
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_get_user: nowhere to record username");
+ return PAM_PERM_DENIED;
+ } else
+ *user = NULL;
+
+ if (pamh->user) { /* have one so return it */
+ *user = pamh->user;
+ return PAM_SUCCESS;
+ }
+
+ /* will need a prompt */
+ use_prompt = prompt;
+ if (use_prompt == NULL) {
+ use_prompt = pamh->prompt;
+ if (use_prompt == NULL) {
+ use_prompt = PAM_DEFAULT_PROMPT;
+ }
+ }
+
+ /* If we are resuming an old conversation, we verify that the prompt
+ is the same. Anything else is an error. */
+ if (pamh->former.want_user) {
+ /* must have a prompt to resume with */
+ if (! pamh->former.prompt) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_get_user: failed to resume with prompt"
+ );
+ return PAM_ABORT;
+ }
+
+ /* must be the same prompt as last time */
+ if (strcmp(pamh->former.prompt, use_prompt)) {
+ pam_system_log(pamh, NULL, LOG_ERR,
+ "pam_get_user: resumed with different prompt");
+ return PAM_ABORT;
+ }
+
+ /* ok, we can resume where we left off last time */
+ pamh->former.want_user = PAM_FALSE;
+ _pam_overwrite(pamh->former.prompt);
+ _pam_drop(pamh->former.prompt);
+ }
+
+ /* converse with application -- prompt user for a username */
+ pmsg = &msg;
+ msg.msg_style = PAM_PROMPT_ECHO_ON;
+ msg.msg = use_prompt;
+ resp = NULL;
+
+ retval = pamh->pam_conversation->
+ conv(1, (const struct pam_message **) &pmsg, &resp,
+ pamh->pam_conversation->appdata_ptr);
+
+ if (retval == PAM_CONV_AGAIN) {
+ /* conversation function is waiting for an event - save state */
+ D(("conversation function is not ready yet"));
+ pamh->former.want_user = PAM_TRUE;
+ pamh->former.prompt = _pam_strdup(use_prompt);
+ } else if (resp == NULL) {
+ /*
+ * conversation should have given a response
+ */
+ D(("pam_get_user: no response provided"));
+ retval = PAM_CONV_ERR;
+ } else if (retval == PAM_SUCCESS) { /* copy the username */
+ /*
+ * now we set the PAM_USER item -- this was missing from pre.53
+ * releases. However, reading the Sun manual, it is part of
+ * the standard API.
+ */
+ RESET(pamh->user, resp->resp);
+ *user = pamh->user;
+ }
+
+ if (resp) {
+ /*
+ * note 'resp' is allocated by the application and is
+ * correctly free()'d here
+ */
+ _pam_drop_reply(resp, 1);
+ }
+
+ return retval; /* pass on any error from conversation */
+}
diff --git a/contrib/libpam/libpam/pam_log.c b/contrib/libpam/libpam/pam_log.c
new file mode 100644
index 000000000000..9eddf29ba0ee
--- /dev/null
+++ b/contrib/libpam/libpam/pam_log.c
@@ -0,0 +1,425 @@
+/*
+ * pam_log.c -- PAM system logging
+ *
+ * $Id$
+ *
+ * $Log$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "pam_private.h"
+
+#ifdef __hpux
+# include <stdio.h>
+# include <syslog.h>
+# ifdef __STDC__
+# ifndef __P
+# define __P(p) p
+# endif /* __P */
+# include <stdarg.h>
+# define VA_LOCAL_DECL va_list ap;
+# define VA_START(f) va_start(ap, f)
+# define VA_END va_end(ap)
+# else /* __STDC__ */
+# ifndef __P
+# define __P(p) ()
+# endif /* __P */
+# include <varargs.h>
+# define VA_LOCAL_DECL va_list ap;
+# define VA_START(f) va_start(ap)
+# define VA_END va_end(ap)
+# endif /* __STDC__ */
+/**************************************************************
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ **************************************************************/
+
+static void dopr();
+static char *end;
+# ifndef _SCO_DS
+/* VARARGS3 */
+int
+# ifdef __STDC__
+snprintf(char *str, size_t count, const char *fmt, ...)
+# else /* __STDC__ */
+snprintf(str, count, fmt, va_alist)
+ char *str;
+ size_t count;
+ const char *fmt;
+ va_dcl
+# endif /* __STDC__ */
+{
+ int len;
+ VA_LOCAL_DECL
+
+ VA_START(fmt);
+ len = vsnprintf(str, count, fmt, ap);
+ VA_END;
+ return len;
+}
+# endif /* _SCO_DS */
+
+int
+# ifdef __STDC__
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+# else /* __STDC__ */
+vsnprintf(str, count, fmt, args)
+ char *str;
+ int count;
+ char *fmt;
+ va_list args;
+# endif /* __STDC__ */
+{
+ str[0] = 0;
+ end = str + count - 1;
+ dopr( str, fmt, args );
+ if (count > 0)
+ end[0] = 0;
+ return strlen(str);
+}
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+static void fmtstr __P((char *value, int ljust, int len, int zpad,
+ int maxwidth));
+static void fmtnum __P((long value, int base, int dosign, int ljust, int len,
+ int zpad));
+static void dostr __P(( char * , int ));
+static char *output;
+static void dopr_outch __P(( int c ));
+
+static void
+# ifdef __STDC__
+dopr(char * buffer, const char * format, va_list args )
+# else /* __STDC__ */
+dopr( buffer, format, args )
+ char *buffer;
+ char *format;
+ va_list args;
+# endif /* __STDC__ */
+{
+ int ch;
+ long value;
+ int longflag = 0;
+ int pointflag = 0;
+ int maxwidth = 0;
+ char *strvalue;
+ int ljust;
+ int len;
+ int zpad;
+
+ output = buffer;
+ while( (ch = *format++) ){
+ switch( ch ){
+ case '%':
+ ljust = len = zpad = maxwidth = 0;
+ longflag = pointflag = 0;
+ nextch:
+ ch = *format++;
+ switch( ch ){
+ case 0:
+ dostr( "**end of format**" , 0);
+ return;
+ case '-': ljust = 1; goto nextch;
+ case '0': /* set zero padding if len not set */
+ if(len==0 && !pointflag) zpad = '0';
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ if (pointflag)
+ maxwidth = maxwidth*10 + ch - '0';
+ else
+ len = len*10 + ch - '0';
+ goto nextch;
+ case '*':
+ if (pointflag)
+ maxwidth = va_arg( args, int );
+ else
+ len = va_arg( args, int );
+ goto nextch;
+ case '.': pointflag = 1; goto nextch;
+ case 'l': longflag = 1; goto nextch;
+ case 'u': case 'U':
+ /*fmtnum(value,base,dosign,ljust,len,zpad) */
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 10,0, ljust, len, zpad ); break;
+ case 'o': case 'O':
+ /*fmtnum(value,base,dosign,ljust,len,zpad) */
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 8,0, ljust, len, zpad ); break;
+ case 'd': case 'D':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 10,1, ljust, len, zpad ); break;
+ case 'x':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 16,0, ljust, len, zpad ); break;
+ case 'X':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value,-16,0, ljust, len, zpad ); break;
+ case 's':
+ strvalue = va_arg( args, char *);
+ if (maxwidth > 0 || !pointflag) {
+ if (pointflag && len > maxwidth)
+ len = maxwidth; /* Adjust padding */
+ fmtstr( strvalue,ljust,len,zpad, maxwidth);
+ }
+ break;
+ case 'c':
+ ch = va_arg( args, int );
+ dopr_outch( ch ); break;
+ case '%': dopr_outch( ch ); continue;
+ default:
+ dostr( "???????" , 0);
+ }
+ break;
+ default:
+ dopr_outch( ch );
+ break;
+ }
+ }
+ *output = 0;
+}
+
+static void
+fmtstr( value, ljust, len, zpad, maxwidth )
+ char *value;
+ int ljust, len, zpad, maxwidth;
+{
+ int padlen, strlen; /* amount to pad */
+
+ if( value == 0 ){
+ value = "<NULL>";
+ }
+ for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */
+ if (strlen > maxwidth && maxwidth)
+ strlen = maxwidth;
+ padlen = len - strlen;
+ if( padlen < 0 ) padlen = 0;
+ if( ljust ) padlen = -padlen;
+ while( padlen > 0 ) {
+ dopr_outch( ' ' );
+ --padlen;
+ }
+ dostr( value, maxwidth );
+ while( padlen < 0 ) {
+ dopr_outch( ' ' );
+ ++padlen;
+ }
+}
+
+static void
+fmtnum( value, base, dosign, ljust, len, zpad )
+ long value;
+ int base, dosign, ljust, len, zpad;
+{
+ int signvalue = 0;
+ unsigned long uvalue;
+ char convert[20];
+ int place = 0;
+ int padlen = 0; /* amount to pad */
+ int caps = 0;
+
+ /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
+ value, base, dosign, ljust, len, zpad )); */
+ uvalue = value;
+ if( dosign ){
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ }
+ }
+ if( base < 0 ){
+ caps = 1;
+ base = -base;
+ }
+ do{
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ }while(uvalue);
+ convert[place] = 0;
+ padlen = len - place;
+ if( padlen < 0 ) padlen = 0;
+ if( ljust ) padlen = -padlen;
+ /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
+ convert,place,signvalue,padlen)); */
+ if( zpad && padlen > 0 ){
+ if( signvalue ){
+ dopr_outch( signvalue );
+ --padlen;
+ signvalue = 0;
+ }
+ while( padlen > 0 ){
+ dopr_outch( zpad );
+ --padlen;
+ }
+ }
+ while( padlen > 0 ) {
+ dopr_outch( ' ' );
+ --padlen;
+ }
+ if( signvalue ) dopr_outch( signvalue );
+ while( place > 0 ) dopr_outch( convert[--place] );
+ while( padlen < 0 ){
+ dopr_outch( ' ' );
+ ++padlen;
+ }
+}
+
+static void
+dostr( str , cut)
+ char *str;
+ int cut;
+{
+ if (cut) {
+ while(*str && cut-- > 0) dopr_outch(*str++);
+ } else {
+ while(*str) dopr_outch(*str++);
+ }
+}
+
+static void
+dopr_outch( c )
+ int c;
+{
+ if( end == 0 || output < end )
+ *output++ = c;
+}
+
+int
+# ifdef __STDC__
+vsyslog(int priority, const char *fmt, ...)
+# else /* __STDC__ */
+vsyslog(priority, fmt, va_alist)
+ int priority;
+ const char *fmt;
+ va_dcl
+# endif /* __STDC__ */
+{
+ VA_LOCAL_DECL
+ char logbuf[BUFSIZ];
+
+ VA_START(fmt);
+
+ vsnprintf(logbuf, BUFSIZ, fmt, ap);
+ syslog(priority, "%s", logbuf);
+
+ VA_END;
+}
+#endif /* __hpux */
+
+void pam_vsystem_log(const pam_handle_t *pamh,
+ const struct pam_log_state *log_state,
+ int priority, const char *format, va_list args)
+{
+ const char *ident;
+ int option, facility;
+
+ D(("pam_vsystem_log called"));
+
+ /* make sure we have a log state to use */
+ if (NULL == log_state) {
+ if (NULL != pamh && NULL != pamh->pam_default_log.ident) {
+ ident = pamh->pam_default_log.ident;
+ option = pamh->pam_default_log.option;
+ facility = pamh->pam_default_log.facility;
+ } else {
+ ident = PAM_LOG_STATE_IDENT;
+ option = PAM_LOG_STATE_OPTION;
+ facility = PAM_LOG_STATE_FACILITY;
+ }
+ openlog(ident, option, facility);
+ } else {
+ openlog(log_state->ident, log_state->option, log_state->facility);
+ }
+
+ vsyslog(priority, format, args);
+ closelog();
+
+ D(("done."));
+}
+
+void pam_system_log(const pam_handle_t *pamh,
+ const struct pam_log_state *log_state,
+ int priority, const char *format, ... )
+{
+ const char *ident;
+ int option, facility;
+ va_list args;
+
+ D(("pam_system_log called"));
+
+ /* make sure we have a log state to use */
+ if (NULL == log_state) {
+ if (NULL != pamh && NULL != pamh->pam_default_log.ident) {
+ ident = pamh->pam_default_log.ident;
+ option = pamh->pam_default_log.option;
+ facility = pamh->pam_default_log.facility;
+ } else {
+ ident = PAM_LOG_STATE_IDENT;
+ option = PAM_LOG_STATE_OPTION;
+ facility = PAM_LOG_STATE_FACILITY;
+ }
+ openlog(ident, option, facility);
+ } else {
+ openlog(log_state->ident, log_state->option, log_state->facility);
+ }
+
+ va_start(args, format);
+ vsyslog(priority, format, args);
+ va_end(args);
+ closelog();
+
+ D(("done."));
+}
+
+/*
+ * Recommended #defines to make porting legacy apps easier [Ed. at this
+ * point, the syslog() #define is breoken -- suggestions?]
+ *
+ * #ifdef PAM_LOG_STATE
+ * # define openlog(ident, option, facility) { \
+ * struct pam_log_state tmp_state; \
+ * tmp_state.ident = ident; \
+ * tmp_state.option = option; \
+ * tmp_state.facility = facility; \
+ * (void) pam_set_item(pamh, PAM_LOG_STATE, &tmp_state); \
+ * }
+ * # define syslog pam_system_log
+ * # define closelog()
+ * #endif
+ */
diff --git a/contrib/libpam/libpam/pam_malloc.c b/contrib/libpam/libpam/pam_malloc.c
new file mode 100644
index 000000000000..cc66f1aad6c7
--- /dev/null
+++ b/contrib/libpam/libpam/pam_malloc.c
@@ -0,0 +1,394 @@
+/*
+ * $Id: pam_malloc.c,v 1.2 1996/12/01 03:14:13 morgan Exp $
+ *
+ * $Log: pam_malloc.c,v $
+ * Revision 1.2 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.1 1996/11/10 21:26:11 morgan
+ * Initial revision
+ *
+ */
+
+/*
+ * This pair of files helps to locate memory leaks. It is a wrapper for
+ * the malloc family of calls. (Actutally, it currently only deals
+ * with calloc, malloc, realloc, free and exit)
+ *
+ * To use these functions the header "pam_malloc.h" must be included
+ * in all parts of the code (that use the malloc functions) and this
+ * file must be linked with the result. The pam_malloc_flags can be
+ * set from another function and determine the level of logging.
+ *
+ * The output is via the macros defined in _pam_macros.h
+ *
+ * It is a debugging tool and should be turned off in released code.
+ *
+ * This suite was written by Andrew Morgan <morgan@parc.power.net> for
+ * Linux-PAM.
+ */
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#include "pam_private.h"
+
+#include <security/pam_malloc.h>
+#include <security/_pam_macros.h>
+
+/* this must be done to stop infinite recursion! */
+#undef malloc
+#undef calloc
+#undef free
+#undef realloc
+#undef exit
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * default debugging level
+ */
+
+int pam_malloc_flags = PAM_MALLOC_DEFAULT;
+int pam_malloc_delay_length = 4;
+
+#define on(x) ((pam_malloc_flags&(x))==(x))
+
+/*
+ * the implementation
+ */
+
+static const char *last_fn=NULL;
+static const char *last_file=NULL;
+static const char *last_call=NULL;
+static int last_line = 1;
+
+#define err(x) { _pam_output_xdebug_info(); _pam_output_debug x ; }
+
+static void set_last_(const char *x, const char *f
+ , const char *fn, const int l)
+{
+ last_fn = x ? x : "error-in-pam_malloc..";
+ last_file = f ? f : "*bad-file*";
+ last_call = fn ? fn: "*bad-fn*";
+ last_line = l;
+}
+
+static void _pam_output_xdebug_info(void)
+{
+ FILE *logfile;
+ int must_close = 1;
+
+ if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
+ logfile = stderr;
+ must_close = 0;
+ }
+ fprintf(logfile, "[%s:%s(%d)->%s()] ",
+ last_file, last_call, last_line, last_fn);
+ if (must_close) {
+ fflush(logfile);
+ fclose(logfile);
+ }
+}
+
+static void hinder(void)
+{
+ if (on(PAM_MALLOC_PAUSE)) {
+ if (on(0)) err(("pause requested"));
+ sleep(pam_malloc_delay_length);
+ }
+
+ if (on(PAM_MALLOC_STOP)) {
+ if (on(0)) err(("stop requested"));
+ exit(1);
+ }
+}
+
+/*
+ * here are the memory pointer registering functions.. these actually
+ * use malloc(!) but that's ok! ;^)
+ */
+
+struct reference {
+ void *ptr; /* pointer */
+ int nelements; /* number of elements */
+ int size; /* - each of this size */
+ char *file; /* where it was requested - filename */
+ char *function; /* - function */
+ int line; /* - line number */
+/*
+ * linking info
+ */
+ struct reference *next;
+};
+
+static void _dump(const char *say, const struct reference *ref)
+{
+ _pam_output_debug(" <%s: %p (#%d of %d) req. by %s(); %s line %d>\n"
+ , say
+ , ref->ptr,ref->nelements,ref->size
+ , ref->function,ref->file,ref->line);
+}
+
+static struct reference *root=NULL;
+
+static char *_strdup(const char *x)
+{
+ char *s;
+
+ s = (char *)malloc(strlen(x)+1);
+ if (s == NULL) {
+ if (on(0)) err(("_strdup failed"));
+ exit(1);
+ }
+
+ strcpy(s,x);
+ return s;
+}
+
+static void add_new_ref(void *new, int n, int size)
+{
+ struct reference *ref=NULL;
+
+ ref = (struct reference *) malloc( sizeof(struct reference) );
+ if (new == NULL || ref == NULL) {
+ if (on(0)) err(("internal error {add_new_ref}"));
+ exit(1);
+ }
+
+ ref->ptr = new;
+ ref->nelements = n;
+ ref->size = size;
+
+ ref->file = _strdup(last_file);
+ ref->function = _strdup(last_call);
+ ref->line = last_line;
+
+ ref->next = root;
+
+ if (on(PAM_MALLOC_REQUEST)) {
+ _dump("new_ptr", ref);
+ }
+
+ root = ref;
+}
+
+static void del_old_ref(void *old)
+{
+ struct reference *this,*last;
+
+ if (old == NULL) {
+ if (on(0)) err(("internal error {del_old_ref}"));
+ exit(1);
+ }
+
+ /* locate old pointer */
+
+ last = NULL;
+ this = root;
+ while (this) {
+ if (this->ptr == old)
+ break;
+ last = this;
+ this = this->next;
+ }
+
+ /* Did we find a reference ? */
+
+ if (this) {
+ if (on(PAM_MALLOC_FREE)) {
+ _dump("free old_ptr", this);
+ }
+ if (last == NULL) {
+ root = this->next;
+ } else {
+ last->next = this->next;
+ }
+ free(this->file);
+ free(this->function);
+ free(this);
+ } else {
+ if (on(0)) err(("ERROR!: bad memory"));
+ hinder();
+ }
+}
+
+static void verify_old_ref(void *old)
+{
+ struct reference *this;
+
+ if (old == NULL) {
+ if (on(0)) err(("internal error {verify_old_ref}"));
+ exit(1);
+ }
+
+ /* locate old pointer */
+
+ this = root;
+ while (this) {
+ if (this->ptr == old)
+ break;
+ this = this->next;
+ }
+
+ /* Did we find a reference ? */
+
+ if (this) {
+ if (on(PAM_MALLOC_VERIFY)) {
+ _dump("verify_ptr", this);
+ }
+ } else {
+ if (on(0)) err(("ERROR!: bad request"));
+ hinder();
+ }
+}
+
+static void dump_memory_list(const char *dump)
+{
+ struct reference *this;
+
+ this = root;
+ if (this) {
+ if (on(0)) err(("un-free()'d memory"));
+ while (this) {
+ _dump(dump, this);
+ this = this->next;
+ }
+ } else {
+ if (on(0)) err(("no memory allocated"));
+ }
+}
+
+/* now for the wrappers */
+
+#define _fn(x) set_last_(x,file,fn,line)
+
+void *pam_malloc(size_t size, const char *file, const char *fn, const int line)
+{
+ void *new;
+
+ _fn("malloc");
+
+ if (on(PAM_MALLOC_FUNC)) err(("request for %d", size));
+
+ new = malloc(size);
+ if (new == NULL) {
+ if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
+ } else {
+ if (on(PAM_MALLOC_REQUEST)) err(("request new"));
+ add_new_ref(new, 1, size);
+ }
+
+ return new;
+}
+
+void *pam_calloc(size_t nelm, size_t size
+ , const char *file, const char *fn, const int line)
+{
+ void *new;
+
+ _fn("calloc");
+
+ if (on(PAM_MALLOC_FUNC)) err(("request for %d of %d", nelm, size));
+
+ new = calloc(nelm,size);
+ if (new == NULL) {
+ if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
+ } else {
+ if (on(PAM_MALLOC_REQUEST)) err(("request new"));
+ add_new_ref(new, nelm, size);
+ }
+
+ return new;
+}
+
+void pam_free(void *ptr
+ , const char *file, const char *fn, const int line)
+{
+ _fn("free");
+
+ if (on(PAM_MALLOC_FUNC)) err(("request to free %p", ptr));
+
+ if (ptr == NULL) {
+ if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
+ } else {
+ if (on(PAM_MALLOC_FREE)) err(("deleted old"));
+ del_old_ref(ptr);
+ free(ptr);
+ }
+}
+
+void *pam_memalign(size_t ali, size_t size
+ , const char *file, const char *fn, const int line)
+{
+ _fn("memalign");
+ if (on(0)) err(("not implemented currently (Sorry)"));
+ exit(1);
+}
+
+void *pam_realloc(void *ptr, size_t size
+ , const char *file, const char *fn, const int line)
+{
+ void *new;
+
+ _fn("realloc");
+
+ if (on(PAM_MALLOC_FUNC)) err(("resize %p to %d", ptr, size));
+
+ if (ptr == NULL) {
+ if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
+ } else {
+ verify_old_ref(ptr);
+ }
+
+ new = realloc(ptr, size);
+ if (new == NULL) {
+ if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
+ } else {
+ if (ptr) {
+ if (on(PAM_MALLOC_FREE)) err(("deleted old"));
+ del_old_ref(ptr);
+ } else {
+ if (on(PAM_MALLOC_NULL)) err(("old is NULL"));
+ }
+ if (on(PAM_MALLOC_REQUEST)) err(("request new"));
+ add_new_ref(new, 1, size);
+ }
+
+ return new;
+}
+
+void *pam_valloc(size_t size
+ , const char *file, const char *fn, const int line)
+{
+ _fn("valloc");
+ if (on(0)) err(("not implemented currently (Sorry)"));
+ exit(1);
+}
+
+#include <alloca.h>
+
+void *pam_alloca(size_t size
+ , const char *file, const char *fn, const int line)
+{
+ _fn("alloca");
+ if (on(0)) err(("not implemented currently (Sorry)"));
+ exit(1);
+}
+
+void pam_exit(int i
+ , const char *file, const char *fn, const int line)
+{
+ _fn("exit");
+
+ if (on(0)) err(("passed (%d)", i));
+ if (on(PAM_MALLOC_LEAKED)) {
+ dump_memory_list("leaked");
+ }
+ exit(i);
+}
+
+/* end of file */
diff --git a/contrib/libpam/libpam/pam_map.c b/contrib/libpam/libpam/pam_map.c
new file mode 100644
index 000000000000..6e186b703bb0
--- /dev/null
+++ b/contrib/libpam/libpam/pam_map.c
@@ -0,0 +1,79 @@
+/* pam_map.c - PAM mapping interface
+ *
+ * $Id$
+ *
+ * This is based on the X/Open XSSO specification of March 1997.
+ * It is not implemented as it is going to change... after 1997/9/25.
+ *
+ * $Log$
+ */
+
+#include <stdio.h>
+
+#include "pam_private.h"
+
+/* p 54 */
+
+int pam_get_mapped_authtok(pam_handle_t *pamh,
+ const char *target_module_username,
+ const char *target_module_type,
+ const char *target_authn_domain,
+ size_t *target_authtok_len
+ unsigned char **target_module_authtok);
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_get_mapped_authtok",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
+
+/* p 68 */
+
+int pam_set_mapped_authtok(pam_handle_t *pamh,
+ char *target_module_username,
+ size_t *target_authtok_len,
+ unsigned char *target_module_authtok,
+ char *target_module_type,
+ char *target_authn_domain)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_set_mapped_authtok",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
+
+/* p 56 */
+
+int pam_get_mapped_username(pam_handle_t *pamh,
+ const char *src_username,
+ const char *src_module_type,
+ const char *src_authn_domain,
+ const char *target_module_type,
+ const char *target_authn_domain,
+ char **target_module_username)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_get_mapped_username",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
+
+/* p 70 */
+
+int pam_set_mapped_username(pam_handle_t *pamh,
+ char *src_username,
+ char *src_module_type,
+ char *src_authn_domain,
+ char *target_module_username,
+ char *target_module_type,
+ char *target_authn_domain)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_set_mapped_username",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
diff --git a/contrib/libpam/libpam/pam_misc.c b/contrib/libpam/libpam/pam_misc.c
new file mode 100644
index 000000000000..6fed9ba126b9
--- /dev/null
+++ b/contrib/libpam/libpam/pam_misc.c
@@ -0,0 +1,334 @@
+/* pam_misc.c -- This is random stuff */
+
+/* $Id: pam_misc.c,v 1.9 1997/04/05 06:56:19 morgan Exp $
+ *
+ * $Log: pam_misc.c,v $
+ * Revision 1.9 1997/04/05 06:56:19 morgan
+ * enforce AUTHTOK restrictions
+ *
+ * Revision 1.8 1997/02/15 15:59:46 morgan
+ * modified ..strCMP comment
+ *
+ * Revision 1.7 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.6 1996/11/10 20:05:52 morgan
+ * name convention _pam_ enforced. Also modified _pam_strdup()
+ *
+ * Revision 1.5 1996/07/07 23:57:14 morgan
+ * deleted debuggin function and replaced it with a static function
+ * defined in pam_private.h
+ *
+ * Revision 1.4 1996/06/02 08:00:56 morgan
+ * added StrTok function
+ *
+ * Revision 1.3 1996/05/21 04:36:58 morgan
+ * added debugging information
+ * replaced the _pam_log need for a local buffer with a call to vsyslog()
+ * [Al Longyear had some segfaulting problems related to this]
+ *
+ * Revision 1.2 1996/03/16 21:55:13 morgan
+ * changed pam_mkargv to _pam_mkargv
+ *
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#include "pam_private.h"
+
+/* caseless string comparison: POSIX does not define this.. */
+int _pam_strCMP(const char *s, const char *t)
+{
+ int cf;
+
+ do {
+ cf = tolower(*s) - tolower(*t);
+ ++t;
+ } while (!cf && *s++);
+
+ return cf;
+}
+
+char *_pam_StrTok(char *from, const char *format, char **next)
+/*
+ * this function is a variant of the standard strtok, it differs in that
+ * it takes an additional argument and doesn't nul terminate tokens until
+ * they are actually reached.
+ */
+{
+ char table[256], *end;
+ int i;
+
+ if (from == NULL && (from = *next) == NULL)
+ return from;
+
+ /* initialize table */
+ for (i=1; i<256; table[i++] = '\0');
+ for (i=0; format[i] ; table[(int)format[i++]] = 'y');
+
+ /* look for first non-blank char */
+ while (*from && table[(int)*from]) {
+ ++from;
+ }
+
+ if (*from == '[') {
+ /*
+ * special case, "[...]" is considered to be a single
+ * object. Note, however, if one of the format[] chars is
+ * '[' this single string will not be read correctly.
+ */
+ for (end=++from; *end && *end != ']'; ++end) {
+ if (*end == '\\' && end[1] == ']')
+ ++end;
+ }
+ /* note, this string is stripped of its edges: "..." is what
+ remains */
+ } else if (*from) {
+ /* simply look for next blank char */
+ for (end=from; *end && !table[(int)*end]; ++end);
+ } else {
+ return (*next = NULL); /* no tokens left */
+ }
+
+ /* now terminate what we have */
+ if (*end)
+ *end++ = '\0';
+
+ /* indicate what it left */
+ if (*end) {
+ *next = end;
+ } else {
+ *next = NULL; /* have found last token */
+ }
+
+ /* return what we have */
+ return from;
+}
+
+/*
+ * Safe duplication of character strings. "Paranoid"; don't leave
+ * evidence of old token around for later stack analysis.
+ */
+
+char *_pam_strdup(const char *x)
+{
+ register char *new=NULL;
+
+ if (x != NULL) {
+ register int i;
+
+ for (i=0; x[i]; ++i); /* length of string */
+ if ((new = malloc(++i)) == NULL) {
+ i = 0;
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "_pam_strdup: failed to get memory");
+ } else {
+ while (i-- > 0) {
+ new[i] = x[i];
+ }
+ }
+ x = NULL;
+ }
+
+ return new; /* return the duplicate or NULL on error */
+}
+
+/* Generate argv, argc from s */
+/* caller must free(argv) */
+
+int _pam_mkargv(char *s, char ***argv, int *argc)
+{
+ int l;
+ int argvlen = 0;
+ char *sbuf, *sbuf_start;
+ char **our_argv = NULL;
+ char **argvbuf;
+ char *argvbufp;
+#ifdef DEBUG
+ int count=0;
+#endif
+
+ D(("_pam_mkargv called: %s",s));
+
+ *argc = 0;
+
+ l = strlen(s);
+ if (l) {
+ if ((sbuf = sbuf_start = _pam_strdup(s)) == NULL) {
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "pam_mkargv: null returned by _pam_strdup");
+ D(("arg NULL"));
+ } else {
+ /* Overkill on the malloc, but not large */
+ argvlen = (l + 1) * ((sizeof(char)) + sizeof(char *));
+ if ((our_argv = argvbuf = malloc(argvlen)) == NULL) {
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "pam_mkargv: null returned by malloc");
+ } else {
+ char *tmp=NULL;
+
+ argvbufp = (char *) argvbuf + (l * sizeof(char *));
+ D(("[%s]",sbuf));
+ while ((sbuf = _pam_StrTok(sbuf, " \n\t", &tmp))) {
+ D(("arg #%d",++count));
+ D(("->[%s]",sbuf));
+ strcpy(argvbufp, sbuf);
+ D(("copied token"));
+ *argvbuf = argvbufp;
+ argvbufp += strlen(argvbufp) + 1;
+ D(("stepped in argvbufp"));
+ (*argc)++;
+ argvbuf++;
+ sbuf = NULL;
+ D(("loop again?"));
+ }
+ _pam_drop(sbuf_start);
+ }
+ }
+ }
+
+ *argv = our_argv;
+
+ D(("_pam_mkargv returned"));
+
+ return(argvlen);
+}
+
+/*
+ * this function is used to protect the modules from accidental or
+ * semi-mallicious harm that an application may do to confuse the API.
+ */
+
+void _pam_sanitize(pam_handle_t *pamh)
+{
+ /*
+ * this is for security. We reset the auth-tokens here.
+ */
+ pam_set_item(pamh,PAM_AUTHTOK,NULL);
+ pam_set_item(pamh,PAM_OLDAUTHTOK,NULL);
+}
+
+/*
+ * This function scans the array and replaces the _PAM_ACTION_UNDEF
+ * entries with the default action.
+ */
+
+void _pam_set_default_control(int *control_array, int default_action)
+{
+ int i;
+
+ for (i=0; i<_PAM_RETURN_VALUES; ++i) {
+ if (control_array[i] == _PAM_ACTION_UNDEF) {
+ control_array[i] = default_action;
+ }
+ }
+}
+
+/*
+ * This function is used to parse a control string. This string is a
+ * series of tokens of the following form:
+ *
+ * "[ ]*return_code[ ]*=[ ]*action/[ ]".
+ */
+
+#include "pam_tokens.h"
+
+void _pam_parse_control(int *control_array, char *tok)
+{
+ const char *error;
+ int ret;
+
+ while (*tok) {
+ int act, len;
+
+ /* skip leading space */
+ while (isspace(*tok) && *++tok);
+ if (!*tok)
+ break;
+
+ /* identify return code */
+ for (ret=0; ret<=_PAM_RETURN_VALUES; ++ret) {
+ len = strlen(_pam_token_returns[ret]);
+ if (!strncmp(_pam_token_returns[ret], tok, len)) {
+ break;
+ }
+ }
+ if (ret > _PAM_RETURN_VALUES || !*(tok += len)) {
+ error = "expecting return value";
+ goto parse_error;
+ }
+
+ /* observe '=' */
+ while (isspace(*tok) && *++tok);
+ if (!*tok || *tok++ != '=') {
+ error = "expecting '='";
+ goto parse_error;
+ }
+
+ /* skip leading space */
+ while (isspace(*tok) && *++tok);
+ if (!*tok) {
+ error = "expecting action";
+ goto parse_error;
+ }
+
+ /* observe action type */
+ for (act=0; act<=-_PAM_ACTION_UNDEF; ++act) {
+ len = strlen(_pam_token_actions[act]);
+ if (!strncmp(_pam_token_actions[act], tok, len)) {
+ act *= -1;
+ tok += len;
+ break;
+ }
+ }
+ if (act > 0) {
+ /*
+ * Either we have a number or we have hit an error. In
+ * principle, there is nothing to stop us accepting
+ * negative offsets. (Although we would have to think of
+ * another way of encoding the tokens.) However, I really
+ * think this would be both hard to administer and easily
+ * cause looping problems. So, for now, we will just
+ * allow forward jumps. (AGM 1998/1/7)
+ */
+ if (!isdigit(*tok)) {
+ error = "expecting jump number";
+ goto parse_error;
+ }
+ /* parse a number */
+ act = 0;
+ do {
+ act *= 10;
+ act += *tok - '0'; /* XXX - this assumes ascii behavior */
+ } while (*++tok && isdigit(*tok));
+ if (! act) {
+ /* we do not allow 0 jumps. There is a token ('ignore')
+ for that */
+ error = "expecting non-zero";
+ goto parse_error;
+ }
+ }
+
+ /* set control_array element */
+ if (ret != _PAM_RETURN_VALUES) {
+ control_array[ret] = act;
+ } else {
+ /* set the default to 'act' */
+ _pam_set_default_control(control_array, act);
+ }
+ }
+
+ /* that was a success */
+ return;
+
+parse_error:
+ /* treat everything as bad */
+ pam_system_log(NULL, NULL, LOG_ERR, "pam_parse: %s; [...%s]", error, tok);
+ for (ret=0; ret<_PAM_RETURN_VALUES; control_array[ret++]=_PAM_ACTION_BAD);
+
+}
diff --git a/contrib/libpam/libpam/pam_password.c b/contrib/libpam/libpam/pam_password.c
new file mode 100644
index 000000000000..303425ab6254
--- /dev/null
+++ b/contrib/libpam/libpam/pam_password.c
@@ -0,0 +1,51 @@
+/* pam_password.c - PAM Password Management */
+
+/*
+ * $Id: pam_password.c,v 1.7 1997/04/05 06:56:45 morgan Exp $
+ *
+ * $Log: pam_password.c,v $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+int pam_chauthtok(pam_handle_t *pamh, int flags)
+{
+ int retval;
+
+ D(("called."));
+
+ IF_NO_PAMH("pam_chauthtok", pamh, PAM_SYSTEM_ERR);
+
+ if (pamh->former.choice == PAM_NOT_STACKED) {
+ _pam_start_timer(pamh); /* we try to make the time for a failure
+ independent of the time it takes to
+ fail */
+ _pam_sanitize(pamh);
+ pamh->former.update = PAM_FALSE;
+ }
+
+ /* first loop through to check if there will be a problem */
+ if (pamh->former.update ||
+ (retval = _pam_dispatch(pamh, flags|PAM_PRELIM_CHECK,
+ PAM_CHAUTHTOK)) == PAM_SUCCESS) {
+ pamh->former.update = PAM_TRUE;
+ retval = _pam_dispatch(pamh, flags|PAM_UPDATE_AUTHTOK,
+ PAM_CHAUTHTOK);
+ }
+
+ /* if we completed we should clean up */
+ if (retval != PAM_INCOMPLETE) {
+ _pam_sanitize(pamh);
+ pamh->former.update = PAM_FALSE;
+ _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
+ D(("pam_authenticate exit"));
+ } else {
+ D(("will resume when ready"));
+ }
+
+ return retval;
+}
+
diff --git a/contrib/libpam/libpam/pam_private.h b/contrib/libpam/libpam/pam_private.h
new file mode 100644
index 000000000000..f8a0da54fc94
--- /dev/null
+++ b/contrib/libpam/libpam/pam_private.h
@@ -0,0 +1,322 @@
+/*
+ * pam_private.h
+ *
+ * $Id: pam_private.h,v 1.12 1997/04/05 06:57:37 morgan Exp morgan $
+ *
+ * This is the Linux-PAM Library Private Header. It contains things
+ * internal to the Linux-PAM library. Things not needed by either an
+ * application or module.
+ *
+ * Please see end of file for copyright.
+ *
+ * Creator: Marc Ewing.
+ * Maintained: AGM
+ *
+ * $Log: pam_private.h,v $
+ */
+
+#ifndef _PAM_PRIVATE_H
+#define _PAM_PRIVATE_H
+
+/* this is not used at the moment --- AGM */
+#define LIBPAM_VERSION 65
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+/* the Linux-PAM configuration file */
+
+#define PAM_CONFIG "/etc/pam.conf"
+#define PAM_CONFIG_D "/etc/pam.d"
+#define PAM_CONFIG_DF "/etc/pam.d/%s"
+
+#define PAM_DEFAULT_SERVICE "other" /* lower case */
+#define PAM_DEFAULT_SERVICE_FILE PAM_CONFIG_D "/" PAM_DEFAULT_SERVICE
+
+#ifdef PAM_LOCKING
+/*
+ * the Linux-PAM lock file. If it exists Linux-PAM will abort. Use it
+ * to block access to libpam
+ */
+#define PAM_LOCK_FILE "/var/lock/subsys/PAM"
+#endif
+
+/* components of the pam_handle structure */
+
+struct handler {
+ int must_fail;
+ int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv);
+ int actions[_PAM_RETURN_VALUES];
+ int argc;
+ char **argv;
+ struct handler *next;
+};
+
+struct loaded_module {
+ char *name;
+ int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */
+ void *dl_handle;
+};
+
+#define PAM_MT_DYNAMIC_MOD 0
+#define PAM_MT_STATIC_MOD 1
+#define PAM_MT_FAULTY_MOD 2
+
+struct handlers {
+ struct handler *authenticate;
+ struct handler *setcred;
+ struct handler *acct_mgmt;
+ struct handler *open_session;
+ struct handler *close_session;
+ struct handler *chauthtok;
+};
+
+struct service {
+ struct loaded_module *module; /* Only used for dynamic loading */
+ int modules_allocated;
+ int modules_used;
+ int handlers_loaded;
+
+ struct handlers conf; /* the configured handlers */
+ struct handlers other; /* the default handlers */
+};
+
+/*
+ * Environment helper functions
+ */
+
+#define PAM_ENV_CHUNK 10 /* chunks of memory calloc()'d *
+ * at once */
+
+struct pam_environ {
+ int entries; /* the number of pointers available */
+ int requested; /* the number of pointers used: *
+ * 1 <= requested <= entries */
+ char **list; /* the environment storage (a list *
+ * of pointers to malloc() memory) */
+};
+
+#include <sys/time.h>
+
+typedef enum { PAM_FALSE, PAM_TRUE } _pam_boolean;
+
+struct _pam_fail_delay {
+ _pam_boolean set;
+ unsigned int delay;
+ time_t begin;
+ const void *delay_fn_ptr;
+};
+
+struct _pam_former_state {
+/* this is known and set by _pam_dispatch() */
+ int choice; /* which flavor of module function did we call? */
+
+/* state info for the _pam_dispatch_aux() function */
+ int depth; /* how deep in the stack were we? */
+ int impression; /* the impression at that time */
+ int status; /* the status before returning incomplete */
+
+/* state info used by pam_get_user() function */
+ int want_user;
+ char *prompt; /* saved prompt information */
+
+/* state info for the pam_chauthtok() function */
+ _pam_boolean update;
+};
+
+struct pam_handle {
+ char *authtok;
+ struct pam_conv *pam_conversation;
+ char *oldauthtok;
+ char *prompt; /* for use by pam_get_user() */
+ char *service_name;
+ char *user;
+ char *rhost;
+ char *ruser;
+ char *tty;
+ struct pam_log_state pam_default_log; /* for ident etc., log state */
+ struct pam_data *data;
+ struct pam_environ *env; /* structure to maintain environment list */
+ struct _pam_fail_delay fail_delay; /* helper function for easy delays */
+ struct service handlers;
+ struct _pam_former_state former; /* library state - support for
+ event driven applications */
+};
+
+/* Values for select arg to _pam_dispatch() */
+#define PAM_NOT_STACKED 0
+#define PAM_AUTHENTICATE 1
+#define PAM_SETCRED 2
+#define PAM_ACCOUNT 3
+#define PAM_OPEN_SESSION 4
+#define PAM_CLOSE_SESSION 5
+#define PAM_CHAUTHTOK 6
+
+#define _PAM_ACTION_IS_JUMP(x) ((x) > 0)
+#define _PAM_ACTION_IGNORE 0
+#define _PAM_ACTION_OK -1
+#define _PAM_ACTION_DONE -2
+#define _PAM_ACTION_BAD -3
+#define _PAM_ACTION_DIE -4
+#define _PAM_ACTION_RESET -5
+/* Add any new entries here. Will need to change ..._UNDEF and then
+ * need to change pam_tokens.h */
+#define _PAM_ACTION_UNDEF -6 /* this is treated as an error
+ ( = _PAM_ACTION_BAD) */
+
+/* character tables for parsing config files */
+extern const char * const _pam_token_actions[-_PAM_ACTION_UNDEF];
+extern const char * const _pam_token_returns[_PAM_RETURN_VALUES+1];
+
+/*
+ * internally defined functions --- these should not be directly
+ * called by applications or modules
+ */
+int _pam_dispatch(pam_handle_t *pamh, int flags, int choice);
+
+/* Free various allocated structures and dlclose() the libs */
+int _pam_free_handlers(pam_handle_t *pamh);
+
+/* Parse config file, allocate handler structures, dlopen() */
+int _pam_init_handlers(pam_handle_t *pamh);
+
+/* Set all hander stuff to 0/NULL - called once from pam_start() */
+void _pam_start_handlers(pam_handle_t *pamh);
+
+/* environment helper functions */
+
+/* create the environment structure */
+int _pam_make_env(pam_handle_t *pamh);
+
+/* delete the environment structure */
+void _pam_drop_env(pam_handle_t *pamh);
+
+#ifdef LINUX_PAM
+
+/* these functions deal with failure delays as required by the
+ authentication modules and application. Their *interface* is likely
+ to remain the same although their function is hopefully going to
+ improve */
+
+/* reset the timer to no-delay */
+void _pam_reset_timer(pam_handle_t *pamh);
+
+/* this sets the clock ticking */
+void _pam_start_timer(pam_handle_t *pamh);
+
+/* this waits for the clock to stop ticking if status != PAM_SUCCESS */
+void _pam_await_timer(pam_handle_t *pamh, int status);
+
+
+#endif /* LINUX_PAM */
+
+typedef void (*voidfunc(void))(void);
+#ifdef PAM_STATIC
+
+/* The next two in ../modules/_pam_static/pam_static.c */
+
+/* Return pointer to data structure used to define a static module */
+struct pam_module * _pam_open_static_handler(char *path);
+
+/* Return pointer to function requested from static module */
+
+voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname);
+
+#endif
+
+/* For now we just use a stack and linear search for module data. */
+/* If it becomes apparent that there is a lot of data, it should */
+/* changed to either a sorted list or a hash table. */
+
+struct pam_data {
+ char *name;
+ void *data;
+ void (*cleanup)(pam_handle_t *pamh, void *data, int error_status);
+ struct pam_data *next;
+};
+
+void _pam_free_data(pam_handle_t *pamh, int status);
+
+int _pam_strCMP(const char *s, const char *t);
+char *_pam_StrTok(char *from, const char *format, char **next);
+
+char *_pam_strdup(const char *s);
+
+int _pam_mkargv(char *s, char ***argv, int *argc);
+
+void _pam_sanitize(pam_handle_t *pamh);
+
+void _pam_set_default_control(int *control_array, int default_action);
+
+void _pam_parse_control(int *control_array, char *tok);
+
+/*
+ * XXX - Take care with this. It could confuse the logic of a trailing
+ * else
+ */
+
+#define IF_NO_PAMH(X,pamh,ERR) \
+if ((pamh) == NULL) { \
+ pam_system_log(NULL, NULL, LOG_ERR, X ": NULL pam handle passed"); \
+ return ERR; \
+}
+
+/* Definition for the default username prompt used by pam_get_user() */
+
+#define PAM_DEFAULT_PROMPT "Please enter username: "
+
+/*
+ * pam_system_log default ident/facility..
+ */
+
+#define PAM_LOG_STATE_DEFAULT { \
+ PAM_LOG_STATE_IDENT, \
+ PAM_LOG_STATE_OPTION, \
+ PAM_LOG_STATE_FACILITY \
+}
+
+/*
+ * include some helpful macros
+ */
+
+#include <security/_pam_macros.h>
+
+/*
+ * Copyright (C) 1995 by Red Hat Software, Marc Ewing
+ * Copyright (c) 1996-8, Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+#endif /* _PAM_PRIVATE_H_ */
diff --git a/contrib/libpam/libpam/pam_second.c b/contrib/libpam/libpam/pam_second.c
new file mode 100644
index 000000000000..b720774e7e61
--- /dev/null
+++ b/contrib/libpam/libpam/pam_second.c
@@ -0,0 +1,40 @@
+/*
+ * pam_second.c -- PAM secondary authentication
+ * (based on XSSO draft spec of March 1997)
+ *
+ * $Id$
+ *
+ * $Log$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+/* p 42 */
+
+int pam_authenticate_secondary(pam_handle_t *pamh,
+ char *target_username,
+ char *target_module_type,
+ char *target_authn_domain,
+ char *target_supp_data,
+ unsigned char *target_module_authtok,
+ int flags)
+{
+ int retval=PAM_SYSTEM_ERR;
+
+ D(("called"));
+
+ _pam_start_timer(pamh); /* we try to make the time for a failure
+ independent of the time it takes to
+ fail */
+
+ IF_NO_PAMH("pam_authenticate_secondary",pamh,PAM_SYSTEM_ERR);
+
+ _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
+
+ D(("pam_authenticate_secondary exit"));
+
+ return retval;
+}
diff --git a/contrib/libpam/libpam/pam_session.c b/contrib/libpam/libpam/pam_session.c
new file mode 100644
index 000000000000..38b93fe70549
--- /dev/null
+++ b/contrib/libpam/libpam/pam_session.c
@@ -0,0 +1,35 @@
+/* pam_session.c - PAM Session Management */
+
+/*
+ * $Id: pam_session.c,v 1.3 1996/12/01 03:14:13 morgan Exp $
+ *
+ * $Log: pam_session.c,v $
+ * Revision 1.3 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.2 1996/03/10 02:19:12 morgan
+ * some oversight meant that this wasn't being compiled. It needed a
+ * couple of changes.
+ *
+ *
+ */
+
+#include <stdio.h>
+
+#include "pam_private.h"
+
+int pam_open_session(pam_handle_t *pamh, int flags)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_open_session",pamh,PAM_SYSTEM_ERR);
+ return _pam_dispatch(pamh, flags, PAM_OPEN_SESSION);
+}
+
+int pam_close_session(pam_handle_t *pamh, int flags)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_close_session",pamh,PAM_SYSTEM_ERR);
+ return _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);
+}
diff --git a/contrib/libpam/libpam/pam_start.c b/contrib/libpam/libpam/pam_start.c
new file mode 100644
index 000000000000..53700a091029
--- /dev/null
+++ b/contrib/libpam/libpam/pam_start.c
@@ -0,0 +1,117 @@
+/* pam_start.c */
+
+/* Creator Marc Ewing
+ * Maintained by AGM
+ *
+ * $Id: pam_start.c,v 1.10 1997/04/05 06:58:11 morgan Exp $
+ *
+ * $Log: pam_start.c,v $
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "pam_private.h"
+
+int pam_start (
+ const char *service_name,
+ const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh)
+{
+ D(("called pam_start: [%s] [%s] [%p] [%p]"
+ ,service_name, user, pam_conversation, pamh));
+
+ if ((*pamh = calloc(1, sizeof(**pamh))) == NULL) {
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "pam_start: calloc failed for *pamh");
+ return (PAM_BUF_ERR);
+ }
+
+ if (service_name) {
+ char *tmp;
+
+ if (((*pamh)->service_name = _pam_strdup(service_name)) == NULL) {
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "pam_start: _pam_strdup failed for service name");
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ }
+ for (tmp=(*pamh)->service_name; *tmp; ++tmp)
+ *tmp = tolower(*tmp); /* require lower case */
+ } else
+ (*pamh)->service_name = NULL;
+
+ if (user) {
+ if (((*pamh)->user = _pam_strdup(user)) == NULL) {
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "pam_start: _pam_strdup failed for user");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ }
+ } else
+ (*pamh)->user = NULL;
+
+ (*pamh)->tty = NULL;
+ (*pamh)->prompt = NULL; /* prompt for pam_get_user() */
+ (*pamh)->ruser = NULL;
+ (*pamh)->rhost = NULL;
+ (*pamh)->authtok = NULL;
+ (*pamh)->oldauthtok = NULL;
+ (*pamh)->fail_delay.delay_fn_ptr = NULL;
+ (*pamh)->former.choice = PAM_NOT_STACKED;
+
+ if (pam_conversation == NULL
+ || ((*pamh)->pam_conversation = (struct pam_conv *)
+ malloc(sizeof(struct pam_conv))) == NULL) {
+ pam_system_log(NULL, NULL, LOG_CRIT,
+ "pam_start: malloc failed for pam_conv");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ } else {
+ memcpy((*pamh)->pam_conversation, pam_conversation,
+ sizeof(struct pam_conv));
+ }
+
+ (*pamh)->data = NULL;
+ if ( _pam_make_env(*pamh) != PAM_SUCCESS ) {
+ pam_system_log(NULL, NULL, LOG_ERR,
+ "pam_start: failed to initialize environment");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return PAM_ABORT;
+ }
+
+ _pam_reset_timer(*pamh); /* initialize timer support */
+
+ _pam_start_handlers(*pamh); /* cannot fail */
+
+ /* According to the SunOS man pages, loading modules and resolving
+ * symbols happens on the first call from the application. */
+
+ /*
+ * XXX - should we call _pam_init_handlers() here ? The following
+ * is new as of Linux-PAM 0.55
+ */
+
+ if ( _pam_init_handlers(*pamh) != PAM_SUCCESS ) {
+ pam_system_log(NULL, NULL, LOG_ERR,
+ "pam_start: failed to initialize handlers");
+ _pam_drop_env(*pamh); /* purge the environment */
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return PAM_ABORT;
+ }
+
+ D(("exiting pam_start successfully"));
+
+ return PAM_SUCCESS;
+}
diff --git a/contrib/libpam/libpam/pam_static.c b/contrib/libpam/libpam/pam_static.c
new file mode 100644
index 000000000000..d840a2dc6d2c
--- /dev/null
+++ b/contrib/libpam/libpam/pam_static.c
@@ -0,0 +1,153 @@
+/* pam_static.c -- static module loading helper functions */
+
+/* created by Michael K. Johnson, johnsonm@redhat.com
+ *
+ * $Id: pam_static.c,v 1.4 1996/12/01 03:14:13 morgan Exp $
+ *
+ * $Log: pam_static.c,v $
+ * Revision 1.4 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.3 1996/11/10 20:09:16 morgan
+ * name convention change _pam_
+ *
+ * Revision 1.2 1996/06/02 08:02:56 morgan
+ * Michael's minor alterations
+ *
+ * Revision 1.1 1996/05/26 04:34:04 morgan
+ * Initial revision
+ *
+ */
+
+/* This whole file is only used for PAM_STATIC */
+
+#ifdef PAM_STATIC
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pam_private.h"
+
+/*
+ * Need to include pointers to static modules; this was built by each
+ * of the modules that register...
+ */
+
+#include "../modules/_static_module_list"
+
+/*
+ * and here is a structure that connects libpam to the above static
+ * modules
+ */
+
+static struct pam_module *static_modules[] = {
+
+#include "../modules/_static_module_entry"
+
+ NULL
+};
+
+/*
+ * and now for the functions
+ */
+
+/* Return pointer to data structure used to define a static module */
+struct pam_module * _pam_open_static_handler(char *path) {
+ int i;
+ char *lpath = path, *end;
+
+ if (strchr(lpath, '/')) {
+ /* ignore path and leading "/" */
+ lpath = strrchr(lpath, '/') + 1;
+ }
+ /* create copy to muck with (must free before return) */
+ lpath = _pam_strdup(lpath);
+ /* chop .so off copy if it exists (or other extension on other
+ platform...) */
+ end = strstr(lpath, ".so");
+ if (end) {
+ *end = '\0';
+ }
+
+ /* now go find the module */
+ for (i = 0; static_modules[i] != NULL; i++) {
+ D(("%s=?%s\n", lpath, static_modules[i]->name));
+ if (static_modules[i]->name &&
+ ! strcmp(static_modules[i]->name, lpath)) {
+ break;
+ }
+ }
+
+ if (static_modules[i] == NULL) {
+ pam_system_log(pamh, NULL, LOG_ERR, "no static module named %s",
+ lpath);
+ }
+
+ free(lpath);
+ return (static_modules[i]);
+}
+
+/* Return pointer to function requested from static module
+ * Can't just return void *, because ANSI C disallows casting a
+ * pointer to a function to a void *...
+ * This definition means:
+ * _pam_get_static_sym is a function taking two arguments and
+ * returning a pointer to a function which takes no arguments
+ * and returns void... */
+voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname) {
+
+ if (! strcmp(symname, "pam_sm_authenticate")) {
+ return ((voidfunc *)mod->pam_sm_authenticate);
+ } else if (! strcmp(symname, "pam_sm_setcred")) {
+ return ((voidfunc *)mod->pam_sm_setcred);
+ } else if (! strcmp(symname, "pam_sm_acct_mgmt")) {
+ return ((voidfunc *)mod->pam_sm_acct_mgmt);
+ } else if (! strcmp(symname, "pam_sm_open_session")) {
+ return ((voidfunc *)mod->pam_sm_open_session);
+ } else if (! strcmp(symname, "pam_sm_close_session")) {
+ return ((voidfunc *)mod->pam_sm_close_session);
+ } else if (! strcmp(symname, "pam_sm_chauthtok")) {
+ return ((voidfunc *)mod->pam_sm_chauthtok);
+ }
+ /* getting to this point is an error */
+ return ((voidfunc *)NULL);
+}
+
+#endif /* PAM_STATIC */
+
+/*
+ * Copyright (C) 1995 by Red Hat Software, Michael K. Johnson
+ * All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/libpam/pam_strerror.c b/contrib/libpam/libpam/pam_strerror.c
new file mode 100644
index 000000000000..607c6d5dbfef
--- /dev/null
+++ b/contrib/libpam/libpam/pam_strerror.c
@@ -0,0 +1,106 @@
+/* pam_strerror.c */
+
+/* $Id: pam_strerror.c,v 1.6 1997/01/04 20:12:02 morgan Exp morgan $
+ *
+ * $Log: pam_strerror.c,v $
+ * Revision 1.6 1997/01/04 20:12:02 morgan
+ * replaced conditional FAIL_NOW with ABORT
+ *
+ * Revision 1.5 1996/07/07 23:58:56 morgan
+ * corrected "... " to "..."
+ *
+ * Revision 1.4 1996/06/02 08:03:29 morgan
+ * spelling correction
+ *
+ * Revision 1.3 1996/03/16 23:08:54 morgan
+ * PAM --> Linux-PAM ;)
+ *
+ */
+
+#include "pam_private.h"
+
+const char *pam_strerror(pam_handle_t *pamh, int errnum)
+{
+#ifdef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT /* will be removed from v 1.0 */
+
+ int possible_error;
+
+ possible_error = (int) pamh;
+ if (!(possible_error >= 0 && possible_error <= PAM_BAD_ITEM)) {
+ possible_error = errnum;
+ }
+
+/* mask standard behavior to use possible_error variable. */
+#define errnum possible_error
+
+#endif /* UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT */
+
+ switch (errnum) {
+ case PAM_SUCCESS:
+ return "Success";
+ case PAM_ABORT:
+ return "Critical error - immediate abort";
+ case PAM_OPEN_ERR:
+ return "dlopen() failure";
+ case PAM_SYMBOL_ERR:
+ return "Symbol not found";
+ case PAM_SERVICE_ERR:
+ return "Error in service module";
+ case PAM_SYSTEM_ERR:
+ return "System error";
+ case PAM_BUF_ERR:
+ return "Memory buffer error";
+ case PAM_PERM_DENIED:
+ return "Permission denied";
+ case PAM_AUTH_ERR:
+ return "Authentication failure";
+ case PAM_CRED_INSUFFICIENT:
+ return "Insufficient credentials to access authentication data";
+ case PAM_AUTHINFO_UNAVAIL:
+ return "Authentication service cannot retrieve authentication info.";
+ case PAM_USER_UNKNOWN:
+ return "User not known to the underlying authentication module";
+ case PAM_MAXTRIES:
+ return "Have exhasted maximum number of retries for service.";
+ case PAM_NEW_AUTHTOK_REQD:
+ return "Authentication token is no longer valid; new one required.";
+ case PAM_ACCT_EXPIRED:
+ return "User account has expired";
+ case PAM_SESSION_ERR:
+ return "Cannot make/remove an entry for the specified session";
+ case PAM_CRED_UNAVAIL:
+ return "Authentication service cannot retrieve user credentials";
+ case PAM_CRED_EXPIRED:
+ return "User credentials expired";
+ case PAM_CRED_ERR:
+ return "Failure setting user credentials";
+ case PAM_NO_MODULE_DATA:
+ return "No module specific data is present";
+ case PAM_BAD_ITEM:
+ return "Bad item passed to pam_*_item()";
+ case PAM_CONV_ERR:
+ return "Conversation error";
+ case PAM_AUTHTOK_ERR:
+ return "Authentication token manipulation error";
+ case PAM_AUTHTOK_RECOVER_ERR:
+ return "Authentication information cannot be recovered";
+ case PAM_AUTHTOK_LOCK_BUSY:
+ return "Authentication token lock busy";
+ case PAM_AUTHTOK_DISABLE_AGING:
+ return "Authentication token aging disabled";
+ case PAM_TRY_AGAIN:
+ return "Failed preliminary check by password service";
+ case PAM_IGNORE:
+ return "Please ignore underlying account module";
+ case PAM_MODULE_UNKNOWN:
+ return "Module is unknown";
+ case PAM_AUTHTOK_EXPIRED:
+ return "Authentication token expired";
+ case PAM_CONV_AGAIN:
+ return "Conversation is waiting for event";
+ case PAM_INCOMPLETE:
+ return "Application needs to call libpam again";
+ }
+
+ return "Unknown Linux-PAM error (need to upgrde libpam?)";
+}
diff --git a/contrib/libpam/libpam/pam_tokens.h b/contrib/libpam/libpam/pam_tokens.h
new file mode 100644
index 000000000000..9380f8837b96
--- /dev/null
+++ b/contrib/libpam/libpam/pam_tokens.h
@@ -0,0 +1,105 @@
+/*
+ * pam_tokens.h
+ *
+ * $Id$
+ *
+ * This is a Linux-PAM Library Private Header file. It contains tokens
+ * that are used when we parse the configuration file(s).
+ *
+ * Please see end of file for copyright.
+ *
+ * Creator: Andrew Morgan.
+ *
+ * $Log$
+ */
+
+#ifndef _PAM_TOKENS_H
+#define _PAM_TOKENS_H
+
+/* an array of actions */
+
+const char * const _pam_token_actions[-_PAM_ACTION_UNDEF] = {
+ "ignore", /* 0 */
+ "ok", /* -1 */
+ "done", /* -2 */
+ "bad", /* -3 */
+ "die", /* -4 */
+ "reset", /* -5 */
+};
+
+/* an array of possible return values */
+
+const char * const _pam_token_returns[_PAM_RETURN_VALUES+1] = {
+ "success", /* 0 */
+ "open_err", /* 1 */
+ "symbol_err", /* 2 */
+ "service_err", /* 3 */
+ "system_err", /* 4 */
+ "buf_err", /* 5 */
+ "perm_denied", /* 6 */
+ "auth_err", /* 7 */
+ "cred_insufficient", /* 8 */
+ "authinfo_unavail", /* 9 */
+ "user_unknown", /* 10 */
+ "maxtries", /* 11 */
+ "new_authtok_reqd", /* 12 */
+ "acct_expired", /* 13 */
+ "session_err", /* 14 */
+ "cred_unavail", /* 15 */
+ "cred_expired", /* 16 */
+ "cred_err", /* 17 */
+ "no_module_data", /* 18 */
+ "conv_err", /* 19 */
+ "authtok_err", /* 20 */
+ "authtok_recover_err", /* 21 */
+ "authtok_lock_busy", /* 22 */
+ "authtok_disable_aging", /* 23 */
+ "try_again", /* 24 */
+ "ignore", /* 25 */
+ "abort", /* 26 */
+ "authtok_expired", /* 27 */
+ "module_unknown", /* 28 */
+ "bad_item", /* 29 */
+/* add new return codes here */
+ "default" /* this is _PAM_RETURN_VALUES and indicates
+ the default return action */
+};
+
+/*
+ * Copyright (C) 1998, Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+#endif /* _PAM_PRIVATE_H_ */
diff --git a/contrib/libpam/libpam_misc/Makefile b/contrib/libpam/libpam_misc/Makefile
new file mode 100644
index 000000000000..1cfc86577b1f
--- /dev/null
+++ b/contrib/libpam/libpam_misc/Makefile
@@ -0,0 +1,109 @@
+# $Header: /home/morgan/pam/Linux-PAM-0.57/libpam_misc/RCS/Makefile,v 1.10 1997/04/05 07:00:18 morgan Exp $
+#
+# $Log: Makefile,v $
+# Revision 1.10 1997/04/05 07:00:18 morgan
+# fakeroot
+#
+# Revision 1.9 1997/02/15 15:46:56 morgan
+# inherit major and minor numbers from top level
+#
+# Revision 1.8 1997/01/04 20:20:11 morgan
+# update for .55 and make -> $(MAKE)
+#
+# Revision 1.7 1996/12/01 03:28:11 morgan
+# update for 0.54
+#
+
+dummy:
+ @echo "*** This is not a top-level Makefile!"
+
+# ///////////////////////////////////////////////////////////////////
+
+# uncomment if you wnat libpam_misc to be made as a dynamic library
+# AGM has had some segfaulting from libdl when I did this. I have not
+# investigated the cause...
+
+MAKE_DYNAMIC=yes
+
+ifeq ($(DEBUG_REL),yes)
+ LIBNAME=pamd_misc
+else
+ LIBNAME=pam_misc
+endif
+LIBMAJOR=$(MAJOR_REL)
+LIBMINOR=$(MINOR_REL)
+
+FILES=misc_conv help_env
+
+#
+# Probably no need to alter anything below here.
+#
+
+# build dynamic library names
+
+LIBDYNAMIC=lib$(LIBNAME).$(DYNTYPE)
+LIBDYNMAJ=$(LIBDYNAMIC).$(LIBMAJOR)
+LIBDYNMIN=$(LIBDYNMAJ).$(LIBMINOR)
+
+# static library name
+
+LIBSTATIC = lib$(LIBNAME).a
+
+# sources and object files
+
+LIBSRC = $(addsuffix .c,$(FILES))
+LIBOBJ = $(addsuffix .o,$(FILES))
+
+# rules
+
+all: $(LIBSTATIC) $(LIBDYNAMIC)
+
+$(LIBDYNAMIC): $(LIBOBJ)
+ifdef MAKE_DYNAMIC
+ ifeq ($(USESONAME),yes)
+ $(LD_L) $(SOSWITCH) $(LIBDYNMAJ) -o $@ $(LIBOBJ)
+ else
+ $(LD_L) -o $@ $(LIBOBJ)
+ endif
+ ifeq ($(NEEDSONAME),yes)
+ rm -f $(LIBDYNMIN)
+ ln -s $(LIBDYNAMIC) $(LIBDYNMAJ)
+ rm -f $(LIBDYNMAJ)
+ ln -s $(LIBDYNAMIC) $(LIBDYNMIN)
+ endif
+endif
+
+$(LIBSTATIC): $(LIBOBJ)
+ $(AR) $@ $(LIBOBJ)
+ $(RANLIB) $@
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 ./pam_misc.h $(FAKEROOT)$(INCLUDED)
+ifdef MAKE_DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBDYNAMIC) $(FAKEROOT)$(LIBDIR)/$(LIBDYNMIN)
+ $(LDCONFIG)
+ ifneq ($(DYNTYPE),"sl")
+ ( cd $(FAKEROOT)$(LIBDIR) ; ln -sf $(LIBDYNMAJ) $(LIBDYNAMIC) )
+ endif
+endif
+ $(INSTALL) -m 644 $(LIBSTATIC) $(FAKEROOT)$(LIBDIR)
+
+clean:
+ rm -f *.so *.a core a.out *~
+
+remove:
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_misc.h
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBDYNAMIC).*
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBDYNAMIC)
+ $(LDCONFIG)
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBSTATIC)
+ rm -f $(FAKEROOT)$(INCLUDED)/chk_malloc.h
+
+.c.o:
+ $(CC) -c $(DEFS) $(CFLAGS) $<
+
+extraclean:
+ @$(MAKE) clean
+ rm -f *.o *.bak
+
diff --git a/contrib/libpam/libpam_misc/help_env.c b/contrib/libpam/libpam_misc/help_env.c
new file mode 100644
index 000000000000..d35b66b948ca
--- /dev/null
+++ b/contrib/libpam/libpam_misc/help_env.c
@@ -0,0 +1,112 @@
+/*
+ * $Id: help_env.c,v 1.2 1997/01/04 20:19:20 morgan Exp morgan $
+ *
+ * This file was written by Andrew G. Morgan <morgan@parc.power.net>
+ *
+ * $Log: help_env.c,v $
+ * Revision 1.2 1997/01/04 20:19:20 morgan
+ * added a prototype (no warning) and fixed paste function
+ *
+ * Revision 1.1 1996/12/01 03:25:37 morgan
+ * Initial revision
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <security/pam_misc.h>
+
+/*
+ * This is a useful function for dumping the Linux-PAM environment
+ * into some local memory, prior to it all getting lost when pam_end()
+ * is called.
+ *
+ * Initially it was assumed that libpam did not do this part correctly
+ * (based on a loose email definition). The X/Open XSSO spec makes it
+ * clear that this function is a duplicate of the one already in
+ * libpam and therefore unnecessary. IT WILL BE COMPLETELY REMOVED
+ * IN libpam_misc 1.0 */
+
+char **pam_misc_copy_env(pam_handle_t *pamh);
+char **pam_misc_copy_env(pam_handle_t *pamh)
+{
+ return pam_getenvlist(pamh);
+}
+
+/*
+ * This function should be used to carefully dispose of the copied
+ * environment.
+ *
+ * usage: env = pam_misc_drop_env(env);
+ */
+
+char **pam_misc_drop_env(char **dump)
+{
+ int i;
+
+ for (i=0; dump[i] != NULL; ++i) {
+ D(("dump[%d]=`%s'", i, dump[i]));
+ _pam_overwrite(dump[i]);
+ _pam_drop(dump[i]);
+ }
+ _pam_drop(dump);
+
+ return NULL;
+}
+
+/*
+ * This function takes the supplied environment and uploads it to be
+ * the PAM one.
+ */
+
+int pam_misc_paste_env(pam_handle_t *pamh, const char * const * user_env)
+{
+ for (; user_env && *user_env; ++user_env) {
+ int retval;
+
+ D(("uploading: %s", *user_env));
+ retval = pam_putenv(pamh, *user_env);
+ if (retval != PAM_SUCCESS) {
+ D(("error setting %s: %s", *user_env, pam_strerror(pamh,retval)));
+ return retval;
+ }
+ }
+ D(("done."));
+ return PAM_SUCCESS;
+}
+
+/*
+ * This is a wrapper to make pam behave in the way that setenv() does.
+ */
+
+int pam_misc_setenv(pam_handle_t *pamh, const char *name
+ , const char *value, int readonly)
+{
+ char *tmp;
+ int retval;
+
+ if (readonly) {
+ const char *etmp;
+
+ /* we check if the variable is there already */
+ etmp = pam_getenv(pamh, name);
+ if (etmp != NULL) {
+ D(("failed to set readonly variable: %s", name));
+ return PAM_PERM_DENIED; /* not allowed to overwrite */
+ }
+ }
+ tmp = malloc(2+strlen(name)+strlen(value));
+ if (tmp != NULL) {
+ sprintf(tmp,"%s=%s",name,value);
+ D(("pam_putt()ing: %s", tmp));
+ retval = pam_putenv(pamh, tmp);
+ _pam_overwrite(tmp); /* purge */
+ _pam_drop(tmp); /* forget */
+ } else {
+ D(("malloc failure"));
+ retval = PAM_BUF_ERR;
+ }
+
+ return retval;
+}
diff --git a/contrib/libpam/libpam_misc/misc_conv.c b/contrib/libpam/libpam_misc/misc_conv.c
new file mode 100644
index 000000000000..53cf51b76ccc
--- /dev/null
+++ b/contrib/libpam/libpam_misc/misc_conv.c
@@ -0,0 +1,371 @@
+/*
+ * $Id: misc_conv.c,v 1.5 1997/01/04 20:16:48 morgan Exp morgan $
+ *
+ * A generic conversation function for text based applications
+ *
+ * Written by Andrew Morgan <morgan@linux.kernel.org>
+ *
+ * $Log: misc_conv.c,v $
+ * Revision 1.5 1997/01/04 20:16:48 morgan
+ * removed getpass. Replaced with POSIX code for same function which
+ * also observes timeouts specified by the parent application
+ *
+ * Revision 1.4 1996/12/01 03:26:51 morgan
+ * *** empty log message ***
+ *
+ * Revision 1.3 1996/11/10 20:10:01 morgan
+ * sgi definition
+ *
+ * Revision 1.2 1996/07/07 23:59:56 morgan
+ * changed the name of the misc include file
+ *
+ * Revision 1.1 1996/05/02 05:17:06 morgan
+ * Initial revision
+ */
+
+#ifdef linux
+#define _GNU_SOURCE
+#include <features.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+#define INPUTSIZE PAM_MAX_MSG_SIZE /* maximum length of input+1 */
+#define CONV_ECHO_ON 1 /* types of echo state */
+#define CONV_ECHO_OFF 0
+
+/*
+ * external timeout definitions - these can be overriden by the
+ * application.
+ */
+
+time_t pam_misc_conv_warn_time = 0; /* time when we warn */
+time_t pam_misc_conv_die_time = 0; /* time when we timeout */
+
+const char *pam_misc_conv_warn_line = "..\a.Time is running out...\n";
+const char *pam_misc_conv_die_line = "..\a.Sorry, your time is up!\n";
+
+int pam_misc_conv_died=0; /* application can probe this for timeout */
+
+static void pam_misc_conv_delete_binary(void **delete_me)
+{
+ if (delete_me && *delete_me) {
+ unsigned char *packet = *(unsigned char **)delete_me;
+ int length;
+
+ length = 4+(packet[0]<<24)+(packet[1]<<16)+(packet[2]<<8)+packet[3];
+ memset(packet, 0, length);
+ free(packet);
+ *delete_me = packet = NULL;
+ }
+}
+
+/* These function pointers are for application specific binary
+ conversations. One or both of the arguments to the first function
+ must be non-NULL. The first function must return PAM_SUCCESS or
+ PAM_CONV_ERR. If input is non-NULL, a response is expected, this
+ response should be malloc()'d and will eventually be free()'d by
+ the calling module. The structure of this malloc()'d response is as
+ follows:
+
+ { int length, char data[length] }
+
+ For convenience, the pointer used by the two function pointer
+ prototypes is 'void *'.
+
+ The ...free() fn pointer is used to discard a binary message that
+ is not of the default form. It should be explicitly overwritten
+ when using some other convention for the structure of a binary
+ prompt (not recommended). */
+
+int (*pam_binary_handler_fn)(const void *send, void **receive) = NULL;
+void (*pam_binary_handler_free)(void **packet_p) = pam_misc_conv_delete_binary;
+
+/* the following code is used to get text input */
+
+volatile static int expired=0;
+
+/* return to the previous signal handling */
+static void reset_alarm(struct sigaction *o_ptr)
+{
+ (void) alarm(0); /* stop alarm clock - if still ticking */
+ (void) sigaction(SIGALRM, o_ptr, NULL);
+}
+
+/* this is where we intercept the alarm signal */
+static void time_is_up(int ignore)
+{
+ expired = 1;
+}
+
+/* set the new alarm to hit the time_is_up() function */
+static int set_alarm(int delay, struct sigaction *o_ptr)
+{
+ struct sigaction new_sig;
+
+ sigemptyset(&new_sig.sa_mask);
+ new_sig.sa_flags = 0;
+ new_sig.sa_handler = time_is_up;
+ if ( sigaction(SIGALRM, &new_sig, o_ptr) ) {
+ return 1; /* setting signal failed */
+ }
+ if ( alarm(delay) ) {
+ (void) sigaction(SIGALRM, o_ptr, NULL);
+ return 1; /* failed to set alarm */
+ }
+ return 0; /* all seems to have worked */
+}
+
+/* return the number of seconds to next alarm. 0 = no delay, -1 = expired */
+static int get_delay(void)
+{
+ time_t now;
+
+ expired = 0; /* reset flag */
+ (void) time(&now);
+
+ /* has the quit time past? */
+ if (pam_misc_conv_die_time && now >= pam_misc_conv_die_time) {
+ fprintf(stderr,"%s",pam_misc_conv_die_line);
+
+ pam_misc_conv_died = 1; /* note we do not reset the die_time */
+ return -1; /* time is up */
+ }
+
+ /* has the warning time past? */
+ if (pam_misc_conv_warn_time && now >= pam_misc_conv_warn_time) {
+ fprintf(stderr, "%s", pam_misc_conv_warn_line);
+ pam_misc_conv_warn_time = 0; /* reset warn_time */
+
+ /* indicate remaining delay - if any */
+
+ return (pam_misc_conv_die_time ? pam_misc_conv_die_time - now:0 );
+ }
+
+ /* indicate possible warning delay */
+
+ if (pam_misc_conv_warn_time)
+ return (pam_misc_conv_warn_time - now);
+ else if (pam_misc_conv_die_time)
+ return (pam_misc_conv_die_time - now);
+ else
+ return 0;
+}
+
+/* read a line of input string, giving prompt when appropriate */
+static char *read_string(int echo, const char *prompt)
+{
+ struct termios term_before, term_tmp;
+ char line[INPUTSIZE];
+ struct sigaction old_sig;
+ int delay, nc, have_term=0;
+
+ D(("called with echo='%s', prompt='%s'.", echo ? "ON":"OFF" , prompt));
+
+ if (isatty(STDIN_FILENO)) { /* terminal state */
+
+ /* is a terminal so record settings and flush it */
+ if ( tcgetattr(STDIN_FILENO, &term_before) != 0 ) {
+ D(("<error: failed to get terminal settings>"));
+ return NULL;
+ }
+ memcpy(&term_tmp, &term_before, sizeof(term_tmp));
+ if (!echo) {
+ term_tmp.c_lflag &= ~(ECHO);
+ }
+ have_term = 1;
+
+ } else if (!echo) {
+ D(("<warning: cannot turn echo off>"));
+ }
+
+ /* set up the signal handling */
+ delay = get_delay();
+
+ /* reading the line */
+ while (delay >= 0) {
+
+ fprintf(stderr, "%s", prompt);
+ /* this may, or may not set echo off -- drop pending input */
+ if (have_term)
+ (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_tmp);
+
+ if ( delay > 0 && set_alarm(delay, &old_sig) ) {
+ D(("<failed to set alarm>"));
+ break;
+ } else {
+ nc = read(STDIN_FILENO, line, INPUTSIZE-1);
+ if (have_term) {
+ (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before);
+ if (!echo || expired) /* do we need a newline? */
+ fprintf(stderr,"\n");
+ }
+ if ( delay > 0 ) {
+ reset_alarm(&old_sig);
+ }
+ if (expired) {
+ delay = get_delay();
+ } else if (nc > 0) { /* we got some user input */
+ char *input;
+
+ if (nc > 0 && line[nc-1] == '\n') { /* <NUL> terminate */
+ line[--nc] = '\0';
+ } else {
+ line[nc] = '\0';
+ }
+ input = x_strdup(line);
+ _pam_overwrite(line);
+
+ return input; /* return malloc()ed string */
+ } else if (nc == 0) { /* Ctrl-D */
+ D(("user did not want to type anything"));
+ fprintf(stderr, "\n");
+ break;
+ }
+ }
+ }
+
+ /* getting here implies that the timer expired */
+ if (have_term)
+ (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before);
+
+ memset(line, 0, INPUTSIZE); /* clean up */
+ return NULL;
+}
+
+/* end of read_string functions */
+
+int misc_conv(int num_msg, const struct pam_message **msgm,
+ struct pam_response **response, void *appdata_ptr)
+{
+ int count=0;
+ struct pam_response *reply;
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ D(("allocating empty response structure array."));
+
+ reply = (struct pam_response *) calloc(num_msg,
+ sizeof(struct pam_response));
+ if (reply == NULL) {
+ D(("no memory for responses"));
+ return PAM_CONV_ERR;
+ }
+
+ D(("entering conversation function."));
+
+ for (count=0; count < num_msg; ++count) {
+ char *string=NULL;
+
+ switch (msgm[count]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ string = read_string(CONV_ECHO_OFF,msgm[count]->msg);
+ if (string == NULL) {
+ goto failed_conversation;
+ }
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ string = read_string(CONV_ECHO_ON,msgm[count]->msg);
+ if (string == NULL) {
+ goto failed_conversation;
+ }
+ break;
+ case PAM_ERROR_MSG:
+ if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) {
+ goto failed_conversation;
+ }
+ break;
+ case PAM_TEXT_INFO:
+ if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) {
+ goto failed_conversation;
+ }
+ break;
+ case PAM_BINARY_PROMPT:
+ {
+ void *pack_out=NULL;
+ const void *pack_in = msgm[count]->msg;
+
+ if (!pam_binary_handler_fn
+ || pam_binary_handler_fn(pack_in, &pack_out) != PAM_SUCCESS
+ || pack_out == NULL) {
+ goto failed_conversation;
+ }
+ string = (char *) pack_out;
+ pack_out = NULL;
+
+ break;
+ }
+ case PAM_BINARY_MSG:
+ {
+ const void *pack_in = msgm[count]->msg;
+ if (!pam_binary_handler_fn
+ || pam_binary_handler_fn(pack_in, NULL) != PAM_SUCCESS) {
+ goto failed_conversation;
+ }
+ break;
+ }
+ default:
+ fprintf(stderr, "erroneous conversation (%d)\n"
+ ,msgm[count]->msg_style);
+ goto failed_conversation;
+ }
+
+ if (string) { /* must add to reply array */
+ /* add string to list of responses */
+
+ reply[count].resp_retcode = 0;
+ reply[count].resp = string;
+ string = NULL;
+ }
+ }
+
+ /* New (0.59+) behavior is to always have a reply - this is
+ compatable with the X/Open (March 1997) spec. */
+ *response = reply;
+ reply = NULL;
+
+ return PAM_SUCCESS;
+
+failed_conversation:
+
+ if (reply) {
+ for (count=0; count<num_msg; ++count) {
+ if (reply[count].resp == NULL) {
+ continue;
+ }
+ switch (msgm[count]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ case PAM_PROMPT_ECHO_OFF:
+ _pam_overwrite(reply[count].resp);
+ free(reply[count].resp);
+ break;
+ case PAM_BINARY_PROMPT:
+ pam_binary_handler_free((void **) &reply[count].resp);
+ break;
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ case PAM_BINARY_MSG:
+ /* should not actually be able to get here... */
+ free(reply[count].resp);
+ }
+ reply[count].resp = NULL;
+ }
+ /* forget reply too */
+ free(reply);
+ reply = NULL;
+ }
+
+ return PAM_CONV_ERR;
+}
+
diff --git a/contrib/libpam/libpam_misc/pam_misc.h b/contrib/libpam/libpam_misc/pam_misc.h
new file mode 100644
index 000000000000..4823973a4f01
--- /dev/null
+++ b/contrib/libpam/libpam_misc/pam_misc.h
@@ -0,0 +1,70 @@
+/* $Id: pam_misc.h,v 1.3 1997/01/04 20:15:52 morgan Exp morgan $ */
+
+/* $Log: pam_misc.h,v $
+ * Revision 1.3 1997/01/04 20:15:52 morgan
+ * added timeout to misc_conv
+ *
+ * Revision 1.2 1996/12/01 03:27:00 morgan
+ * add env prototypes
+ *
+ * Revision 1.1 1996/07/06 19:31:38 morgan
+ * Initial revision
+ *
+ * Revision 1.1 1996/07/06 19:16:30 morgan
+ * Initial revision
+ */
+
+#ifndef __PAMMISC_H
+#define __PAMMISC_H
+
+#include <security/pam_appl.h>
+
+/* include some useful macros */
+
+#include <security/_pam_macros.h>
+
+/* functions defined in pam_misc.* libraries */
+
+extern int misc_conv(int num_msg, const struct pam_message **msgm,
+ struct pam_response **response, void *appdata_ptr);
+
+#include <time.h>
+
+extern time_t pam_misc_conv_warn_time; /* time that we should warn user */
+extern time_t pam_misc_conv_die_time; /* cut-off time for input */
+extern const char *pam_misc_conv_warn_line; /* warning notice */
+extern const char *pam_misc_conv_die_line; /* cut-off remark */
+extern int pam_misc_conv_died; /* 1 = cut-off time reached (0 not) */
+extern int (*pam_binary_handler_fn)(const void *send, void **receive);
+
+/*
+ * Environment helper functions
+ */
+
+/* transcribe given environment (to pam) */
+extern int pam_misc_paste_env(pam_handle_t *pamh
+ , const char * const * user_env);
+
+/* char **pam_misc_copy_env(pam_handle_t *pamh);
+
+ This is no longer defined as a prototype because the X/Open XSSO
+ spec makes it clear that PAM's pam_getenvlist() does exactly
+ what this was needed for.
+
+ A wrapper is still provided in the pam_misc library - so that
+ legacy applications will still work. But _BE_WARNED_ it will
+ disappear by the release of libpam 1.0 . */
+
+/* delete environment as obtained from (pam_getenvlist) */
+extern char **pam_misc_drop_env(char **env);
+
+/* provide something like the POSIX setenv function for the (Linux-)PAM
+ * environment. */
+
+extern int pam_misc_setenv(pam_handle_t *pamh, const char *name
+ , const char *value, int readonly);
+
+#endif
+
+
+
diff --git a/contrib/libpam/libpam_misc/xstrdup.c b/contrib/libpam/libpam_misc/xstrdup.c
new file mode 100644
index 000000000000..e54a87dda7a6
--- /dev/null
+++ b/contrib/libpam/libpam_misc/xstrdup.c
@@ -0,0 +1,38 @@
+/* $Header: /home/morgan/pam/Linux-PAM-0.53/libpam_misc/RCS/xstrdup.c,v 1.4 1996/11/10 20:10:56 morgan Exp $ */
+
+/*
+ * $Log: xstrdup.c,v $
+ * Revision 1.4 1996/11/10 20:10:56 morgan
+ * modification for stack paranoia
+ *
+ */
+
+#include <malloc.h>
+#include <string.h>
+#include <security/pam_misc.h>
+
+/*
+ * Safe duplication of character strings. "Paranoid"; don't leave
+ * evidence of old token around for later stack analysis.
+ */
+
+char *xstrdup(const char *x)
+{
+ register char *new=NULL;
+
+ if (x != NULL) {
+ register int i;
+
+ for (i=0; x[i]; ++i); /* length of string */
+ if ((new = malloc(++i)) == NULL) {
+ i = 0;
+ } else {
+ while (i-- > 0) {
+ new[i] = x[i];
+ }
+ }
+ x = NULL;
+ }
+
+ return new; /* return the duplicate or NULL on error */
+}
diff --git a/contrib/libpam/modules/Makefile b/contrib/libpam/modules/Makefile
new file mode 100644
index 000000000000..0066fb473e0c
--- /dev/null
+++ b/contrib/libpam/modules/Makefile
@@ -0,0 +1,132 @@
+# $Id: Makefile,v 1.21 1997/04/05 06:44:43 morgan Exp morgan $
+#
+# Makefile
+#
+# This makefile controls the build process of shared and static PAM modules.
+#
+# $Log: Makefile,v $
+# Revision 1.21 1997/04/05 06:44:43 morgan
+# pam_env and pam_tally added
+#
+# Revision 1.20 1997/02/15 18:57:11 morgan
+# fixed bash syntax
+#
+# Revision 1.19 1997/01/04 20:21:32 morgan
+# moved responsibility of conditional compilation to modules (more flexible)
+#
+# Revision 1.18 1996/12/01 03:34:40 morgan
+# update for .54
+#
+# Revision 1.17 1996/11/10 20:20:15 morgan
+# cross platform support and new modules
+#
+# Revision 1.16 1996/09/05 06:20:45 morgan
+# added two modules: listfile and shells
+#
+# Revision 1.15 1996/08/09 05:38:28 morgan
+# added new/proposed modules.
+# fixed makefile installation dependencies
+#
+# Revision 1.14 1996/07/08 00:00:33 morgan
+# added wheel and group modules
+#
+
+MODDIRS=\
+ pam_access \
+ pam_afs \
+ pam_afsauth \
+ pam_afspass \
+ pam_afstok \
+ pam_cracklib \
+ pam_deny \
+ pam_desgold \
+ pam_env \
+ pam_filter \
+ pam_ftp \
+ pam_group \
+ pam_kerberos \
+ pam_krb4 \
+ pam_lastlog \
+ pam_listfile \
+ pam_limits \
+ pam_mail \
+ pam_nologin \
+ pam_opie \
+ pam_passwd+ \
+ pam_permit \
+ pam_pwdb \
+ pam_radius \
+ pam_restrict \
+ pam_rhosts \
+ pam_rootok \
+ pam_securetty \
+ pam_shells \
+ pam_sid \
+ pam_skey \
+ pam_skey2 \
+ pam_stress \
+ pam_syslog \
+ pam_tally \
+ pam_time \
+ pam_unix \
+ pam_warn \
+ pam_wheel
+
+
+# ////////////////////////////////////////////////////
+# // You should not modify anything below this line //
+# ////////////////////////////////////////////////////
+
+dummy:
+ @echo "*** This is not a top-level Makefile! ***"
+
+# -----------------------------------------------------------
+
+all:
+ @echo modules for $(OS) are:
+ @ls -d $(MODDIRS) 2>/dev/null ; echo :--------
+ @echo
+ifdef STATIC
+ rm -f ./_static_module_*
+endif
+ @for i in $(MODDIRS) ; do \
+ if [ -d $$i ]; then { \
+ $(MAKE) -C $$i all ; \
+ if [ $$? -ne 0 ]; then exit 1 ; fi ; \
+ } elif [ -f ./.$$i ]; then { \
+ cat ./.$$i ; \
+ } fi ; \
+ done
+
+install:
+ for i in $(MODDIRS) ; do \
+ if [ -d $$i ]; then { \
+ $(MAKE) -C $$i install ; \
+ if [ $$? -ne 0 ]; then exit 1 ; fi ; \
+ } fi ; \
+ done
+
+remove:
+ for i in $(MODDIRS) ; do \
+ if [ -d $$i ]; then { \
+ $(MAKE) -C $$i remove ; \
+ } fi ; \
+ done
+
+lclean:
+ rm -f _static_module_*
+
+clean: lclean
+ for i in $(MODDIRS) ; do \
+ if [ -d $$i ]; then { \
+ $(MAKE) -C $$i clean ; \
+ } fi ; \
+ done
+
+extraclean: lclean
+ for i in $(MODDIRS) ; do \
+ if [ -d $$i ]; then \
+ $(MAKE) -C $$i extraclean ; \
+ fi ; \
+ done
+
diff --git a/contrib/libpam/modules/README b/contrib/libpam/modules/README
new file mode 100644
index 000000000000..864159478c65
--- /dev/null
+++ b/contrib/libpam/modules/README
@@ -0,0 +1,55 @@
+This directory contains the modules.
+
+If you want to reserve a module name please email <pam-list@redhat.com>
+and announce its name. Andrew Morgan, <morgan@parc.power.net>, will
+add it to the Makefile in the next release of Linux-PAM.
+
+As of Linux-PAM-0.40 modules can optionally conform to the static
+modules conventions.
+
+This file was updated for Linux-PAM-0.53.
+
+The conventions are as follows:
+
+There are only 6 functions that a module may declare as "public" they
+fall into 4 managment groups as follows:
+
+ functions Management group
+ ------------------------------------------ ----------------
+ pam_sm_authenticate, pam_sm_setcred, PAM_SM_AUTH
+ pam_sm_acct_mgmt, PAM_SM_ACCOUNT
+ pam_sm_open_session, pam_sm_close_session, PAM_SM_SESSION
+ pam_sm_chauthtok PAM_SM_PASSWORD
+
+If a module contains definitions for any of the above functions, it
+must supply definitions for all of the functions in the corresponding
+management group.
+
+The header file that defines the ANSI prototypes for these functions
+is <security/pam_modules.h> . In the case that the module wishes to
+offer the functions of a given managment group, it must #define
+PAM_SM_XXX, where XXX is one of the above four tokens. These
+definitions must occur *prior* to the
+#include <security/pam_modules.h> line.
+
+The pam_sm_... functions should be defined to be of type 'PAM_EXTERN int'.
+
+In the case that a module is being compiled with PAM_STATIC #define'd
+it should also define a globally accessible structure
+_"NAME"_modstruct containing references to each of the functions
+defined by the module. (this structure is defined in
+<security/pam_modules.h>. "NAME" is the title of the module
+(eg. "pam_deny")
+
+If a module wants to be included in the static libpam.a its Makefile
+should execute "register_static" with appropriate arguments (in this
+directory).
+
+[
+For SIMPLE working examples, see
+
+ ./modules/pam_deny/* and ./modules/pam_rootok/*
+.]
+
+Andrew Morgan
+96/11/10
diff --git a/contrib/libpam/modules/dont_makefile b/contrib/libpam/modules/dont_makefile
new file mode 100644
index 000000000000..f256ce1b3a61
--- /dev/null
+++ b/contrib/libpam/modules/dont_makefile
@@ -0,0 +1,19 @@
+#########################################################################
+# This is a makefile that does nothing. It is designed to be included
+# by module Makefile-s when they are not compatable with the local
+# system
+#########################################################################
+
+all:
+ @echo "This module will not be compiled on this system"
+
+extraclean: clean
+
+install: clean
+
+clean:
+ @echo "Nothing to do"
+
+#########################################################################
+# all over..
+#########################################################################
diff --git a/contrib/libpam/modules/pam_access/Makefile b/contrib/libpam/modules/pam_access/Makefile
new file mode 100644
index 000000000000..a3d684bb7179
--- /dev/null
+++ b/contrib/libpam/modules/pam_access/Makefile
@@ -0,0 +1,111 @@
+# $Id: Makefile,v 1.1 1997/06/23 00:39:42 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.1 1997/06/23 00:39:42 morgan
+# Initial revision
+#
+#
+
+TITLE=pam_access
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/access.conf
+export CONFILE
+
+# Convenient defaults for compiling independently of the full source
+# tree.
+ifndef FULL_LINUX_PAM_SOURCE_TREE
+export DYNAMIC=-DPAM_DYNAMIC
+export CC=gcc
+export CFLAGS=-O2 -Dlinux -DLINUX_PAM \
+ -ansi -D_POSIX_SOURCE -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align -Wtraditional \
+ -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline \
+ -Wshadow -pedantic -fPIC
+export MKDIR=mkdir -p
+export LD_D=gcc -shared -Xlinker -x
+endif
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+DEFS=-DCONFILE=\"$(CONFILE)\"
+
+CFLAGS += $(DEFS)
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SCONFIGED)
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+ rm -f $(FAKEROOT)$(CONFILE)
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+ rm -f ./.ignore_age
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
diff --git a/contrib/libpam/modules/pam_access/README b/contrib/libpam/modules/pam_access/README
new file mode 100644
index 000000000000..df10c269ec04
--- /dev/null
+++ b/contrib/libpam/modules/pam_access/README
@@ -0,0 +1,40 @@
+# Description of its configuration file (/etc/security/access.conf):
+#
+# Login access control table.
+#
+# When someone logs in, the table is scanned for the first entry that
+# matches the (user, host) combination, or, in case of non-networked
+# logins, the first entry that matches the (user, tty) combination. The
+# permissions field of that table entry determines whether the login will
+# be accepted or refused.
+#
+# Format of the login access control table is three fields separated by a
+# ":" character:
+#
+# permission : users : origins
+#
+# The first field should be a "+" (access granted) or "-" (access denied)
+# character.
+#
+# The second field should be a list of one or more login names, group
+# names, or ALL (always matches). A pattern of the form user@host is
+# matched when the login name matches the "user" part, and when the
+# "host" part matches the local machine name.
+#
+# The third field should be a list of one or more tty names (for
+# non-networked logins), host names, domain names (begin with "."), host
+# addresses, internet network numbers (end with "."), ALL (always
+# matches) or LOCAL (matches any string that does not contain a "."
+# character).
+#
+# If you run NIS you can use @netgroupname in host or user patterns; this
+# even works for @usergroup@@hostgroup patterns. Weird.
+#
+# The EXCEPT operator makes it possible to write very compact rules.
+#
+# The group file is searched only when a name does not match that of the
+# logged-in user. Both the user's primary group is matched, as well as
+# groups in which users are explicitly listed.
+#
+# Alexei Nogin <alexei@nogin.dnttm.ru> 1997/06/15
+############################################################################
diff --git a/contrib/libpam/modules/pam_access/access.conf b/contrib/libpam/modules/pam_access/access.conf
new file mode 100644
index 000000000000..abfefa5e75eb
--- /dev/null
+++ b/contrib/libpam/modules/pam_access/access.conf
@@ -0,0 +1,52 @@
+# Login access control table.
+#
+# When someone logs in, the table is scanned for the first entry that
+# matches the (user, host) combination, or, in case of non-networked
+# logins, the first entry that matches the (user, tty) combination. The
+# permissions field of that table entry determines whether the login will
+# be accepted or refused.
+#
+# Format of the login access control table is three fields separated by a
+# ":" character:
+#
+# permission : users : origins
+#
+# The first field should be a "+" (access granted) or "-" (access denied)
+# character.
+#
+# The second field should be a list of one or more login names, group
+# names, or ALL (always matches). A pattern of the form user@host is
+# matched when the login name matches the "user" part, and when the
+# "host" part matches the local machine name.
+#
+# The third field should be a list of one or more tty names (for
+# non-networked logins), host names, domain names (begin with "."), host
+# addresses, internet network numbers (end with "."), ALL (always
+# matches) or LOCAL (matches any string that does not contain a "."
+# character).
+#
+# If you run NIS you can use @netgroupname in host or user patterns; this
+# even works for @usergroup@@hostgroup patterns. Weird.
+#
+# The EXCEPT operator makes it possible to write very compact rules.
+#
+# The group file is searched only when a name does not match that of the
+# logged-in user. Both the user's primary group is matched, as well as
+# groups in which users are explicitly listed.
+#
+##############################################################################
+#
+# Disallow console logins to all but a few accounts.
+#
+#-:ALL EXCEPT wheel shutdown sync:console
+#
+# Disallow non-local logins to privileged accounts (group wheel).
+#
+#-:wheel:ALL EXCEPT LOCAL .win.tue.nl
+#
+# Some accounts are not allowed to login from anywhere:
+#
+#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL
+#
+# All other accounts are allowed to login from anywhere.
+#
diff --git a/contrib/libpam/modules/pam_access/install_conf b/contrib/libpam/modules/pam_access/install_conf
new file mode 100755
index 000000000000..0667b5ecbbc5
--- /dev/null
+++ b/contrib/libpam/modules/pam_access/install_conf
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONFILE=$FAKEROOT"$CONFILE"
+IGNORE_AGE=./.ignore_age
+CONF=./access.conf
+QUIET_INSTALL=../../.quiet_install
+MODULE=pam_access
+
+echo
+
+if [ -f "$QUIET_INSTALL" ]; then
+ if [ ! -f "$CONFILE" ]; then
+ yes="y"
+ else
+ yes="skip"
+ fi
+elif [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "An older $MODULE configuration file already exists ($CONFILE)"
+ echo "Do you wish to copy the $CONF file in this distribution"
+ echo "to $CONFILE ? (y/n) [skip] "
+ read yes
+ else
+ yes="y"
+ fi
+else
+ yes="skip"
+fi
+
+if [ "$yes" = "y" ]; then
+ mkdir -p $FAKEROOT$CONFD
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ echo " Skipping $CONF installation"
+ if [ "$yes" = "n" ]; then
+ touch "$IGNORE_AGE"
+ fi
+fi
+
+echo
+
+exit 0
diff --git a/contrib/libpam/modules/pam_access/pam_access.c b/contrib/libpam/modules/pam_access/pam_access.c
new file mode 100644
index 000000000000..121333928a26
--- /dev/null
+++ b/contrib/libpam/modules/pam_access/pam_access.c
@@ -0,0 +1,424 @@
+/* pam_access module */
+
+/*
+ * Written by Alexei Nogin <alexei@nogin.dnttm.ru> 1997/06/15
+ * (I took login_access from logdaemon-5.6 and converted it to PAM
+ * using parts of pam_time code.)
+ *
+ */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/* man page says above file includes this... */
+extern int gethostname(char *name, size_t len);
+
+#include <stdarg.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/utsname.h>
+
+#ifndef BROKEN_NETWORK_MATCH
+# include <netdb.h>
+# include <sys/socket.h>
+#endif
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_ACCOUNT
+
+#include <security/_pam_macros.h>
+#include <security/pam_modules.h>
+
+/* --- static functions for checking whether the user should be let in --- */
+
+static void _log_err(const char *format, ... )
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_access", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(LOG_ERR, format, args);
+ va_end(args);
+ closelog();
+}
+
+#define PAM_ACCESS_CONFIG CONFILE
+
+int strcasecmp(const char *s1, const char *s2);
+
+/* login_access.c from logdaemon-5.6 with several changes by A.Nogin: */
+
+ /*
+ * This module implements a simple but effective form of login access
+ * control based on login names and on host (or domain) names, internet
+ * addresses (or network numbers), or on terminal line names in case of
+ * non-networked logins. Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 64)
+#undef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+
+static char fs[] = ":"; /* field separator */
+static char sep[] = ", \t"; /* list-element separator */
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES 1
+#define NO 0
+
+ /*
+ * A structure to bundle up all login-related information to keep the
+ * functional interfaces as generic as possible.
+ */
+struct login_info {
+ struct passwd *user;
+ char *from;
+};
+
+typedef int match_func (char *, struct login_info *);
+
+static int list_match (char *, struct login_info *,
+ match_func *);
+static int user_match (char *, struct login_info *);
+static int from_match (char *, struct login_info *);
+static int string_match (char *, char *);
+
+/* login_access - match username/group and host/tty with access control file */
+
+static int login_access(struct passwd *user, char *from)
+{
+ struct login_info item;
+ FILE *fp;
+ char line[BUFSIZ];
+ char *perm; /* becomes permission field */
+ char *users; /* becomes list of login names */
+ char *froms; /* becomes list of terminals or hosts */
+ int match = NO;
+ int end;
+ int lineno = 0; /* for diagnostics */
+
+ /*
+ * Bundle up the arguments to avoid unnecessary clumsiness lateron.
+ */
+ item.user = user;
+ item.from = from;
+
+ /*
+ * Process the table one line at a time and stop at the first match.
+ * Blank lines and lines that begin with a '#' character are ignored.
+ * Non-comment lines are broken at the ':' character. All fields are
+ * mandatory. The first field should be a "+" or "-" character. A
+ * non-existing table means no access control.
+ */
+
+ if ((fp = fopen(PAM_ACCESS_CONFIG, "r"))!=NULL) {
+ while (!match && fgets(line, sizeof(line), fp)) {
+ lineno++;
+ if (line[end = strlen(line) - 1] != '\n') {
+ _log_err("%s: line %d: missing newline or line too long",
+ PAM_ACCESS_CONFIG, lineno);
+ continue;
+ }
+ if (line[0] == '#')
+ continue; /* comment line */
+ while (end > 0 && isspace(line[end - 1]))
+ end--;
+ line[end] = 0; /* strip trailing whitespace */
+ if (line[0] == 0) /* skip blank lines */
+ continue;
+ if (!(perm = strtok(line, fs))
+ || !(users = strtok((char *) 0, fs))
+ || !(froms = strtok((char *) 0, fs))
+ || strtok((char *) 0, fs)) {
+ _log_err("%s: line %d: bad field count", PAM_ACCESS_CONFIG, lineno);
+ continue;
+ }
+ if (perm[0] != '+' && perm[0] != '-') {
+ _log_err("%s: line %d: bad first field", PAM_ACCESS_CONFIG, lineno);
+ continue;
+ }
+ match = (list_match(froms, &item, from_match)
+ && list_match(users, &item, user_match));
+ }
+ (void) fclose(fp);
+ } else if (errno != ENOENT) {
+ _log_err("cannot open %s: %m", PAM_ACCESS_CONFIG);
+ }
+ return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int list_match(char *list, struct login_info *item, match_func *match_fn)
+{
+ char *tok;
+ int match = NO;
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
+ if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ break;
+ if ((match = (*match_fn) (tok, item))) /* YES */
+ break;
+ }
+ /* Process exceptions to matches. */
+
+ if (match != NO) {
+ while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+ /* VOID */ ;
+ if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
+ return (match);
+ }
+ return (NO);
+}
+
+/* myhostname - figure out local machine name */
+
+static char * myhostname(void)
+{
+ static char name[MAXHOSTNAMELEN + 1];
+
+ gethostname(name, MAXHOSTNAMELEN);
+ name[MAXHOSTNAMELEN] = 0;
+ return (name);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int netgroup_match(char *group, char *machine, char *user)
+{
+#ifdef NIS
+ static char *mydomain = 0;
+
+ if (mydomain == 0)
+ yp_get_default_domain(&mydomain);
+ return (innetgr(group, machine, user, mydomain));
+#else
+ _log_err("NIS netgroup support not configured");
+ return (NO);
+#endif
+}
+
+/* user_match - match a username against one token */
+
+static int user_match(char *tok, struct login_info *item)
+{
+ char *string = item->user->pw_name;
+ struct login_info fake_item;
+ struct group *group;
+ int i;
+ char *at;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the username, if the
+ * token is a group that contains the username, or if the token is the
+ * name of the user's primary group.
+ */
+
+ if ((at = strchr(tok + 1, '@')) != 0) { /* split user@host pattern */
+ *at = 0;
+ fake_item.from = myhostname();
+ return (user_match(tok, item) && from_match(at + 1, &fake_item));
+ } else if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, (char *) 0, string));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if ((group = getgrnam(tok))) { /* try group membership */
+ if (item->user->pw_gid == group->gr_gid)
+ return (YES);
+ for (i = 0; group->gr_mem[i]; i++)
+ if (strcasecmp(string, group->gr_mem[i]) == 0)
+ return (YES);
+ }
+ return (NO);
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int from_match(char *tok, struct login_info *item)
+{
+ char *string = item->from;
+ int tok_len;
+ int str_len;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds. Return
+ * YES if the token fully matches the string. If the token is a domain
+ * name, return YES if it matches the last fields of the string. If the
+ * token has the magic value "LOCAL", return YES if the string does not
+ * contain a "." character. If the token is a network number, return YES
+ * if it matches the head of the string.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, string, (char *) 0));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, string + str_len - tok_len) == 0)
+ return (YES);
+ } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr(string, '.') == 0)
+ return (YES);
+#ifdef BROKEN_NETWORK_MATCH
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+ && strncmp(tok, string, tok_len) == 0) {
+ return (YES);
+#else /* BROKEN_NETWORK_MATCH */
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.') {
+ /*
+ The code below does a more correct check if the address specified
+ by "string" starts from "tok".
+ 1998/01/27 Andrey V. Savochkin <saw@msu.ru>
+ */
+ struct hostent *h;
+ char hn[3+1+3+1+3+1+3+1];
+ int r;
+
+ h = gethostbyname(string);
+ if (h == NULL)
+ return (NO);
+ if (h->h_addrtype != AF_INET)
+ return (NO);
+ if (h->h_length != 4)
+ return (NO); /* only IPv4 addresses (SAW) */
+ r = snprintf(hn, sizeof(hn), "%u.%u.%u.%u",
+ (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1],
+ (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
+ if (r < 0 || r >= sizeof(hn))
+ return (NO);
+ if (!strncmp(tok, hn, tok_len))
+ return (YES);
+#endif /* BROKEN_NETWORK_MATCH */
+ }
+ return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int string_match(char *tok, char *string)
+{
+
+ /*
+ * If the token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the string.
+ */
+
+ if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */
+ return (YES);
+ } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+ return (YES);
+ }
+ return (NO);
+}
+
+/* end of login_access.c */
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ while ((toupper(*s1)==toupper(*s2)) && (*s1) && (*s2)) {s1++; s2++;}
+ return(toupper(*s1)-toupper(*s2));
+}
+
+/* --- public account management functions --- */
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ const char *user=NULL;
+ char *from=NULL;
+ struct passwd *user_pw;
+
+ /* set username */
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL
+ || *user == '\0') {
+ _log_err("cannot determine the user's name");
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* remote host name */
+
+ if (pam_get_item(pamh, PAM_RHOST, (const void **)&from)
+ != PAM_SUCCESS) {
+ _log_err("cannot find the remote host name");
+ return PAM_ABORT;
+ }
+
+ if (from==NULL) {
+
+ /* local login, set tty name */
+
+ if (pam_get_item(pamh, PAM_TTY, (const void **)&from) != PAM_SUCCESS
+ || from == NULL) {
+ D(("PAM_TTY not set, probing stdin"));
+ from = ttyname(STDIN_FILENO);
+ if (from == NULL) {
+ _log_err("couldn't get the tty name");
+ return PAM_ABORT;
+ }
+ if (pam_set_item(pamh, PAM_TTY, from) != PAM_SUCCESS) {
+ _log_err("couldn't set tty name");
+ return PAM_ABORT;
+ }
+ }
+ if (strncmp("/dev/",from,5) == 0) { /* strip leading /dev/ */
+ from += 5;
+ }
+
+ }
+ if ((user_pw=getpwnam(user))==NULL) return (PAM_USER_UNKNOWN);
+ if (login_access(user_pw,from)) return (PAM_SUCCESS); else {
+ _log_err("access denied for user `%s' from `%s'",user,from);
+ return (PAM_PERM_DENIED);
+ }
+}
+
+/* end of module definition */
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_access_modstruct = {
+ "pam_access",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff --git a/contrib/libpam/modules/pam_cracklib/Makefile b/contrib/libpam/modules/pam_cracklib/Makefile
new file mode 100644
index 000000000000..668f2f846296
--- /dev/null
+++ b/contrib/libpam/modules/pam_cracklib/Makefile
@@ -0,0 +1,110 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# Created by Cristian Gafton <gafton@redhat.com> 1996/09/10
+#
+
+ifndef FULL_LINUX_PAM_SOURCE_TREE
+#
+# here you should make default variable defines...
+#
+MKDIR=mkdir -p
+LD_D=gcc -shared -Xlinker -x
+INSTALL=install
+SECUREDIR=/usr/lib/security
+#
+HAVE_CRACKLIB=yes
+endif
+
+ifeq ($(HAVE_CRACKLIB),yes)
+
+TITLE=pam_cracklib
+CRACKLIB=-lcrack
+CRACKLIB_DICTPATH=/usr/lib/cracklib_dict
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+ifdef CRACKLIB_DICTPATH
+CFLAGS+=-DCRACKLIB_DICTPATH=\"$(CRACKLIB_DICTPATH)\"
+endif
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC) Makefile
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) $(CRACKLIB)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~ *.so
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+else
+
+include ../dont_makefile
+
+endif
diff --git a/contrib/libpam/modules/pam_cracklib/README b/contrib/libpam/modules/pam_cracklib/README
new file mode 100644
index 000000000000..e4b02731b523
--- /dev/null
+++ b/contrib/libpam/modules/pam_cracklib/README
@@ -0,0 +1,21 @@
+
+pam_cracklib:
+ check the passwd against dictionary words.
+
+RECOGNIZED ARGUMENTS:
+ debug verbose log
+
+ type=XXX alter the message printed as a prompt to the user.
+ the message printed is in the form
+ "New XXX password: ".
+ Default XXX=UNIX
+
+ retry=N Prompt user at most N times before returning with
+ error. Default N=1.
+
+MODULE SERVICES PROVIDED:
+ passwd chauthtok
+
+AUTHOR:
+ Cristian Gafton <gafton@sorosis.ro>
+
diff --git a/contrib/libpam/modules/pam_cracklib/pam_cracklib.c b/contrib/libpam/modules/pam_cracklib/pam_cracklib.c
new file mode 100644
index 000000000000..3400dfb25209
--- /dev/null
+++ b/contrib/libpam/modules/pam_cracklib/pam_cracklib.c
@@ -0,0 +1,687 @@
+/* pam_cracklib module */
+
+/*
+ * 0.85. added six new options to use this with long passwords.
+ * 0.8. tidied output and improved D(()) usage for debugging.
+ * 0.7. added support for more obscure checks for new passwd.
+ * 0.6. root can reset user passwd to any values (it's only warned)
+ * 0.5. supports retries - 'retry=N' argument
+ * 0.4. added argument 'type=XXX' for 'New XXX password' prompt
+ * 0.3. Added argument 'debug'
+ * 0.2. new password is feeded to cracklib for verify after typed once
+ * 0.1. First release
+ */
+
+/*
+ * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
+ * Long password support by Philip W. Dalrymple <pwd@mdtsoft.com> 1997/07/18
+ * See the end of the file for Copyright Information
+ *
+ * Modification for long password systems (>8 chars). The original
+ * module had problems when used in a md5 password system in that it
+ * allowed too short passwords but required that at least half of the
+ * bytes in the new password did not appear in the old one. this
+ * action is still the default and the changes should not break any
+ * current user. This modification adds 6 new options, one to set the
+ * number of bytes in the new password that are not in the old one,
+ * the other five to control the length checking, these are all
+ * documented (or will be before anyone else sees this code) in the PAM
+ * S.A.G. in the section on the cracklib module.
+ */
+
+#include <stdio.h>
+#define __USE_BSD
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+extern char *FascistCheck(char *pw, const char *dictpath);
+
+#ifndef CRACKLIB_DICTPATH
+#define CRACKLIB_DICTPATH "/usr/lib/cracklib_dict"
+#endif
+
+#define PROMPT1 "New %s password: "
+#define PROMPT2 "Retype new %s password: "
+#define MISTYPED_PASS "Sorry, passwords do not match"
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+#ifndef LINUX_PAM
+#include <security/pam_appl.h>
+#endif /* LINUX_PAM */
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-Cracklib", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+#define PAM_DEBUG_ARG 0x0001
+
+/* module data - AGM: please remove these static variables... PAM was
+ * designed to be reentrant based soley on a unique pamh... this
+ * breaks that. */
+
+static int retry_times = 0;
+static int diff_ok = 10;
+static int min_length = 9;
+static int dig_credit = 1;
+static int up_credit = 1;
+static int low_credit = 1;
+static int oth_credit = 1;
+static char prompt_type[BUFSIZ];
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+ char *ep = NULL;
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strncmp(*argv,"type=",5))
+ strcpy(prompt_type, *argv+5);
+ else if (!strncmp(*argv,"retry=",6)) {
+ retry_times = strtol(*argv+6,&ep,10);
+ if (!ep || (retry_times < 1))
+ retry_times = 1;
+ } else if (!strncmp(*argv,"difok=",6)) {
+ diff_ok = strtol(*argv+6,&ep,10);
+ if (!ep || (diff_ok < 0))
+ diff_ok = 10;
+ } else if (!strncmp(*argv,"minlen=",7)) {
+ min_length = strtol(*argv+7,&ep,10);
+ if (!ep || (min_length < 5))
+ min_length = 5;
+ } else if (!strncmp(*argv,"dcredit=",8)) {
+ dig_credit = strtol(*argv+8,&ep,10);
+ if (!ep || (dig_credit < 0))
+ dig_credit = 0;
+ } else if (!strncmp(*argv,"ucredit=",8)) {
+ up_credit = strtol(*argv+8,&ep,10);
+ if (!ep || (up_credit < 0))
+ up_credit = 0;
+ } else if (!strncmp(*argv,"lcredit=",8)) {
+ low_credit = strtol(*argv+8,&ep,10);
+ if (!ep || (low_credit < 0))
+ low_credit = 0;
+ } else if (!strncmp(*argv,"ocredit=",8)) {
+ oth_credit = strtol(*argv+8,&ep,10);
+ if (!ep || (oth_credit < 0))
+ oth_credit = 0;
+ } else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+/* Helper functions */
+
+/* this is a front-end for module-application conversations */
+static int converse(pam_handle_t *pamh, int ctrl, int nargs,
+ struct pam_message **message,
+ struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
+
+ if ( retval == PAM_SUCCESS ) {
+ retval = conv->conv(nargs, (const struct pam_message **)message,
+ response, conv->appdata_ptr);
+ if (retval != PAM_SUCCESS && (ctrl && PAM_DEBUG_ARG)) {
+ _pam_log(LOG_DEBUG, "conversation failure [%s]",
+ pam_strerror(pamh, retval));
+ }
+ } else {
+ _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]",
+ pam_strerror(pamh, retval));
+ }
+
+ return retval; /* propagate error status */
+}
+
+static int make_remark(pam_handle_t *pamh, unsigned int ctrl,
+ int type, const char *text)
+{
+ struct pam_message *pmsg[1], msg[1];
+ struct pam_response *resp;
+ int retval;
+
+ pmsg[0] = &msg[0];
+ msg[0].msg = text;
+ msg[0].msg_style = type;
+ resp = NULL;
+
+ retval = converse(pamh, ctrl, 1, pmsg, &resp);
+ if (retval == PAM_SUCCESS)
+ _pam_drop_reply(resp, 1);
+
+ return retval;
+}
+
+/* use this to free strings. ESPECIALLY password strings */
+static char *_pam_delete(register char *xx)
+{
+ _pam_overwrite(xx);
+ free(xx);
+ return NULL;
+}
+
+/*
+ * can't be a palindrome - like `R A D A R' or `M A D A M'
+ */
+static int palindrome(const char *old, const char *new)
+{
+ int i, j;
+
+ i = strlen (new);
+
+ for (j = 0;j < i;j++)
+ if (new[i - j - 1] != new[j])
+ return 0;
+
+ return 1;
+}
+
+/*
+ * more than half of the characters are different ones.
+ * or at least diff_ok are different
+ * NOTE that the defaults are NOT the same as befor this
+ * change. as long as there are at least 10 different bytes
+ * in a new password it will now pass even if the password
+ * is longer than 20 bytes (MD5)
+ */
+
+static int similiar(const char *old, const char *new)
+{
+ int i, j;
+
+ for (i = j = 0;new[i] && old[i];i++)
+ if (strchr (new, old[i]))
+ j++;
+
+ if (j >= diff_ok || i >= j * 2)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * a nice mix of characters.
+ */
+static int simple(const char *old, const char *new)
+{
+ int digits = 0;
+ int uppers = 0;
+ int lowers = 0;
+ int others = 0;
+ int size;
+ int i;
+
+ for (i = 0;new[i];i++) {
+ if (isdigit (new[i]))
+ digits++;
+ else if (isupper (new[i]))
+ uppers++;
+ else if (islower (new[i]))
+ lowers++;
+ else
+ others++;
+ }
+
+ /*
+ * The scam was this - a password of only one character type
+ * must be 8 letters long. Two types, 7, and so on.
+ * This is now changed, the base size and the credits or defaults
+ * see the docs on the module for info on these parameters, the
+ * defaults cause the effect to be the same as before the change
+ */
+
+ if (digits > dig_credit)
+ digits = dig_credit;
+
+ if (uppers > up_credit)
+ uppers = up_credit;
+
+ if (lowers > low_credit)
+ lowers = low_credit;
+
+ if (others > oth_credit)
+ others = oth_credit;
+
+ size = min_length;
+ size -= digits;
+ size -= uppers;
+ size -= lowers;
+ size -= others;
+
+ if (size <= i)
+ return 0;
+
+ return 1;
+}
+
+static char * str_lower(char *string)
+{
+ char *cp;
+
+ for (cp = string; *cp; cp++)
+ *cp = tolower(*cp);
+ return string;
+}
+
+static const char * password_check(const char *old, const char *new)
+{
+ const char *msg = NULL;
+ char *oldmono, *newmono, *wrapped;
+
+ if (strcmp(new, old) == 0) {
+ msg = "is the same as the old one";
+ return msg;
+ }
+
+ newmono = str_lower(x_strdup(new));
+ oldmono = str_lower(x_strdup(old));
+ wrapped = malloc(strlen(oldmono) * 2 + 1);
+ strcpy (wrapped, oldmono);
+ strcat (wrapped, oldmono);
+
+ if (palindrome(oldmono, newmono))
+ msg = "is a palindrome";
+
+ if (!msg && strcmp(oldmono, newmono) == 0)
+ msg = "case changes only";
+
+ if (!msg && similiar(oldmono, newmono))
+ msg = "is too similiar to the old one";
+
+ if (!msg && simple(old, new))
+ msg = "is too simple";
+
+ if (!msg && strstr(wrapped, newmono))
+ msg = "is rotated";
+
+ memset(newmono, 0, strlen(newmono));
+ memset(oldmono, 0, strlen(oldmono));
+ memset(wrapped, 0, strlen(wrapped));
+ free(newmono);
+ free(oldmono);
+ free(wrapped);
+
+ return msg;
+}
+
+
+static int _pam_unix_approve_pass(pam_handle_t *pamh,
+ unsigned int ctrl,
+ const char *pass_old,
+ const char *pass_new)
+{
+ const char *msg = NULL;
+
+ if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) {
+ if (ctrl && PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "bad authentication token");
+ make_remark(pamh, ctrl, PAM_ERROR_MSG,
+ pass_new == NULL ?
+ "No password supplied":"Password unchanged" );
+ return PAM_AUTHTOK_ERR;
+ }
+
+ /*
+ * if one wanted to hardwire authentication token strength
+ * checking this would be the place
+ */
+ msg = password_check(pass_old,pass_new);
+ if (msg) {
+ char remark[BUFSIZ];
+
+ memset(remark,0,sizeof(remark));
+ sprintf(remark,"BAD PASSWORD: %s",msg);
+ if (ctrl && PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE, "new passwd fails strength check: %s",
+ msg);
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
+ return PAM_AUTHTOK_ERR;
+ };
+ return PAM_SUCCESS;
+
+}
+
+/* The Main Thing (by Cristian Gafton, CEO at this module :-)
+ * (stolen from http://home.netscape.com)
+ */
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+
+ retry_times = 1;
+ memset(prompt_type,0,sizeof(prompt_type));
+ ctrl = _pam_parse(argc, argv);
+
+ D(("called."));
+ if (!prompt_type[0])
+ strcpy(prompt_type,"UNIX");
+
+ if (flags & PAM_PRELIM_CHECK) {
+ /* Check for passwd dictionary */
+ struct stat st;
+ char buf[sizeof(CRACKLIB_DICTPATH)+10];
+
+ D(("prelim check"));
+
+ memset(buf,0,sizeof(buf)); /* zero the buffer */
+ sprintf(buf,"%s.pwd",CRACKLIB_DICTPATH);
+
+ if (!stat(buf,&st) && st.st_size)
+ return PAM_SUCCESS;
+ else {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"dict path '%s'[.pwd] is invalid",
+ CRACKLIB_DICTPATH);
+ return PAM_ABORT;
+ }
+
+ /* Not reached */
+ return PAM_SERVICE_ERR;
+
+ } else if (flags & PAM_UPDATE_AUTHTOK) {
+ int retval;
+ char *token1, *token2, *oldtoken;
+ const char *item;
+ struct pam_message msg[1],*pmsg[1];
+ struct pam_response *resp;
+ const char *cracklib_dictpath = CRACKLIB_DICTPATH;
+ char prompt[BUFSIZ];
+
+ D(("do update"));
+ retval = pam_get_item(pamh, PAM_OLDAUTHTOK,
+ (const void **)&oldtoken);
+ if (retval != PAM_SUCCESS) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_ERR,"Can not get old passwd");
+ oldtoken=NULL;
+ retval = PAM_SUCCESS;
+ }
+
+ do {
+ /*
+ * make sure nothing inappropriate gets returned
+ */
+ token1 = token2 = NULL;
+
+ if (!retry_times) {
+ D(("returning %s because maxtries reached",
+ pam_strerror(pamh, retval)));
+ return retval;
+ }
+
+ /* Planned modus operandi:
+ * Get a passwd.
+ * Verify it against cracklib.
+ * If okay get it a second time.
+ * Check to be the same with the first one.
+ * set PAM_AUTHTOK and return
+ */
+
+ /* Prepare to ask the user for the first time */
+ memset(prompt,0,sizeof(prompt));
+ sprintf(prompt,PROMPT1,prompt_type);
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[0].msg = prompt;
+
+ resp = NULL;
+ retval = converse(pamh, ctrl, 1, pmsg, &resp);
+ if (resp != NULL) {
+ /* interpret the response */
+ if (retval == PAM_SUCCESS) { /* a good conversation */
+ token1 = x_strdup(resp[0].resp);
+ if (token1 == NULL) {
+ _pam_log(LOG_NOTICE,
+ "could not recover authentication token 1");
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+ /*
+ * tidy up the conversation (resp_retcode) is ignored
+ */
+ _pam_drop_reply(resp, 1);
+ } else {
+ retval = (retval == PAM_SUCCESS) ?
+ PAM_AUTHTOK_RECOVER_ERR:retval ;
+ }
+
+ if (retval != PAM_SUCCESS) {
+ if (ctrl && PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"unable to obtain a password");
+ continue;
+ }
+
+ D(("testing password, retval = %s", pam_strerror(pamh, retval)));
+ /* now test this passwd against cracklib */
+ {
+ char *crack_msg;
+ char remark[BUFSIZ];
+
+ bzero(remark,sizeof(remark));
+ D(("against cracklib"));
+ if ((crack_msg = FascistCheck(token1, cracklib_dictpath))) {
+ if (ctrl && PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"bad password: %s",crack_msg);
+ sprintf(remark,"BAD PASSWORD: %s", crack_msg);
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
+ if (getuid() || (flags & PAM_CHANGE_EXPIRED_AUTHTOK))
+ retval = PAM_AUTHTOK_ERR;
+ else
+ retval = PAM_SUCCESS;
+ } else {
+ /* check it for strength too... */
+ D(("for strength"));
+ if (oldtoken) {
+ retval = _pam_unix_approve_pass(pamh,ctrl,
+ oldtoken,token1);
+ if (retval != PAM_SUCCESS)
+ if (getuid() || (flags & PAM_CHANGE_EXPIRED_AUTHTOK))
+ retval = PAM_AUTHTOK_ERR;
+ else
+ retval = PAM_SUCCESS;
+ }
+ }
+ }
+
+ D(("after testing: retval = %s", pam_strerror(pamh, retval)));
+ /* if cracklib/strength check said it is a bad passwd... */
+ if ((retval != PAM_SUCCESS) && (retval != PAM_IGNORE)) {
+ int temp_unused;
+
+ temp_unused = pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ token1 = _pam_delete(token1);
+ continue;
+ }
+
+ /* Now we have a good passwd. Ask for it once again */
+
+ bzero(prompt,sizeof(prompt));
+ sprintf(prompt,PROMPT2,prompt_type);
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[0].msg = prompt;
+
+ resp = NULL;
+ retval = converse(pamh, ctrl, 1, pmsg, &resp);
+ if (resp != NULL) {
+ /* interpret the response */
+ if (retval == PAM_SUCCESS) { /* a good conversation */
+ token2 = x_strdup(resp[0].resp);
+ if (token2 == NULL) {
+ _pam_log(LOG_NOTICE,
+ "could not recover authentication token 2");
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+ /*
+ * tidy up the conversation (resp_retcode) is ignored
+ */
+ _pam_drop_reply(resp, 1);
+ } else {
+ retval = (retval == PAM_SUCCESS) ?
+ PAM_AUTHTOK_RECOVER_ERR:retval ;
+ }
+
+ if (retval != PAM_SUCCESS) {
+ if (ctrl && PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG
+ ,"unable to obtain the password a second time");
+ continue;
+ }
+
+ /* Hopefully now token1 and token2 the same password ... */
+ if (strcmp(token1,token2) != 0) {
+ /* tell the user */
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, MISTYPED_PASS);
+ token1 = _pam_delete(token1);
+ token2 = _pam_delete(token2);
+ pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"Password mistyped");
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ continue;
+ }
+
+ /* Yes, the password was typed correct twice
+ * we store this password as an item
+ */
+
+ retval = pam_set_item(pamh, PAM_AUTHTOK, token1);
+ /* clean it up */
+ token1 = _pam_delete(token1);
+ token2 = _pam_delete(token2);
+ if (
+ (retval != PAM_SUCCESS) ||
+ (
+ (
+ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&item)
+ ) != PAM_SUCCESS
+ )
+ ) {
+ _pam_log(LOG_CRIT, "error manipulating password");
+ continue;
+ }
+ item = NULL; /* break link to password */
+ return PAM_SUCCESS;
+
+ } while (retry_times--);
+
+ } else {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE, "UNKNOWN flags setting %02X",flags);
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Not reached */
+ return PAM_SERVICE_ERR;
+}
+
+
+
+#ifdef PAM_STATIC
+/* static module data */
+struct pam_module _pam_cracklib_modstruct = {
+ "pam_cracklib",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_chauthtok
+};
+#endif
+
+/*
+ * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996.
+ * All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `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 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.
+ *
+ * The following copyright was appended for the long password support
+ * added with the libpam 0.58 release:
+ *
+ * Modificaton Copyright (c) Philip W. Dalrymple III <pwd@mdtsoft.com>
+ * 1997. All rights reserved
+ *
+ * THE MODIFICATION THAT PROVIDES SUPPORT FOR LONG PASSWORD TYPE CHECKING TO
+ * THIS SOFTWARE IS PROVIDED `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 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.
+ */
diff --git a/contrib/libpam/modules/pam_deny/Makefile b/contrib/libpam/modules/pam_deny/Makefile
new file mode 100644
index 000000000000..02506cb38122
--- /dev/null
+++ b/contrib/libpam/modules/pam_deny/Makefile
@@ -0,0 +1,125 @@
+#
+# $Id: Makefile,v 1.7 1997/04/05 06:43:41 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.7 1997/04/05 06:43:41 morgan
+# full-source-tree and fakeroot
+#
+# Revision 1.6 1997/02/15 19:04:27 morgan
+# fixed email
+#
+# Revision 1.5 1996/11/10 20:11:48 morgan
+# crossplatform support
+#
+# Revision 1.4 1996/09/05 06:50:12 morgan
+# ld --> gcc
+#
+# Revision 1.3 1996/05/26 15:48:38 morgan
+# make dynamic and static dirs
+#
+# Revision 1.2 1996/05/26 04:00:16 morgan
+# changes for automated static/dynamic modules
+#
+# Revision 1.1 1996/03/16 17:47:36 morgan
+# Initial revision
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+#
+
+# Convenient defaults for compiling independently of the full source
+# tree.
+ifndef FULL_LINUX_PAM_SOURCE_TREE
+export DYNAMIC=-DPAM_DYNAMIC
+export CC=gcc
+export CFLAGS=-O2 -Dlinux -DLINUX_PAM \
+ -ansi -D_POSIX_SOURCE -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align -Wtraditional \
+ -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline \
+ -Wshadow -pedantic -fPIC
+export MKDIR=mkdir -p
+export LD_D=gcc -shared -Xlinker -x
+endif
+
+#
+
+TITLE=pam_deny
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_deny/README b/contrib/libpam/modules/pam_deny/README
new file mode 100644
index 000000000000..4f7f6de664fe
--- /dev/null
+++ b/contrib/libpam/modules/pam_deny/README
@@ -0,0 +1,4 @@
+# $Id: README,v 1.1 1996/03/16 18:11:12 morgan Exp $
+#
+
+this module always fails, it ignores all options.
diff --git a/contrib/libpam/modules/pam_deny/pam_deny.c b/contrib/libpam/modules/pam_deny/pam_deny.c
new file mode 100644
index 000000000000..76ba24d3fd90
--- /dev/null
+++ b/contrib/libpam/modules/pam_deny/pam_deny.c
@@ -0,0 +1,94 @@
+/* pam_permit module */
+
+/*
+ * $Id: pam_deny.c,v 1.4 1997/02/15 19:05:15 morgan Exp $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ *
+ * $Log: pam_deny.c,v $
+ * Revision 1.4 1997/02/15 19:05:15 morgan
+ * fixed email
+ *
+ * Revision 1.3 1996/06/02 08:06:19 morgan
+ * changes for new static protocol
+ *
+ * Revision 1.2 1996/05/26 04:01:12 morgan
+ * added static support
+ *
+ * Revision 1.1 1996/03/16 17:47:36 morgan
+ * Initial revision
+ *
+ */
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+
+/* --- authentication management functions --- */
+
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_AUTH_ERR;
+}
+
+PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_CRED_UNAVAIL;
+}
+
+/* --- account management functions --- */
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_ACCT_EXPIRED;
+}
+
+/* --- password management --- */
+
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_AUTHTOK_ERR;
+}
+
+/* --- session management --- */
+
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SYSTEM_ERR;
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SYSTEM_ERR;
+}
+
+/* end of module definition */
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_deny_modstruct = {
+ "pam_deny",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok
+};
+#endif
diff --git a/contrib/libpam/modules/pam_env/Makefile b/contrib/libpam/modules/pam_env/Makefile
new file mode 100644
index 000000000000..df363bc9536b
--- /dev/null
+++ b/contrib/libpam/modules/pam_env/Makefile
@@ -0,0 +1,107 @@
+#
+# $Id: Makefile,v 1.1 1997/04/05 06:42:35 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.1 1997/04/05 06:42:35 morgan
+# Initial revision
+#
+# Revision 1.1 1997/01/04 20:32:52 morgan
+# Initial revision
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/12/8
+# Adaptations by Dave Kinclea and Cristian Gafton
+#
+
+TITLE=pam_env
+
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/pam_env.conf
+export CONFILE
+
+#ifeq ($(HAVE_PWDBLIB),yes)
+#CFLAGS += -DWANT_PWDB
+#EXTRALIB = -lpwdb
+#endif
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) $(EXTRALIB)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS) $(EXTRALIB)
+endif
+
+install: all
+ifdef DYNAMIC
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SCONFIGED)
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_env/README b/contrib/libpam/modules/pam_env/README
new file mode 100644
index 000000000000..d6e959cdbee5
--- /dev/null
+++ b/contrib/libpam/modules/pam_env/README
@@ -0,0 +1,72 @@
+# $Date: 1997/04/05 06:42:35 $
+# $Author: morgan $
+# $Id: README,v 1.1 1997/04/05 06:42:35 morgan Exp $
+#
+# This is the configuration file for pam_env, a PAM module to load in
+# a configurable list of environment variables for a
+#
+# The original idea for this came from Andrew G. Morgan ...
+#<quote>
+# Mmm. Perhaps you might like to write a pam_env module that reads a
+# default environment from a file? I can see that as REALLY
+# useful... Note it would be an "auth" module that returns PAM_IGNORE
+# for the auth part and sets the environment returning PAM_SUCCESS in
+# the setcred function...
+#</quote>
+#
+# What I wanted was the REMOTEHOST variable set, purely for selfish
+# reasons, and AGM didn't want it added to the SimpleApps login
+# program (which is where I added the patch). So, my first concern is
+# that variable, from there there are numerous others that might/would
+# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER .....
+#
+# Of course, these are a different kind of variable than REMOTEHOST in
+# that they are things that are likely to be configured by
+# administrators rather than set by logging in, how to treat them both
+# in the same config file?
+#
+# Here is my idea:
+#
+# Each line starts with the variable name, there are then two possible
+# options for each variable DEFAULT and OVERRIDE.
+# DEFAULT allows and administrator to set the value of the
+# variable to some default value, if none is supplied then the empty
+# string is assumed. The OVERRIDE option tells pam_env that it should
+# enter in its value (overriding the default value) if there is one
+# to use. OVERRIDE is not used, "" is assumed and no override will be
+# done.
+#
+# VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]]
+#
+# (Possibly non-existent) environment variables may be used in values
+# using the ${string} syntax and (possibly non-existent) PAM_ITEMs may
+# be used in values using the @{string} syntax. Both the $ and @
+# characters can be backslash escaped to be used as literal values
+# values can be delimited with "", escaped " not supported.
+#
+#
+# First, some special variables
+#
+# Set the REMOTEHOST variable for any hosts that are remote, default
+# to "localhost" rather than not being set at all
+REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST}
+#
+# Set the DISPLAY variable if it seems reasonable
+DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
+#
+#
+# Now some simple variables
+#
+PAGER DEFAULT=less
+MANPAGER DEFAULT=less
+LESS DEFAULT="M q e h15 z23 b80"
+NNTPSERVER DEFAULT=localhost
+PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
+:/usr/bin:/usr/local/bin/X11:/usr/bin/X11
+#
+# silly examples of escaped variables, just to show how they work.
+#
+DOLLAR DEFAULT=\$
+DOLLARDOLLAR DEFAULT= OVERRIDE=\$${DOLLAR}
+DOLLARPLUS DEFAULT=\${REMOTEHOST}${REMOTEHOST}
+ATSIGN DEFAULT="" OVERRIDE=\@
diff --git a/contrib/libpam/modules/pam_env/install_conf b/contrib/libpam/modules/pam_env/install_conf
new file mode 100755
index 000000000000..4c608400229f
--- /dev/null
+++ b/contrib/libpam/modules/pam_env/install_conf
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONFILE=$FAKEROOT"$CONFILE"
+IGNORE_AGE=./.ignore_age
+QUIET_INSTALL=../../.quiet_install
+CONF=./pam_env.conf-example
+MODULE=pam_env
+
+echo
+
+if [ -f "$QUIET_INSTALL" ]; then
+ if [ ! -f "$CONFILE" ]; then
+ yes="y"
+ else
+ yes="skip"
+ fi
+elif [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "An older $MODULE configuration file already exists ($CONFILE)"
+ echo "Do you wish to copy the $CONF file in this distribution"
+ echo "to $CONFILE ? (y/n) [skip] "
+ read yes
+ else
+ yes="y"
+ fi
+else
+ yes="skip"
+fi
+
+if [ "$yes" = "y" ]; then
+ mkdir -p $FAKEROOT$CONFD
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ echo " Skipping $CONF installation"
+ if [ "$yes" = "n" ]; then
+ touch "$IGNORE_AGE"
+ fi
+fi
+
+echo
+
+exit 0
diff --git a/contrib/libpam/modules/pam_env/pam_env.c b/contrib/libpam/modules/pam_env/pam_env.c
new file mode 100644
index 000000000000..bd0879c52283
--- /dev/null
+++ b/contrib/libpam/modules/pam_env/pam_env.c
@@ -0,0 +1,779 @@
+/* pam_mail module */
+
+/*
+ * $Id: pam_env.c,v 1.1 1997/04/05 06:42:35 morgan Exp morgan $
+ *
+ * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31
+ * Inspired by Andrew Morgan <morgan@parc.power.net, who also supplied the
+ * template for this file (via pam_mail)
+ *
+ * $Log: pam_env.c,v $
+ * Revision 1.1 1997/04/05 06:42:35 morgan
+ * Initial revision
+ *
+ * Revision 0.6 1997/02/04 17:58:27 kinch
+ * Debugging code cleaned up, lots added (whereever _log_err called) some removed
+ *
+ * Revision 0.5 1997/02/04 17:20:30 kinch
+ * Changed default config file
+ * Removed bogus message in pam_sm_authenticate()
+ * Added back support in pam_sm_session(), this could conceivably be used
+ * both as an auth_setcred and a session module
+ *
+ * Revision 0.4 1997/02/04 07:34:15 kinch
+ * Fixed dealing with escaped '$' and '@' characters
+ * This is now an pam_sm_setcred module to work closer to the RFC model
+ * though this whole thing seems to have little to do with Authentication
+ *
+ * Revision 0.3 1997/02/04 04:53:15 kinch
+ * Removed bogus space in PAM_ENV_SILENT
+ * Removed line that added a space when allowing for escaped newlines, that
+ * is not what we want at all, if we want a space, we can add one.
+ * Changed a PAM_ABORT to PAM_BUF_ERR for a malloc failure
+ * Changed bogus PAM_RUSER to PAM_RHOST
+ *
+ * Revision 0.2 1997/02/03 23:31:26 kinch
+ * Lots of D(()) debugging code added, probably too much actually.
+ * This now seems to work for all cases I can think of
+ * Lots of little code changes but nothing major and no function
+ * interface changes, largest change has to do with adding the
+ * logic to get &quote hack to make it through all the code. Probably
+ * ought to have done this with a global flag for each of defval and
+ * override - it would have been cleaner.
+ *
+ * Revision 0.1 1997/02/03 01:39:06 kinch
+ * Initial code, it compiles cleanly but has not been tested at all.
+ *
+ */
+
+#ifndef DEFAULT_CONF_FILE
+#define DEFAULT_CONF_FILE "/etc/security/pam_env.conf"
+#endif
+
+#ifdef linux
+#define _GNU_SOURCE
+#include <features.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef WANT_PWDB
+#include <pwdb/pwdb_public.h>
+#endif
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH /* This is primarily a AUTH_SETCRED module */
+#define PAM_SM_SESSION /* But I like to be friendly */
+#define PAM_SM_PASSWORD /* "" */
+#define PAM_SM_ACCOUNT /* "" */
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* This little structure makes it easier to keep variables together */
+
+typedef struct var {
+ char *name;
+ char *value;
+ char *defval;
+ char *override;
+} VAR;
+
+#define BUF_SIZE 1024
+#define MAX_ENV 8192
+
+#define GOOD_LINE 0
+#define BAD_LINE 100 /* This must be > the largest PAM_* error code */
+
+#define DEFINE_VAR 101
+#define UNDEFINE_VAR 102
+#define ILLEGAL_VAR 103
+
+static int _assemble_line(FILE *, char *, int);
+static int _parse_line(char *, VAR *);
+static int _check_var(pam_handle_t *, VAR *); /* This is the real meat */
+static void _clean_var(VAR *);
+static int _expand_arg(pam_handle_t *, char **);
+static const char * _pam_get_item_byname(pam_handle_t *, const char *);
+static int _define_var(pam_handle_t *, VAR *);
+static int _undefine_var(pam_handle_t *, VAR *);
+
+/* This is a flag used to designate an empty string */
+static char quote='Z';
+
+/* some syslogging */
+
+static void _log_err(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-env", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 01
+#define PAM_NEW_CONF_FILE 02
+#define PAM_ENV_SILENT 04
+
+static int _pam_parse(int flags, int argc, const char **argv, char **conffile)
+{
+ int ctrl=0;
+
+
+ /* step through arguments */
+ for (; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strncmp(*argv,"conffile=",9)) {
+ *conffile = x_strdup(9+*argv);
+ if (*conffile != NULL) {
+ D(("new Configuration File: %s", *conffile));
+ ctrl |= PAM_NEW_CONF_FILE;
+ } else {
+ _log_err(LOG_CRIT,
+ "Configuration file specification missing argument - ignored");
+ }
+ } else {
+ _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+static int _parse_config_file(pam_handle_t *pamh, int ctrl, char **conffile)
+{
+ int retval;
+ const char *file;
+ char buffer[BUF_SIZE];
+ FILE *conf;
+ VAR Var, *var=&Var;
+
+ var->name=NULL; var->defval=NULL; var->override=NULL;
+ D(("Called."));
+
+ if (ctrl & PAM_NEW_CONF_FILE) {
+ file = *conffile;
+ } else {
+ file = DEFAULT_CONF_FILE;
+ }
+
+ D(("Config file name is: %s", file));
+
+ /*
+ * Lets try to open the config file, parse it and process
+ * any variables found.
+ */
+
+ if ((conf = fopen(file,"r")) == NULL) {
+ _log_err(LOG_ERR, "Unable to open config file: %s",
+ strerror(errno));
+ return PAM_ABORT;
+ }
+
+ /* _pam_assemble_line will provide a complete line from the config file, with all
+ * comments removed and any escaped newlines fixed up
+ */
+
+ while (( retval = _assemble_line(conf, buffer, BUF_SIZE)) > 0) {
+ D(("Read line: %s", buffer));
+
+ if ((retval = _parse_line(buffer, var)) == GOOD_LINE) {
+ retval = _check_var(pamh, var);
+
+ if (DEFINE_VAR == retval) {
+ retval = _define_var(pamh, var);
+
+ } else if (UNDEFINE_VAR == retval) {
+ retval = _undefine_var(pamh, var);
+ }
+ }
+ if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval
+ && BAD_LINE != retval && PAM_BAD_ITEM != retval) break;
+
+ _clean_var(var);
+
+ } /* while */
+
+ (void) fclose(conf);
+
+ /* tidy up */
+ _clean_var(var); /* We could have got here prematurely, this is safe though */
+ _pam_overwrite(*conffile);
+ _pam_drop(*conffile);
+ file = NULL;
+ D(("Exit."));
+ return (retval<0?PAM_ABORT:PAM_SUCCESS);
+}
+
+/*
+ * This is where we read a line of the PAM config file. The line may be
+ * preceeded by lines of comments and also extended with "\\\n"
+ */
+
+static int _assemble_line(FILE *f, char *buffer, int buf_len)
+{
+ char *p = buffer;
+ char *s, *os;
+ int used = 0;
+
+ /* loop broken with a 'break' when a non-'\\n' ended line is read */
+
+ D(("called."));
+ for (;;) {
+ if (used >= buf_len) {
+ /* Overflow */
+ D(("_assemble_line: overflow"));
+ return -1;
+ }
+ if (fgets(p, buf_len - used, f) == NULL) {
+ if (used) {
+ /* Incomplete read */
+ return -1;
+ } else {
+ /* EOF */
+ return 0;
+ }
+ }
+
+ /* skip leading spaces --- line may be blank */
+
+ s = p + strspn(p, " \n\t");
+ if (*s && (*s != '#')) {
+ os = s;
+
+ /*
+ * we are only interested in characters before the first '#'
+ * character
+ */
+
+ while (*s && *s != '#')
+ ++s;
+ if (*s == '#') {
+ *s = '\0';
+ used += strlen(os);
+ break; /* the line has been read */
+ }
+
+ s = os;
+
+ /*
+ * Check for backslash by scanning back from the end of
+ * the entered line, the '\n' has been included since
+ * normally a line is terminated with this
+ * character. fgets() should only return one though!
+ */
+
+ s += strlen(s);
+ while (s > os && ((*--s == ' ') || (*s == '\t')
+ || (*s == '\n')));
+
+ /* check if it ends with a backslash */
+ if (*s == '\\') {
+ *s = '\0'; /* truncate the line here */
+ used += strlen(os);
+ p = s; /* there is more ... */
+ } else {
+ /* End of the line! */
+ used += strlen(os);
+ break; /* this is the complete line */
+ }
+
+ } else {
+ /* Nothing in this line */
+ /* Don't move p */
+ }
+ }
+
+ return used;
+}
+
+static int _parse_line(char *buffer, VAR *var)
+{
+ /*
+ * parse buffer into var, legal syntax is
+ * VARIABLE [DEFAULT=[[string]] [OVERRIDE=[value]]
+ *
+ * Any other options defined make this a bad line,
+ * error logged and no var set
+ */
+
+ int length, quoteflg=0;
+ char *ptr, **valptr, *tmpptr;
+
+ D(("Called buffer = <%s>", buffer));
+
+ length = strcspn(buffer," \t\n");
+
+ if ((var->name = malloc(length + 1)) == NULL) {
+ _log_err(LOG_ERR, "Couldn't malloc %d bytes", length+1);
+ return PAM_BUF_ERR;
+ }
+
+ /*
+ * The first thing on the line HAS to be the variable name,
+ * it may be the only thing though.
+ */
+ strncpy(var->name, buffer, length);
+ var->name[length] = '\0';
+ D(("var->name = <%s>, length = %d", var->name, length));
+
+ /*
+ * Now we check for arguments, we only support two kinds and ('cause I am lazy)
+ * each one can actually be listed any number of times
+ */
+
+ ptr = buffer+length;
+ while ((length = strspn(ptr, " \t")) > 0) {
+ ptr += length; /* remove leading whitespace */
+ D((ptr));
+ if (strncmp(ptr,"DEFAULT=",8) == 0) {
+ ptr+=8;
+ D(("Default arg found: <%s>", ptr));
+ valptr=&(var->defval);
+ } else if (strncmp(ptr, "OVERRIDE=", 9) == 0) {
+ ptr+=9;
+ D(("Override arg found: <%s>", ptr));
+ valptr=&(var->override);
+ } else {
+ D(("Unrecognized options: <%s> - ignoring line", ptr));
+ _log_err(LOG_ERR, "Unrecognized Option: %s - ignoring line", ptr);
+ return BAD_LINE;
+ }
+
+ if ('"' != *ptr) { /* Escaped quotes not supported */
+ length = strcspn(ptr, " \t\n");
+ tmpptr = ptr+length;
+ } else {
+ tmpptr = strchr(++ptr, '"');
+ if (!tmpptr) {
+ D(("Unterminated quoted string: %s", ptr-1));
+ _log_err(LOG_ERR, "Unterminated quoted string: %s", ptr-1);
+ return BAD_LINE;
+ }
+ length = tmpptr - ptr;
+ if (*++tmpptr && ' ' != *tmpptr && '\t' != *tmpptr && '\n' != *tmpptr) {
+ D(("Quotes must cover the entire string: <%s>", ptr));
+ _log_err(LOG_ERR, "Quotes must cover the entire string: <%s>", ptr);
+ return BAD_LINE;
+ }
+ quoteflg++;
+ }
+ if (length) {
+ if ((*valptr = malloc(length + 1)) == NULL) {
+ D(("Couldn't malloc %d bytes", length+1));
+ _log_err(LOG_ERR, "Couldn't malloc %d bytes", length+1);
+ return PAM_BUF_ERR;
+ }
+ (void)strncpy(*valptr,ptr,length);
+ (*valptr)[length]='\0';
+ } else if (quoteflg--) {
+ *valptr = &quote; /* a quick hack to handle the empty string */
+ }
+ ptr = tmpptr; /* Start the search where we stopped */
+ } /* while */
+
+ /*
+ * The line is parsed, all is well.
+ */
+
+ D(("Exit."));
+ ptr = NULL; tmpptr = NULL; valptr = NULL;
+ return GOOD_LINE;
+}
+
+static int _check_var(pam_handle_t *pamh, VAR *var)
+{
+ /*
+ * Examine the variable and determine what action to take.
+ * Returns DEFINE_VAR, UNDEFINE_VAR depending on action to take
+ * or a PAM_* error code if passed back from other routines
+ *
+ * if no DEFAULT provided, the empty string is assumed
+ * if no OVERRIDE provided, the empty string is assumed
+ * if DEFAULT= and OVERRIDE evaluates to the empty string,
+ * this variable should be undefined
+ * if DEFAULT="" and OVERRIDE evaluates to the empty string,
+ * this variable should be defined with no value
+ * if OVERRIDE=value and value turns into the empty string, DEFAULT is used
+ *
+ * If DEFINE_VAR is to be returned, the correct value to define will
+ * be pointed to by var->value
+ */
+
+ int retval;
+
+ D(("Called."));
+
+ /*
+ * First thing to do is to expand any arguments, but only
+ * if they are not the special quote values (cause expand_arg
+ * changes memory).
+ */
+
+ if (var->defval && (&quote != var->defval) &&
+ ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) {
+ return retval;
+ }
+ if (var->override && (&quote != var->override) &&
+ ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) {
+ return retval;
+ }
+
+ /* Now its easy */
+
+ if (var->override && *(var->override) && &quote != var->override) {
+ /* if there is a non-empty string in var->override, we use it */
+ D(("OVERRIDE variable <%s> being used: <%s>", var->name, var->override));
+ var->value = var->override;
+ retval = DEFINE_VAR;
+ } else {
+
+ var->value = var->defval;
+ if (&quote == var->defval) {
+ /*
+ * This means that the empty string was given for defval value
+ * which indicates that a variable should be defined with no value
+ */
+ *var->defval = '\0';
+ D(("An empty variable: <%s>", var->name));
+ retval = DEFINE_VAR;
+ } else if (var->defval) {
+ D(("DEFAULT variable <%s> being used: <%s>", var->name, var->defval));
+ retval = DEFINE_VAR;
+ } else {
+ D(("UNDEFINE variable <%s>", var->name));
+ retval = UNDEFINE_VAR;
+ }
+ }
+
+ D(("Exit."));
+ return retval;
+}
+
+static int _expand_arg(pam_handle_t *pamh, char **value)
+{
+ const char *orig=*value, *tmpptr=NULL;
+ char *ptr; /*
+ * Sure would be nice to use tmpptr but it needs to be
+ * a constant so that the compiler will shut up when I
+ * call pam_getenv and _pam_get_item_byname -- sigh
+ */
+
+ char type, tmpval[BUF_SIZE]; /* No unexpanded variable can be bigger than BUF_SIZE */
+ char tmp[MAX_ENV]; /* I know this shouldn't be hard-coded but it's so
+ * much easier this way */
+
+ D(("Remember to initialize tmp!"));
+ tmp[0] = '\0';
+
+ /*
+ * (possibly non-existent) environment variables can be used as values
+ * by prepending a "$" and wrapping in {} (ie: ${HOST}), can escape with "\"
+ * (possibly non-existent) PAM items can be used as values
+ * by prepending a "@" and wrapping in {} (ie: @{PAM_RHOST}, can escape
+ *
+ */
+ D(("Expanding <%s>",orig));
+ while (*orig) { /* while there is some input to deal with */
+ if ('\\' == *orig) {
+ ++orig;
+ if ('$' != *orig && '@' != *orig) {
+ D(("Unrecognized escaped character: <%c> - ignoring", *orig));
+ _log_err(LOG_ERR, "Unrecognized escaped character: <%c> - ignoring",
+ *orig);
+ } else if ((strlen(tmp) + 1) < MAX_ENV) {
+ tmp[strlen(tmp)] = *orig++; /* Note the increment */
+ } else {
+ /* is it really a good idea to try to log this? */
+ D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr));
+ _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr);
+ }
+ continue;
+ }
+ if ('$' == *orig || '@' == *orig) {
+ if ('{' != *(orig+1)) {
+ D(("Expandable variables must be wrapped in {} <%s> - ignoring", orig));
+ _log_err(LOG_ERR, "Expandable variables must be wrapped in {} <%s> - ignoring",
+ orig);
+ if ((strlen(tmp) + 1) < MAX_ENV) {
+ tmp[strlen(tmp)] = *orig++; /* Note the increment */
+ }
+ continue;
+ } else {
+ D(("Expandable argument: <%s>", orig));
+ type = *orig;
+ orig+=2; /* skip the ${ or @{ characters */
+ ptr = strchr(orig, '}');
+ if (ptr) {
+ *ptr++ = '\0';
+ } else {
+ D(("Unterminated expandable variable: <%s>", orig-2));
+ _log_err(LOG_ERR, "Unterminated expandable variable: <%s>", orig-2);
+ return PAM_ABORT;
+ }
+ strcpy(tmpval, orig);
+ orig=ptr;
+ /*
+ * so, we know we need to expand tmpval, it is either
+ * an environment variable or a PAM_ITEM. type will tell us which
+ */
+ switch (type) {
+
+ case '$':
+ D(("Expanding env var: <%s>",tmpval));
+ tmpptr = pam_getenv(pamh, tmpval);
+ D(("Expanded to <%s>", tmpptr));
+ break;
+
+ case '@':
+ D(("Expanding pam item: <%s>",tmpval));
+ tmpptr = _pam_get_item_byname(pamh, tmpval);
+ D(("Expanded to <%s>", tmpptr));
+ break;
+
+ default:
+ D(("Impossible error, type == <%c>", type));
+ _log_err(LOG_CRIT, "Impossible error, type == <%c>", type);
+ return PAM_ABORT;
+ } /* switch */
+
+ if (tmpptr) {
+ if ((strlen(tmp) + strlen(tmpptr)) < MAX_ENV) {
+ strcat(tmp, tmpptr);
+ } else {
+ /* is it really a good idea to try to log this? */
+ D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr));
+ _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr);
+ }
+ }
+ } /* if ('{' != *orig++) */
+ } else { /* if ( '$' == *orig || '@' == *orig) */
+ if ((strlen(tmp) + 1) < MAX_ENV) {
+ tmp[strlen(tmp)] = *orig++; /* Note the increment */
+ } else {
+ /* is it really a good idea to try to log this? */
+ D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr));
+ _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr);
+ }
+ }
+ } /* for (;*orig;) */
+
+ if (strlen(tmp) > strlen(*value)) {
+ free(*value);
+ if ((*value = malloc(strlen(tmp) +1)) == NULL) {
+ D(("Couldn't malloc %d bytes for expanded var", strlen(tmp)+1));
+ _log_err(LOG_ERR,"Couldn't malloc %d bytes for expanded var",
+ strlen(tmp)+1);
+ return PAM_BUF_ERR;
+ }
+ }
+ strcpy(*value, tmp);
+ memset(tmp,'\0',sizeof(tmp));
+ D(("Exit."));
+
+ return PAM_SUCCESS;
+}
+
+static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name)
+{
+ /*
+ * This function just allows me to use names as given in the config
+ * file and translate them into the appropriate PAM_ITEM macro
+ */
+
+ int item;
+ const char *itemval;
+
+ D(("Called."));
+ if (strcmp(name, "PAM_USER") == 0) {
+ item = PAM_USER;
+ } else if (strcmp(name, "PAM_USER_PROMPT") == 0) {
+ item = PAM_USER_PROMPT;
+ } else if (strcmp(name, "PAM_TTY") == 0) {
+ item = PAM_TTY;
+ } else if (strcmp(name, "PAM_RUSER") == 0) {
+ item = PAM_RUSER;
+ } else if (strcmp(name, "PAM_RHOST") == 0) {
+ item = PAM_RHOST;
+ } else {
+ D(("Unknown PAM_ITEM: <%s>", name));
+ _log_err(LOG_ERR, "Unknown PAM_ITEM: <%s>", name);
+ return NULL;
+ }
+
+ if (pam_get_item(pamh, item, (const void **)&itemval) != PAM_SUCCESS) {
+ D(("pam_get_item failed"));
+ return NULL; /* let pam_get_item() log the error */
+ }
+ D(("Exit."));
+ return itemval;
+}
+
+static int _define_var(pam_handle_t *pamh, VAR *var)
+{
+ /* We have a variable to define, this is a simple function */
+
+ char *envvar;
+ int size, retval=PAM_SUCCESS;
+
+ D(("Called."));
+ size = strlen(var->name)+strlen(var->value)+2;
+ if ((envvar = malloc(size)) == NULL) {
+ D(("Malloc fail, size = %d", size));
+ _log_err(LOG_ERR, "Malloc fail, size = %d", size);
+ return PAM_BUF_ERR;
+ }
+ (void) sprintf(envvar,"%s=%s",var->name,var->value);
+ retval = pam_putenv(pamh, envvar);
+ free(envvar); envvar=NULL;
+ D(("Exit."));
+ return retval;
+}
+
+static int _undefine_var(pam_handle_t *pamh, VAR *var)
+{
+ /* We have a variable to undefine, this is a simple function */
+
+ D(("Called and exit."));
+ return pam_putenv(pamh, var->name);
+}
+
+static void _clean_var(VAR *var)
+{
+ if (var->name) {
+ free(var->name);
+ }
+ if (var->defval && (&quote != var->defval)) {
+ free(var->defval);
+ }
+ if (var->override && (&quote != var->override)) {
+ free(var->override);
+ }
+ var->name = NULL;
+ var->value = NULL; /* never has memory specific to it */
+ var->defval = NULL;
+ var->override = NULL;
+ return;
+}
+
+
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return PAM_IGNORE;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ int retval, ctrl;
+ char *conf_file=NULL;
+
+ /*
+ * this module sets environment variables read in from a file
+ */
+
+ D(("Called."));
+ ctrl = _pam_parse(flags, argc, argv, &conf_file);
+
+ retval = _parse_config_file(pamh, ctrl, &conf_file);
+
+ /* indicate success or failure */
+
+ D(("Exit."));
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ _log_err(LOG_NOTICE, "pam_sm_acct_mgmt called inappropriatly");
+ return PAM_SERVICE_ERR;
+}
+
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int retval, ctrl;
+ char *conf_file=NULL;
+
+ /*
+ * this module sets environment variables read in from a file
+ */
+
+ D(("Called."));
+ ctrl = _pam_parse(flags, argc, argv, &conf_file);
+
+ retval = _parse_config_file(pamh, ctrl, &conf_file);
+
+ /* indicate success or failure */
+
+ D(("Exit."));
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc,
+ const char **argv)
+{
+ D(("Called and Exit"));
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ _log_err(LOG_NOTICE, "pam_sm_chauthtok called inappropriatly");
+ return PAM_SERVICE_ERR;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_env_modstruct = {
+ "pam_env",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_env/pam_env.conf-example b/contrib/libpam/modules/pam_env/pam_env.conf-example
new file mode 100644
index 000000000000..388e8b6b16d4
--- /dev/null
+++ b/contrib/libpam/modules/pam_env/pam_env.conf-example
@@ -0,0 +1,72 @@
+# $Date: 1997/04/05 06:42:35 $
+# $Author: morgan $
+# $Id: pam_env.conf-example,v 1.1 1997/04/05 06:42:35 morgan Exp $
+#
+# This is the configuration file for pam_env, a PAM module to load in
+# a configurable list of environment variables for a
+#
+# The original idea for this came from Andrew G. Morgan ...
+#<quote>
+# Mmm. Perhaps you might like to write a pam_env module that reads a
+# default environment from a file? I can see that as REALLY
+# useful... Note it would be an "auth" module that returns PAM_IGNORE
+# for the auth part and sets the environment returning PAM_SUCCESS in
+# the setcred function...
+#</quote>
+#
+# What I wanted was the REMOTEHOST variable set, purely for selfish
+# reasons, and AGM didn't want it added to the SimpleApps login
+# program (which is where I added the patch). So, my first concern is
+# that variable, from there there are numerous others that might/would
+# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER .....
+#
+# Of course, these are a different kind of variable than REMOTEHOST in
+# that they are things that are likely to be configured by
+# administrators rather than set by logging in, how to treat them both
+# in the same config file?
+#
+# Here is my idea:
+#
+# Each line starts with the variable name, there are then two possible
+# options for each variable DEFAULT and OVERRIDE.
+# DEFAULT allows and administrator to set the value of the
+# variable to some default value, if none is supplied then the empty
+# string is assumed. The OVERRIDE option tells pam_env that it should
+# enter in its value (overriding the default value) if there is one
+# to use. OVERRIDE is not used, "" is assumed and no override will be
+# done.
+#
+# VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]]
+#
+# (Possibly non-existent) environment variables may be used in values
+# using the ${string} syntax and (possibly non-existent) PAM_ITEMs may
+# be used in values using the @{string} syntax. Both the $ and @
+# characters can be backslash escaped to be used as literal values
+# values can be delimited with "", escaped " not supported.
+#
+#
+# First, some special variables
+#
+# Set the REMOTEHOST variable for any hosts that are remote, default
+# to "localhost" rather than not being set at all
+#REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST}
+#
+# Set the DISPLAY variable if it seems reasonable
+#DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
+#
+#
+# Now some simple variables
+#
+#PAGER DEFAULT=less
+#MANPAGER DEFAULT=less
+#LESS DEFAULT="M q e h15 z23 b80"
+#NNTPSERVER DEFAULT=localhost
+#PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
+#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11
+#
+# silly examples of escaped variables, just to show how they work.
+#
+#DOLLAR DEFAULT=\$
+#DOLLARDOLLAR DEFAULT= OVERRIDE=\$${DOLLAR}
+#DOLLARPLUS DEFAULT=\${REMOTEHOST}${REMOTEHOST}
+#ATSIGN DEFAULT="" OVERRIDE=\@
diff --git a/contrib/libpam/modules/pam_filter/Makefile b/contrib/libpam/modules/pam_filter/Makefile
new file mode 100644
index 000000000000..dbd6452ab285
--- /dev/null
+++ b/contrib/libpam/modules/pam_filter/Makefile
@@ -0,0 +1,150 @@
+#
+# $Id: Makefile,v 1.10 1997/04/05 06:41:09 morgan Exp $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.10 1997/04/05 06:41:09 morgan
+# fakeroot
+#
+# Revision 1.9 1997/02/15 18:58:48 morgan
+# fixed bash syntax
+#
+# Revision 1.8 1997/01/04 20:24:29 morgan
+# don't compile on solaris, make -> $(MAKE)
+#
+# Revision 1.7 1996/11/10 20:12:09 morgan
+# cross platform support
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+#
+
+ifeq ($(OS),solaris)
+
+include ../dont_makefile
+
+else
+
+TITLE=pam_filter
+FILTERS=upperLOWER
+FILTERSDIR=$(SUPLEMENTED)/pam_filter
+export FILTERSDIR
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+#
+# this is where we compile this module
+#
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register filters
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+filters:
+ @for i in $(FILTERS) ; do \
+ if [ -d $$i ]; then \
+ $(MAKE) -C $$i all ; \
+ fi ; \
+ done
+
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+endif
+
+ifdef DYNAMIC
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+endif
+
+ifdef STATIC
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ @for i in $(FILTERS) ; do \
+ if [ -d $$i ]; then \
+ $(MAKE) -C $$i install ; \
+ fi ; \
+ done
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/pam_filter.h $(FAKEROOT)$(INCLUDED)
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_filter.h
+ @for i in $(FILTERS) ; do \
+ if [ -d $$i ]; then \
+ $(MAKE) -C $$i remove ; \
+ fi ; \
+ done
+
+lclean:
+ rm -f $(LIBSHARED) $(LIBOBJD) $(LIBOBJS) core *~
+
+clean: lclean
+ @for i in $(FILTERS) ; do \
+ if [ -d $$i ]; then \
+ $(MAKE) -C $$i clean ; \
+ fi ; \
+ done
+
+extraclean: lclean
+ @rm -f *.a *.o *.so *.bak
+ for i in $(FILTERS) ; do \
+ if [ -d $$i ]; then \
+ $(MAKE) -C $$i extraclean ; \
+ fi ; \
+ done
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+endif
diff --git a/contrib/libpam/modules/pam_filter/README b/contrib/libpam/modules/pam_filter/README
new file mode 100644
index 000000000000..9d46a56e5c9c
--- /dev/null
+++ b/contrib/libpam/modules/pam_filter/README
@@ -0,0 +1,94 @@
+#
+# $Id: README,v 1.5 1996/12/01 02:53:08 morgan Exp $
+#
+# This describes the behavior of this module with respect to the
+# /etc/pam.conf file.
+#
+# writen by Andrew Morgan <morgan@parc.power.net>
+#
+
+This module is intended to be a platform for providing access to all
+of the input/output that passes between the user and the application.
+It is only suitable for tty-based and (stdin/stdout) applications. And
+is only known to work on Linux based systems.
+
+The action of the module is dictated by the arguments it is given in
+the pam.conf file.
+
+recognized flags are:
+
+ debug print some information to syslog(3)
+
+ new_term set the PAM_TTY item to the new filtered
+ terminal (the default is to set it
+ to be that of the users terminal)
+
+ non_term don't try to set the PAM_TTY item
+
+ run1/run2 these arguments indicate that the
+ module should separate the application
+ from the user and insert a filter
+ program between them. The pathname of
+ the filter program follows the 'runN'
+ argument. Arguments that follow this
+ pathname are passed as arguments to
+ the filter program.
+
+ The distinction between run1 and run2
+ is which of the two functions of
+ the given management-type triggers the
+ execution of the indicated filter.
+
+ type: run1 run2
+ ----- ---- ----
+
+ auth pam_sm_authenticate pam_sm_setcred
+
+ account [ pam_sm_acct_mgmt (either is good) ]
+
+ session pam_sm_open_session pam_sm_close_session
+
+ password pam_sm_chauthtok/PRELIM pam_sm_chauthtok/UPDATE
+
+Note, in the case of 'password' PRELIM/UPDATE indicates which of the
+two calls to pam_sm_chauthtok from libpam (not the application) will
+trigger the filter.
+
+What a filter program should expect:
+------------------------------------
+
+Definitions for filter programs (which may be locally designed) are
+contained in the <security/pam_filter.h> file.
+
+Arguments are not passed to the filter on the command line, since this
+is plainly visible when a user types 'ps -a'. Instead they are passed
+as the filter's environment. Other information is passed in this way
+too.
+
+Here is a list of the environment variables that a filter should
+expect:
+
+ ARGS="filter_path_name argument list"
+ SERVICE="service_name" (as it appears in /etc/pam.conf)
+ USER="username"
+ TYPE="module_fn" (the name of the function in pam_filter.so
+ that invoked the filter)
+
+[This list is likely to grow. If you want something added, email me!]
+
+Among other things this module is intended to provide a useful means
+of logging the activity of users in as discrete a manner as possible.
+
+Existing filters:
+-----------------
+
+Currently, there is a single supplied filter (upperLOWER). The effect
+of using this filter is to transpose upper and lower case letters
+between the user and the application. This is really annoying when you
+try the 'xsh' example application! ;)
+
+TODO: provide more filters...
+ Decide if providing stderr interception is really overkill.
+
+Andrew G. Morgan <morgan@parc.power.net> 1996/5/27
+
diff --git a/contrib/libpam/modules/pam_filter/include/pam_filter.h b/contrib/libpam/modules/pam_filter/include/pam_filter.h
new file mode 100644
index 000000000000..3eb2730e768b
--- /dev/null
+++ b/contrib/libpam/modules/pam_filter/include/pam_filter.h
@@ -0,0 +1,32 @@
+/*
+ * $Id: pam_filter.h,v 1.2 1997/02/15 19:09:09 morgan Exp $
+ *
+ * this file is associated with the Linux-PAM filter module.
+ * it was written by Andrew G. Morgan <morgan@parc.power.net>
+ *
+ */
+
+#ifndef PAM_FILTER_H
+#define PAM_FILTER_H
+
+#include <sys/file.h>
+
+/*
+ * this will fail if there is some problem with these file descriptors
+ * being allocated by the pam_filter Linux-PAM module. The numbers
+ * here are thought safe, but the filter developer should use the
+ * macros, as these numbers are subject to change.
+ *
+ * The APPXXX_FILENO file descriptors are the STDIN/OUT/ERR_FILENO of the
+ * application. The filter uses the STDIN/OUT/ERR_FILENO's to converse
+ * with the user, passes (modified) user input to the application via
+ * APPIN_FILENO, and receives application output from APPOUT_FILENO/ERR.
+ */
+
+#define APPIN_FILENO 3 /* write here to give application input */
+#define APPOUT_FILENO 4 /* read here to get application output */
+#define APPERR_FILENO 5 /* read here to get application errors */
+
+#define APPTOP_FILE 6 /* used by select */
+
+#endif
diff --git a/contrib/libpam/modules/pam_filter/pam_filter.c b/contrib/libpam/modules/pam_filter/pam_filter.c
new file mode 100644
index 000000000000..fc3d1f2b53fc
--- /dev/null
+++ b/contrib/libpam/modules/pam_filter/pam_filter.c
@@ -0,0 +1,747 @@
+/*
+ * $Id: pam_filter.c,v 1.9 1997/02/15 19:07:49 morgan Exp morgan $
+ *
+ * $Log: pam_filter.c,v $
+ * Revision 1.9 1997/02/15 19:07:49 morgan
+ * fixed email
+ *
+ * Revision 1.8 1996/11/10 20:59:23 morgan
+ * gcc warning removed
+ *
+ * Revision 1.7 1996/07/08 00:01:17 morgan
+ * set the PAM_TTY item now
+ *
+ * Revision 1.6 1996/06/02 08:08:19 morgan
+ * completely re-written
+ *
+ *
+ * written by Andrew Morgan <morgan@transmeta.com> with much help from
+ * Richard Stevens' UNIX Network Programming book.
+ */
+
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <termio.h>
+
+#include <signal.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+#include <security/pam_filter.h>
+
+/* ------ some tokens used for convenience throughout this file ------- */
+
+#define FILTER_DEBUG 01
+#define FILTER_RUN1 02
+#define FILTER_RUN2 04
+#define NEW_TERM 010
+#define NON_TERM 020
+
+/* -------------------------------------------------------------------- */
+
+/* log errors */
+
+#include <stdarg.h>
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_filter", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+#define TERMINAL_LEN 12
+
+static int master(char *terminal)
+/*
+ * try to open all of the terminals in sequence return first free one,
+ * or -1
+ */
+{
+ const char ptys[] = "pqrs", *pty = ptys;
+ const char hexs[] = "0123456789abcdef", *hex;
+ struct stat tstat;
+ int fd;
+
+ strcpy(terminal, "/dev/pty??");
+
+ while (*pty) { /* step through four types */
+ terminal[8] = *pty++;
+ terminal[9] = '0';
+ if (stat(terminal,&tstat) < 0) {
+ _pam_log(LOG_WARNING, "unknown pseudo terminal; %s", terminal);
+ break;
+ }
+ for (hex = hexs; *hex; ) { /* step through 16 of these */
+ terminal[9] = *hex++;
+ if ((fd = open(terminal, O_RDWR)) >= 0) {
+ return fd;
+ }
+ }
+ }
+
+ /* no terminal found */
+
+ return -1;
+}
+
+static int process_args(pam_handle_t *pamh
+ , int argc, const char **argv, const char *type
+ , char ***evp, const char **filtername)
+{
+ int ctrl=0;
+
+ while (argc-- > 0) {
+ if (strcmp("debug",*argv) == 0) {
+ ctrl |= FILTER_DEBUG;
+ } else if (strcmp("new_term",*argv) == 0) {
+ ctrl |= NEW_TERM;
+ } else if (strcmp("non_term",*argv) == 0) {
+ ctrl |= NON_TERM;
+ } else if (strcmp("run1",*argv) == 0) {
+ ctrl |= FILTER_RUN1;
+ if (argc <= 0) {
+ _pam_log(LOG_ALERT,"no run filter supplied");
+ } else
+ break;
+ } else if (strcmp("run2",*argv) == 0) {
+ ctrl |= FILTER_RUN2;
+ if (argc <= 0) {
+ _pam_log(LOG_ALERT,"no run filter supplied");
+ } else
+ break;
+ } else {
+ _pam_log(LOG_ERR, "unrecognized option: %s (ignored)", *argv);
+ }
+ ++argv; /* step along list */
+ }
+
+ if (argc < 0) {
+ /* there was no reference to a filter */
+ *filtername = NULL;
+ *evp = NULL;
+ } else {
+ char **levp;
+ const char *tmp;
+ int i,size;
+
+ *filtername = *++argv;
+ if (ctrl & FILTER_DEBUG) {
+ _pam_log(LOG_DEBUG,"will run filter %s\n", *filtername);
+ }
+
+ levp = (char **) malloc(5*sizeof(char *));
+ if (levp == NULL) {
+ _pam_log(LOG_CRIT,"no memory for environment of filter");
+ return -1;
+ }
+
+ for (size=i=0; i<argc; ++i) {
+ size += strlen(argv[i])+1;
+ }
+
+ /* the "ARGS" variable */
+
+#define ARGS_OFFSET 5 /* sizeof("ARGS="); */
+#define ARGS_NAME "ARGS="
+
+ size += ARGS_OFFSET;
+
+ levp[0] = (char *) malloc(size);
+ if (levp[0] == NULL) {
+ _pam_log(LOG_CRIT,"no memory for filter arguments");
+ if (levp) {
+ free(levp);
+ }
+ return -1;
+ }
+
+ strncpy(levp[0],ARGS_NAME,ARGS_OFFSET);
+ for (i=0,size=ARGS_OFFSET; i<argc; ++i) {
+ strcpy(levp[0]+size, argv[i]);
+ size += strlen(argv[i]);
+ levp[0][size++] = ' ';
+ }
+ levp[0][--size] = '\0'; /* <NUL> terminate */
+
+ /* the "SERVICE" variable */
+
+#define SERVICE_OFFSET 8 /* sizeof("SERVICE="); */
+#define SERVICE_NAME "SERVICE="
+
+ pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp);
+ size = SERVICE_OFFSET+strlen(tmp);
+
+ levp[1] = (char *) malloc(size+1);
+ if (levp[1] == NULL) {
+ _pam_log(LOG_CRIT,"no memory for service name");
+ if (levp) {
+ free(levp[0]);
+ free(levp);
+ }
+ return -1;
+ }
+
+ strncpy(levp[1],SERVICE_NAME,SERVICE_OFFSET);
+ strcpy(levp[1]+SERVICE_OFFSET, tmp);
+ levp[1][size] = '\0'; /* <NUL> terminate */
+
+ /* the "USER" variable */
+
+#define USER_OFFSET 5 /* sizeof("USER="); */
+#define USER_NAME "USER="
+
+ pam_get_user(pamh, &tmp, NULL);
+ if (tmp == NULL) {
+ tmp = "<unknown>";
+ }
+ size = USER_OFFSET+strlen(tmp);
+
+ levp[2] = (char *) malloc(size+1);
+ if (levp[2] == NULL) {
+ _pam_log(LOG_CRIT,"no memory for user's name");
+ if (levp) {
+ free(levp[1]);
+ free(levp[0]);
+ free(levp);
+ }
+ return -1;
+ }
+
+ strncpy(levp[2],USER_NAME,USER_OFFSET);
+ strcpy(levp[2]+USER_OFFSET, tmp);
+ levp[2][size] = '\0'; /* <NUL> terminate */
+
+ /* the "USER" variable */
+
+#define TYPE_OFFSET 5 /* sizeof("TYPE="); */
+#define TYPE_NAME "TYPE="
+
+ size = TYPE_OFFSET+strlen(type);
+
+ levp[3] = (char *) malloc(size+1);
+ if (levp[3] == NULL) {
+ _pam_log(LOG_CRIT,"no memory for type");
+ if (levp) {
+ free(levp[2]);
+ free(levp[1]);
+ free(levp[0]);
+ free(levp);
+ }
+ return -1;
+ }
+
+ strncpy(levp[3],TYPE_NAME,TYPE_OFFSET);
+ strcpy(levp[3]+TYPE_OFFSET, type);
+ levp[3][size] = '\0'; /* <NUL> terminate */
+
+ levp[4] = NULL; /* end list */
+
+ *evp = levp;
+ }
+
+ if ((ctrl & FILTER_DEBUG) && *filtername) {
+ char **e;
+
+ _pam_log(LOG_DEBUG,"filter[%s]: %s",type,*filtername);
+ _pam_log(LOG_DEBUG,"environment:");
+ for (e=*evp; e && *e; ++e) {
+ _pam_log(LOG_DEBUG," %s",*e);
+ }
+ }
+
+ return ctrl;
+}
+
+static void free_evp(char *evp[])
+{
+ int i;
+
+ if (evp)
+ for (i=0; i<4; ++i) {
+ if (evp[i])
+ free(evp[i]);
+ }
+ free(evp);
+}
+
+static int set_filter(pam_handle_t *pamh, int flags, int ctrl
+ , const char **evp, const char *filtername)
+{
+ int status=-1;
+ char terminal[TERMINAL_LEN];
+ struct termio stored_mode; /* initial terminal mode settings */
+ int fd[2], child=0, child2=0, aterminal;
+
+ if (filtername == NULL || *filtername != '/') {
+ _pam_log(LOG_ALERT, "filtername not permitted; require full path");
+ return PAM_ABORT;
+ }
+
+ if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
+ aterminal = 0;
+ } else {
+ aterminal = 1;
+ }
+
+ if (aterminal) {
+
+ /* open the master pseudo terminal */
+
+ fd[0] = master(terminal);
+ if (fd[0] < 0) {
+ _pam_log(LOG_CRIT,"no master terminal");
+ return PAM_AUTH_ERR;
+ }
+
+ /* set terminal into raw mode.. remember old mode so that we can
+ revert to it after the child has quit. */
+
+ /* this is termio terminal handling... */
+
+ if (ioctl(STDIN_FILENO, TCGETA, (char *) &stored_mode ) < 0) {
+ /* in trouble, so close down */
+ close(fd[0]);
+ _pam_log(LOG_CRIT, "couldn't copy terminal mode");
+ return PAM_ABORT;
+ } else {
+ struct termio t_mode = stored_mode;
+
+ t_mode.c_iflag = 0; /* no input control */
+ t_mode.c_oflag &= ~OPOST; /* no ouput post processing */
+
+ /* no signals, canonical input, echoing, upper/lower output */
+ t_mode.c_lflag &= ~(ISIG|ICANON|ECHO|XCASE);
+ t_mode.c_cflag &= ~(CSIZE|PARENB); /* no parity */
+ t_mode.c_cflag |= CS8; /* 8 bit chars */
+
+ t_mode.c_cc[VMIN] = 1; /* number of chars to satisfy a read */
+ t_mode.c_cc[VTIME] = 0; /* 0/10th second for chars */
+
+ if (ioctl(STDIN_FILENO, TCSETA, (char *) &t_mode) < 0) {
+ close(fd[0]);
+ _pam_log(LOG_WARNING, "couldn't put terminal in RAW mode");
+ return PAM_ABORT;
+ }
+
+ /*
+ * NOTE: Unlike the stream socket case here the child
+ * opens the slave terminal as fd[1] *after* the fork...
+ */
+ }
+ } else {
+
+ /*
+ * not a terminal line so just open a stream socket fd[0-1]
+ * both set...
+ */
+
+ if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) {
+ _pam_log(LOG_CRIT,"couldn't open a stream pipe");
+ return PAM_ABORT;
+ }
+ }
+
+ /* start child process */
+
+ if ( (child = fork()) < 0 ) {
+
+ _pam_log(LOG_WARNING,"first fork failed");
+ if (aterminal) {
+ (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode);
+ }
+
+ return PAM_AUTH_ERR;
+ }
+
+ if ( child == 0 ) { /* child process *is* application */
+
+ if (aterminal) {
+
+ /* close the controlling tty */
+
+#if defined(__hpux) && defined(O_NOCTTY)
+ int t = open("/dev/tty", O_RDWR|O_NOCTTY);
+#else
+ int t = open("/dev/tty",O_RDWR);
+ if (t > 0) {
+ (void) ioctl(t, TIOCNOTTY, NULL);
+ close(t);
+ }
+#endif /* defined(__hpux) && defined(O_NOCTTY) */
+
+ /* make this process it's own process leader */
+ if (setsid() == -1) {
+ _pam_log(LOG_WARNING,"child cannot become new session");
+ return PAM_ABORT;
+ }
+
+ /* find slave's name */
+ terminal[5] = 't'; /* want to open slave terminal */
+ fd[1] = open(terminal, O_RDWR);
+ close(fd[0]); /* process is the child -- uses line fd[1] */
+
+ if (fd[1] < 0) {
+ _pam_log(LOG_WARNING,"cannot open slave terminal; %s"
+ ,terminal);
+ return PAM_ABORT;
+ }
+
+ /* initialize the child's terminal to be the way the
+ parent's was before we set it into RAW mode */
+
+ if (ioctl(fd[1], TCSETA, (char *) &stored_mode) < 0) {
+ _pam_log(LOG_WARNING,"cannot set slave terminal mode; %s"
+ ,terminal);
+ close(fd[1]);
+ return PAM_ABORT;
+ }
+
+ } else {
+
+ /* nothing to do for a simple stream socket */
+
+ }
+
+ /* re-assign the stdin/out to fd[1] <- (talks to filter). */
+
+ if ( dup2(fd[1],STDIN_FILENO) != STDIN_FILENO ||
+ dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO ||
+ dup2(fd[1],STDERR_FILENO) != STDERR_FILENO ) {
+ _pam_log(LOG_WARNING
+ ,"unable to re-assign STDIN/OUT/ERR...'s");
+ close(fd[1]);
+ return PAM_ABORT;
+ }
+
+ /* make sure that file descriptors survive 'exec's */
+
+ if ( fcntl(STDIN_FILENO, F_SETFD, 0) ||
+ fcntl(STDOUT_FILENO,F_SETFD, 0) ||
+ fcntl(STDERR_FILENO,F_SETFD, 0) ) {
+ _pam_log(LOG_WARNING
+ ,"unable to re-assign STDIN/OUT/ERR...'s");
+ return PAM_ABORT;
+ }
+
+ /* now the user input is read from the parent/filter: forget fd */
+
+ close(fd[1]);
+
+ /* the current process is now aparently working with filtered
+ stdio/stdout/stderr --- success! */
+
+ return PAM_SUCCESS;
+ }
+
+ /*
+ * process is the parent here. So we can close the application's
+ * input/output
+ */
+
+ close(fd[1]);
+
+ /* Clear out passwords... there is a security problem here in
+ * that this process never executes pam_end. Consequently, any
+ * other sensitive data in this process is *not* explicitly
+ * overwritten, before the process terminates */
+
+ (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
+
+ /* fork a copy of process to run the actual filter executable */
+
+ if ( (child2 = fork()) < 0 ) {
+
+ _pam_log(LOG_WARNING,"filter fork failed");
+ child2 = 0;
+
+ } else if ( child2 == 0 ) { /* exec the child filter */
+
+ if ( dup2(fd[0],APPIN_FILENO) != APPIN_FILENO ||
+ dup2(fd[0],APPOUT_FILENO) != APPOUT_FILENO ||
+ dup2(fd[0],APPERR_FILENO) != APPERR_FILENO ) {
+ _pam_log(LOG_WARNING
+ ,"unable to re-assign APPIN/OUT/ERR...'s");
+ close(fd[0]);
+ exit(1);
+ }
+
+ /* make sure that file descriptors survive 'exec's */
+
+ if ( fcntl(APPIN_FILENO, F_SETFD, 0) == -1 ||
+ fcntl(APPOUT_FILENO,F_SETFD, 0) == -1 ||
+ fcntl(APPERR_FILENO,F_SETFD, 0) == -1 ) {
+ _pam_log(LOG_WARNING
+ ,"unable to retain APPIN/OUT/ERR...'s");
+ close(APPIN_FILENO);
+ close(APPOUT_FILENO);
+ close(APPERR_FILENO);
+ exit(1);
+ }
+
+ /* now the user input is read from the parent through filter */
+
+ execle(filtername, "<pam_filter>", NULL, evp);
+
+ /* getting to here is an error */
+
+ _pam_log(LOG_ALERT, "filter: %s, not executable", filtername);
+
+ } else { /* wait for either of the two children to exit */
+
+ while (child && child2) { /* loop if there are two children */
+ int lstatus=0;
+ int chid;
+
+ chid = wait(&lstatus);
+ if (chid == child) {
+
+ if (WIFEXITED(lstatus)) { /* exited ? */
+ status = WEXITSTATUS(lstatus);
+ } else if (WIFSIGNALED(lstatus)) { /* killed ? */
+ status = -1;
+ } else
+ continue; /* just stopped etc.. */
+ child = 0; /* the child has exited */
+
+ } else if (chid == child2) {
+ /*
+ * if the filter has exited. Let the child die
+ * naturally below
+ */
+ if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus))
+ child2 = 0;
+ } else {
+
+ _pam_log(LOG_ALERT
+ ,"programming error <chid=%d,lstatus=%x>: "
+ __FILE__ " line %d"
+ , lstatus, __LINE__ );
+ child = child2 = 0;
+ status = -1;
+
+ }
+ }
+ }
+
+ close(fd[0]);
+
+ /* if there is something running, wait for it to exit */
+
+ while (child || child2) {
+ int lstatus=0;
+ int chid;
+
+ chid = wait(&lstatus);
+
+ if (child && chid == child) {
+
+ if (WIFEXITED(lstatus)) { /* exited ? */
+ status = WEXITSTATUS(lstatus);
+ } else if (WIFSIGNALED(lstatus)) { /* killed ? */
+ status = -1;
+ } else
+ continue; /* just stopped etc.. */
+ child = 0; /* the child has exited */
+
+ } else if (child2 && chid == child2) {
+
+ if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus))
+ child2 = 0;
+
+ } else {
+
+ _pam_log(LOG_ALERT
+ ,"programming error <chid=%d,lstatus=%x>: "
+ __FILE__ " line %d"
+ , lstatus, __LINE__ );
+ child = child2 = 0;
+ status = -1;
+
+ }
+ }
+
+ if (aterminal) {
+ /* reset to initial terminal mode */
+ (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode);
+ }
+
+ if (ctrl & FILTER_DEBUG) {
+ _pam_log(LOG_DEBUG,"parent process exited"); /* clock off */
+ }
+
+ /* quit the parent process, returning the child's exit status */
+
+ exit(status);
+}
+
+static int set_the_terminal(pam_handle_t *pamh)
+{
+ const char *tty;
+
+ if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS
+ || tty == NULL) {
+ tty = ttyname(STDIN_FILENO);
+ if (tty == NULL) {
+ _pam_log(LOG_ERR, "couldn't get the tty name");
+ return PAM_ABORT;
+ }
+ if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "couldn't set tty name");
+ return PAM_ABORT;
+ }
+ }
+ return PAM_SUCCESS;
+}
+
+static int need_a_filter(pam_handle_t *pamh
+ , int flags, int argc, const char **argv
+ , const char *name, int which_run)
+{
+ int ctrl;
+ char **evp;
+ const char *filterfile;
+ int retval;
+
+ ctrl = process_args(pamh, argc, argv, name, &evp, &filterfile);
+ if (ctrl == -1) {
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* set the tty to the old or the new one? */
+
+ if (!(ctrl & NON_TERM) && !(ctrl & NEW_TERM)) {
+ retval = set_the_terminal(pamh);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "tried and failed to set PAM_TTY");
+ }
+ } else {
+ retval = PAM_SUCCESS; /* nothing to do which is always a success */
+ }
+
+ if (retval == PAM_SUCCESS && (ctrl & which_run)) {
+ retval = set_filter(pamh, flags, ctrl
+ , (const char **)evp, filterfile);
+ }
+
+ if (retval == PAM_SUCCESS
+ && !(ctrl & NON_TERM) && (ctrl & NEW_TERM)) {
+ retval = set_the_terminal(pamh);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR
+ , "tried and failed to set new terminal as PAM_TTY");
+ }
+ }
+
+ free_evp(evp);
+
+ if (ctrl & FILTER_DEBUG) {
+ _pam_log(LOG_DEBUG, "filter/%s, returning %d", name, retval);
+ _pam_log(LOG_DEBUG, "[%s]", pam_strerror(pamh, retval));
+ }
+
+ return retval;
+}
+
+/* ----------------- public functions ---------------- */
+
+/*
+ * here are the advertised access points ...
+ */
+
+/* ------------------ authentication ----------------- */
+
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh
+ , int flags, int argc, const char **argv)
+{
+ return need_a_filter(pamh, flags, argc, argv
+ , "authenticate", FILTER_RUN1);
+}
+
+PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ return need_a_filter(pamh, flags, argc, argv, "setcred", FILTER_RUN2);
+}
+
+/* --------------- account management ---------------- */
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return need_a_filter(pamh, flags, argc, argv
+ , "setcred", FILTER_RUN1|FILTER_RUN2 );
+}
+
+/* --------------- session management ---------------- */
+
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ return need_a_filter(pamh, flags, argc, argv
+ , "open_session", FILTER_RUN1);
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ return need_a_filter(pamh, flags, argc, argv
+ , "close_session", FILTER_RUN2);
+}
+
+/* --------- updating authentication tokens --------- */
+
+
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ int runN;
+
+ if (flags & PAM_PRELIM_CHECK)
+ runN = FILTER_RUN1;
+ else if (flags & PAM_UPDATE_AUTHTOK)
+ runN = FILTER_RUN2;
+ else {
+ _pam_log(LOG_ERR, "unknown flags for chauthtok (0x%X)", flags);
+ return PAM_TRY_AGAIN;
+ }
+
+ return need_a_filter(pamh, flags, argc, argv, "chauthtok", runN);
+}
+
+#ifdef PAM_STATIC
+
+/* ------------ stuff for static modules ------------ */
+
+struct pam_module _pam_filter_modstruct = {
+ "pam_filter",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok,
+};
+
+#endif
diff --git a/contrib/libpam/modules/pam_filter/upperLOWER/Makefile b/contrib/libpam/modules/pam_filter/upperLOWER/Makefile
new file mode 100644
index 000000000000..09b693bf6803
--- /dev/null
+++ b/contrib/libpam/modules/pam_filter/upperLOWER/Makefile
@@ -0,0 +1,58 @@
+#
+# $Id: Makefile,v 1.5 1997/04/05 06:41:35 morgan Exp $
+#
+# $Log: Makefile,v $
+# Revision 1.5 1997/04/05 06:41:35 morgan
+# fakeroot
+#
+# Revision 1.4 1997/01/04 20:25:04 morgan
+# removed need for make
+#
+# Revision 1.3 1996/11/10 20:13:08 morgan
+# email address
+#
+# Revision 1.2 1996/11/10 20:12:24 morgan
+# cross platform support
+#
+# Revision 1.1 1996/06/02 08:17:02 morgan
+# Initial revision
+#
+#
+# This directory contains a pam_filter filter executable
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+#
+
+TITLE=upperLOWER
+
+#
+
+OBJS = $(TITLE).o
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+
+all: $(TITLE)
+
+$(TITLE): $(OBJS)
+ $(CC) -o $(TITLE) $(OBJS)
+ strip $(TITLE)
+
+install:
+ $(MKDIR) $(FAKEROOT)$(FILTERSDIR)
+ $(INSTALL) -m 511 $(TITLE) $(FAKEROOT)$(FILTERSDIR)
+
+remove:
+ cd $(FAKEROOT)$(FILTERSDIR) && rm -f $(TITLE)
+
+clean:
+ rm -f $(TITLE) $(OBJS) core *~
+
+extraclean: clean
+ rm -f *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_filter/upperLOWER/upperLOWER.c b/contrib/libpam/modules/pam_filter/upperLOWER/upperLOWER.c
new file mode 100644
index 000000000000..b375c0794edf
--- /dev/null
+++ b/contrib/libpam/modules/pam_filter/upperLOWER/upperLOWER.c
@@ -0,0 +1,160 @@
+/*
+ * $Id: upperLOWER.c,v 1.1 1996/06/02 08:17:02 morgan Exp $
+ *
+ * This is a sample filter program, for use with pam_filter (a module
+ * provided with Linux-PAM). This filter simply transposes upper and
+ * lower case letters, it is intended for demonstration purposes and
+ * it serves no purpose other than to annoy the user...
+ *
+ * $Log: upperLOWER.c,v $
+ * Revision 1.1 1996/06/02 08:17:02 morgan
+ * Initial revision
+ *
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <security/pam_filter.h>
+
+/* ---------------------------------------------------------------- */
+
+#include <stdarg.h>
+#ifdef hpux
+# define log_this syslog
+#else
+static void log_this(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("upperLOWER", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+#endif
+
+#include <ctype.h>
+
+static void do_transpose(char *buffer,int len)
+{
+ int i;
+ for (i=0; i<len; ++i) {
+ if (islower(buffer[i])) {
+ buffer[i] = toupper(buffer[i]);
+ } else {
+ buffer[i] = tolower(buffer[i]);
+ }
+ }
+}
+
+int main(int argc, char **argv, char **envp)
+{
+ char buffer[BUFSIZ];
+ fd_set readers;
+ void (*before_user)(char *,int);
+ void (*before_app)(char *,int);
+
+#ifdef DEBUG
+ {
+ int i;
+
+ fprintf(stderr,"environment :[\r\n");
+ for (i=0; envp[i]; ++i) {
+ fprintf(stderr,"-> %s\r\n",envp[i]);
+ }
+ fprintf(stderr,"]: end\r\n");
+ }
+#endif
+
+ if (argc != 1) {
+#ifdef DEBUG
+ fprintf(stderr,"filter invoked as conventional executable\n");
+#else
+ log_this(LOG_ERR, "filter invoked as conventional executable");
+#endif
+ exit(1);
+ }
+
+ before_user = before_app = do_transpose; /* assign filter functions */
+
+ /* enter a loop that deals with the input and output of the
+ user.. passing it to and from the application */
+
+ FD_ZERO(&readers); /* initialize reading mask */
+
+ for (;;) {
+
+ FD_SET(APPOUT_FILENO, &readers); /* wake for output */
+ FD_SET(APPERR_FILENO, &readers); /* wake for error */
+ FD_SET(STDIN_FILENO, &readers); /* wake for input */
+
+ if ( select(APPTOP_FILE,&readers,NULL,NULL,NULL) < 0 ) {
+#ifdef DEBUG
+ fprintf(stderr,"select failed\n");
+#else
+ log_this(LOG_WARNING,"select failed");
+#endif
+ break;
+ }
+
+ /* application errors */
+
+ if ( FD_ISSET(APPERR_FILENO,&readers) ) {
+ int got = read(APPERR_FILENO, buffer, BUFSIZ);
+ if (got <= 0) {
+ break;
+ } else {
+ /* translate to give to real terminal */
+ if (before_user != NULL)
+ before_user(buffer, got);
+ if ( write(STDERR_FILENO, buffer, got) != got ) {
+ log_this(LOG_WARNING,"couldn't write %d bytes?!",got);
+ break;
+ }
+ }
+ } else if ( FD_ISSET(APPOUT_FILENO,&readers) ) { /* app output */
+ int got = read(APPOUT_FILENO, buffer, BUFSIZ);
+ if (got <= 0) {
+ break;
+ } else {
+ /* translate to give to real terminal */
+ if (before_user != NULL)
+ before_user(buffer, got);
+ if ( write(STDOUT_FILENO, buffer, got) != got ) {
+ log_this(LOG_WARNING,"couldn't write %d bytes!?",got);
+ break;
+ }
+ }
+ }
+
+ if ( FD_ISSET(STDIN_FILENO, &readers) ) { /* user input */
+ int got = read(STDIN_FILENO, buffer, BUFSIZ);
+ if (got < 0) {
+ log_this(LOG_WARNING,"user input junked");
+ break;
+ } else if (got) {
+ /* translate to give to application */
+ if (before_app != NULL)
+ before_app(buffer, got);
+ if ( write(APPIN_FILENO, buffer, got) != got ) {
+ log_this(LOG_WARNING,"couldn't pass %d bytes!?",got);
+ break;
+ }
+ } else {
+ /* nothing received -- an error? */
+ log_this(LOG_WARNING,"user input null?");
+ break;
+ }
+ }
+ }
+
+ exit(0);
+}
+
+
+
diff --git a/contrib/libpam/modules/pam_ftp/Makefile b/contrib/libpam/modules/pam_ftp/Makefile
new file mode 100644
index 000000000000..b5355c68b55e
--- /dev/null
+++ b/contrib/libpam/modules/pam_ftp/Makefile
@@ -0,0 +1,96 @@
+#
+# $Id: Makefile,v 1.2 1997/04/05 06:40:33 morgan Exp $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.2 1997/04/05 06:40:33 morgan
+# fakeroot
+#
+# Revision 1.1 1996/12/01 03:17:57 morgan
+# Initial revision
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/11/14
+#
+
+TITLE=pam_ftp
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_ftp/README b/contrib/libpam/modules/pam_ftp/README
new file mode 100644
index 000000000000..597f9120bd86
--- /dev/null
+++ b/contrib/libpam/modules/pam_ftp/README
@@ -0,0 +1,20 @@
+# $Id: README,v 1.1 1996/12/01 03:17:57 morgan Exp $
+#
+
+This module is an authentication module that does not authenticate.
+Instead it always returns PAM_IGNORE, indicating that it does not want
+to affect the authentication process.
+
+Its purpose is to log a message to the syslog indicating the
+pam_item's available at the time it was invoked. It is a diagnostic
+tool.
+
+Recognized arguments:
+
+ none
+
+module services provided:
+
+ auth _authetication and _setcred (blank)
+
+Andrew Morgan
diff --git a/contrib/libpam/modules/pam_ftp/pam_ftp.c b/contrib/libpam/modules/pam_ftp/pam_ftp.c
new file mode 100644
index 000000000000..ca2d41545e94
--- /dev/null
+++ b/contrib/libpam/modules/pam_ftp/pam_ftp.c
@@ -0,0 +1,295 @@
+/* pam_ftp module */
+
+/*
+ * $Id: pam_ftp.c,v 1.2 1997/02/15 16:23:59 morgan Exp morgan $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ *
+ * $Log: pam_ftp.c,v $
+ * Revision 1.2 1997/02/15 16:23:59 morgan
+ * fixed logging to avoid a fixed buffer size
+ *
+ * Revision 1.1 1996/12/01 03:17:57 morgan
+ * Initial revision
+ *
+ *
+ */
+
+#define PLEASE_ENTER_PASSWORD "Password required for %s."
+#define GUEST_LOGIN_PROMPT "Guest login ok, " \
+"send your complete e-mail address as password."
+
+/* the following is a password that "can't be correct" */
+#define BLOCK_PASSWORD "\177BAD PASSWPRD\177"
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <string.h>
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-ftp", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+static int converse(pam_handle_t *pamh, int nargs
+ , struct pam_message **message
+ , struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ D(("begin to converse\n"));
+
+ retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
+ if ( retval == PAM_SUCCESS ) {
+
+ retval = conv->conv(nargs, ( const struct pam_message ** ) message
+ , response, conv->appdata_ptr);
+
+ D(("returned from application's conversation function\n"));
+
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_DEBUG, "conversation failure [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ } else {
+ _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ D(("ready to return from module conversation\n"));
+
+ return retval; /* propagate error status */
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 01
+#define PAM_IGNORE_EMAIL 02
+#define PAM_NO_ANON 04
+
+static int _pam_parse(int argc, const char **argv, char **users)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strncmp(*argv,"users=",6)) {
+ *users = x_strdup(6+*argv);
+ if (*users == NULL) {
+ ctrl |= PAM_NO_ANON;
+ _pam_log(LOG_CRIT, "failed to duplicate user list - anon off");
+ }
+ } else if (!strcmp(*argv,"ignore")) {
+ ctrl |= PAM_IGNORE_EMAIL;
+ } else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+/*
+ * check if name is in list or default list. place users name in *_user
+ * return 1 if listed 0 if not.
+ */
+
+static int lookup(const char *name, char *list, const char **_user)
+{
+ int anon = 0;
+
+ *_user = name; /* this is the default */
+ if (list) {
+ const char *l;
+ char *x;
+
+ x = list;
+ while ((l = strtok(x, ","))) {
+ x = NULL;
+ if (!strcmp(name, l)) {
+ *_user = list;
+ anon = 1;
+ }
+ }
+ } else {
+#define MAX_L 2
+ static const char *l[MAX_L] = { "ftp", "anonymous" };
+ int i;
+
+ for (i=0; i<MAX_L; ++i) {
+ if (!strcmp(l[i], name)) {
+ *_user = l[0];
+ anon = 1;
+ break;
+ }
+ }
+ }
+
+ return anon;
+}
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int retval, anon=0, ctrl;
+ const char *user;
+ char *users=NULL;
+
+ /*
+ * this module checks if the user name is ftp or annonymous. If
+ * this is the case, it can set the PAM_RUSER to the entered email
+ * address and SUCCEEDS, otherwise it FAILS.
+ */
+
+ ctrl = _pam_parse(argc, argv, &users);
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS || user == NULL) {
+ _pam_log(LOG_ERR, "no user specified");
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (!(ctrl & PAM_NO_ANON)) {
+ anon = lookup(user, users, &user);
+ }
+
+ if (anon) {
+ retval = pam_set_item(pamh, PAM_USER, (const void *)user);
+ if (retval != PAM_SUCCESS || user == NULL) {
+ _pam_log(LOG_ERR, "user resetting failed");
+ return PAM_USER_UNKNOWN;
+ }
+ }
+
+ /*
+ * OK. we require an email address for user or the user's password.
+ * - build conversation and get their input.
+ */
+
+ {
+ struct pam_message msg[1], *mesg[1];
+ struct pam_response *resp=NULL;
+ const char *token;
+ char *prompt=NULL;
+ int i=0;
+
+ mesg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ if (anon) {
+ prompt = malloc(sizeof(PLEASE_ENTER_PASSWORD + strlen(user)));
+ sprintf(prompt, PLEASE_ENTER_PASSWORD, user);
+ msg[i].msg = prompt;
+ } else {
+ msg[i].msg = GUEST_LOGIN_PROMPT;
+ }
+
+ retval = converse(pamh, ++i, mesg, &resp);
+ _pam_overwrite(prompt);
+ _pam_drop(prompt);
+
+ if (retval != PAM_SUCCESS) {
+ if (resp != NULL)
+ _pam_drop_reply(resp,i);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ if (anon) {
+ /* XXX: Some effort should be made to verify this email address! */
+
+ if (!(ctrl & PAM_IGNORE_EMAIL)) {
+ token = strtok(resp->resp, "@");
+ retval = pam_set_item(pamh, PAM_RUSER, token);
+
+ if (token && retval != PAM_SUCCESS) {
+ token = strtok(NULL, "@");
+ retval = pam_set_item(pamh, PAM_RHOST, token);
+ }
+ }
+ } else {
+ /*
+ * we have a password so set AUTHTOK
+ */
+
+ (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp);
+
+ /*
+ * this module failed, but the next one might succeed with
+ * this password.
+ */
+
+ retval = PAM_AUTH_ERR;
+ }
+
+ if (resp) { /* clean up */
+ _pam_drop_reply(resp, i);
+ }
+
+ /* success or failure */
+
+ return retval;
+ }
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_IGNORE;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_ftp_modstruct = {
+ "pam_ftp",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_group/Makefile b/contrib/libpam/modules/pam_group/Makefile
new file mode 100644
index 000000000000..5db53ccf1133
--- /dev/null
+++ b/contrib/libpam/modules/pam_group/Makefile
@@ -0,0 +1,114 @@
+#
+# $Id: Makefile,v 1.6 1997/04/05 06:39:56 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.6 1997/04/05 06:39:56 morgan
+# fakeroot
+#
+# Revision 1.5 1997/01/04 20:28:47 morgan
+# compile with and without libpwdb
+#
+# Revision 1.4 1996/11/10 20:13:18 morgan
+# cross platform support
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/6/11
+#
+
+TITLE=pam_group
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/group.conf
+export CONFILE
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+DEFS=-DCONFILE=\"$(CONFILE)\"
+ifndef STATIC
+ifeq ($(HAVE_PWDBLIB),yes)
+ DEFS+=-DWANT_PWDB
+ ELIBS=-lpwdb
+endif
+endif
+
+CFLAGS += $(DEFS)
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) $(ELIBS)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS) $(ELIBS)
+endif
+
+install: all
+ifdef DYNAMIC
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SCONFIGED)
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+ rm -f $(FAKEROOT)$(CONFILE)
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+ rm -f ./.ignore_age
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_group/group.conf b/contrib/libpam/modules/pam_group/group.conf
new file mode 100644
index 000000000000..bdd76adbe68f
--- /dev/null
+++ b/contrib/libpam/modules/pam_group/group.conf
@@ -0,0 +1,60 @@
+##
+## Note, to get this to work as it is currently typed you need
+##
+## 1. to run an application as root
+## 2. add the following groups to the /etc/group file:
+## floppy, games, sound
+##
+#
+# *** Please note that giving group membership on a session basis is
+# *** NOT inherently secure. If a user can create an executable that
+# *** is setgid a group that they are infrequently given membership
+# *** of, they can basically obtain group membership any time they
+# *** like. Example: games are alowed between the hours of 6pm and 6am
+# *** user joe logs in at 7pm writes a small C-program toplay.c that
+# *** invokes their favorite shell, compiles it and does
+# *** "chgrp games toplay; chmod g+s toplay". They are basically able
+# *** to play games any time... You have been warned. AGM
+#
+# this is an example configuration file for the pam_group module. Its
+# syntax is based on that of the pam_time module and (at some point in
+# the distant past was inspired by the 'shadow' package)
+#
+# the syntax of the lines is as follows:
+#
+# services;ttys;users;times;groups
+#
+# white space is ignored and lines maybe extended with '\\n' (escaped
+# newlines). From reading these comments, it is clear that
+# text following a '#' is ignored to the end of the line.
+#
+# the first four fields are described in the pam_time directory.
+# The only difference for these is how the time field is interpretted:
+# it is used to indicate "when" these groups are to be given to the user.
+#
+# groups
+# The (comma or space separated) list of groups that the user
+# inherits membership of. These groups are added if the previous
+# fields are satisfied by the user's request
+#
+
+#
+# Here is a simple example: running 'xsh' on tty* (any ttyXXX device),
+# the user 'us' is given access to the floppy (through membership of
+# the floppy group)
+#
+
+#xsh;tty*&!ttyp*;us;Al0000-2400;floppy
+
+#
+# another example: running 'xsh' on tty* (any ttyXXX device),
+# the user 'sword' is given access to games (through membership of
+# the floppy group) after work hours
+#
+
+#xsh; tty* ;sword;!Wk0900-1800;games, sound
+#xsh; tty* ;*;Al0900-1800;floppy
+
+#
+# End of group.conf file
+#
diff --git a/contrib/libpam/modules/pam_group/install_conf b/contrib/libpam/modules/pam_group/install_conf
new file mode 100755
index 000000000000..03bb7edb0235
--- /dev/null
+++ b/contrib/libpam/modules/pam_group/install_conf
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONFILE=$FAKEROOT"$CONFILE"
+IGNORE_AGE=./.ignore_age
+QUIET_INSTALL=../../.quiet_install
+CONF=./group.conf
+MODULE=pam_group
+
+echo
+
+if [ -f "$QUIET_INSTALL" ]; then
+ if [ ! -f "$CONFILE" ]; then
+ yes="y"
+ else
+ yes="skip"
+ fi
+elif [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "An older $MODULE configuration file already exists ($CONFILE)"
+ echo "Do you wish to copy the $CONF file in this distribution"
+ echo "to $CONFILE ? (y/n) [skip] "
+ read yes
+ else
+ yes="y"
+ fi
+else
+ yes="skip"
+fi
+
+if [ "$yes" = "y" ]; then
+ mkdir -p $FAKEROOT$CONFD
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ echo " Skipping $CONF installation"
+ if [ "$yes" = "n" ]; then
+ touch "$IGNORE_AGE"
+ fi
+fi
+
+echo
+
+exit 0
diff --git a/contrib/libpam/modules/pam_group/pam_group.c b/contrib/libpam/modules/pam_group/pam_group.c
new file mode 100644
index 000000000000..9e2cf885e9cf
--- /dev/null
+++ b/contrib/libpam/modules/pam_group/pam_group.c
@@ -0,0 +1,862 @@
+/* pam_group module */
+
+/*
+ * $Id: pam_group.c,v 1.7 1997/02/15 17:31:48 morgan Exp morgan $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/7/6
+ *
+ * $Log: pam_group.c,v $
+ * Revision 1.7 1997/02/15 17:31:48 morgan
+ * time parsing more robust
+ *
+ * Revision 1.6 1997/01/04 21:57:49 morgan
+ * fixed warning about setgroups not being defined
+ *
+ * Revision 1.5 1997/01/04 20:26:49 morgan
+ * can be compiled with and without libpwdb. fixed buffer underwriting
+ * pays attention to PAM_CRED flags(!)
+ *
+ * Revision 1.4 1996/12/01 02:54:37 morgan
+ * mostly debugging now uses D(())
+ *
+ * Revision 1.3 1996/11/10 21:01:22 morgan
+ * compatability and pam_get_user changes
+ */
+
+const static char rcsid[] =
+"$Id: pam_group.c,v 1.7 1997/02/15 17:31:48 morgan Exp morgan $;\n"
+"Version 0.5 for Linux-PAM\n"
+"Copyright (c) Andrew G. Morgan 1996 <morgan@parc.power.net>\n";
+
+#include <sys/file.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <syslog.h>
+#include <string.h>
+
+#define __USE_BSD
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef WANT_PWDB
+#include <pwdb/pwdb_public.h>
+#endif
+
+#define PAM_GROUP_CONF CONFILE /* from external define */
+#define PAM_GROUP_BUFLEN 1000
+#define FIELD_SEPARATOR ';' /* this is new as of .02 */
+
+typedef enum { FALSE, TRUE } boolean;
+typedef enum { AND, OR } operator;
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* --- static functions for checking whether the user should be let in --- */
+
+static void _log_err(const char *format, ... )
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_group", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(LOG_CRIT, format, args);
+ va_end(args);
+ closelog();
+}
+
+static void shift_bytes(char *mem, int from, int by)
+{
+ while (by-- > 0) {
+ *mem = mem[from];
+ ++mem;
+ }
+}
+
+static int read_field(int fd, char **buf, int *from, int *to)
+{
+ /* is buf set ? */
+
+ if (! *buf) {
+ *buf = (char *) malloc(PAM_GROUP_BUFLEN);
+ if (! *buf) {
+ _log_err("out of memory");
+ return -1;
+ }
+ *from = *to = 0;
+ fd = open(PAM_GROUP_CONF, O_RDONLY);
+ }
+
+ /* do we have a file open ? return error */
+
+ if (fd < 0 && *to <= 0) {
+ _log_err( PAM_GROUP_CONF " not opened");
+ memset(*buf, 0, PAM_GROUP_BUFLEN);
+ _pam_drop(*buf);
+ return -1;
+ }
+
+ /* check if there was a newline last time */
+
+ if ((*to > *from) && (*to > 0)
+ && ((*buf)[*from] == '\0')) { /* previous line ended */
+ (*from)++;
+ (*buf)[0] = '\0';
+ return fd;
+ }
+
+ /* ready for more data: first shift the buffer's remaining data */
+
+ *to -= *from;
+ shift_bytes(*buf, *from, *to);
+ *from = 0;
+ (*buf)[*to] = '\0';
+
+ while (fd >= 0 && *to < PAM_GROUP_BUFLEN) {
+ int i;
+
+ /* now try to fill the remainder of the buffer */
+
+ i = read(fd, *to + *buf, PAM_GROUP_BUFLEN - *to);
+ if (i < 0) {
+ _log_err("error reading " PAM_GROUP_CONF);
+ return -1;
+ } else if (!i) {
+ fd = -1; /* end of file reached */
+ } else
+ *to += i;
+
+ /*
+ * contract the buffer. Delete any comments, and replace all
+ * multiple spaces with single commas
+ */
+
+ i = 0;
+#ifdef DEBUG_DUMP
+ D(("buffer=<%s>",*buf));
+#endif
+ while (i < *to) {
+ if ((*buf)[i] == ',') {
+ int j;
+
+ for (j=++i; j<*to && (*buf)[j] == ','; ++j);
+ if (j!=i) {
+ shift_bytes(i + (*buf), j-i, (*to) - j);
+ *to -= j-i;
+ }
+ }
+ switch ((*buf)[i]) {
+ int j,c;
+ case '#':
+ for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j);
+ if (j >= *to) {
+ (*buf)[*to = ++i] = '\0';
+ } else if (c == '\n') {
+ shift_bytes(i + (*buf), j-i, (*to) - j);
+ *to -= j-i;
+ ++i;
+ } else {
+ _log_err("internal error in " __FILE__
+ " at line %d", __LINE__ );
+ return -1;
+ }
+ break;
+ case '\\':
+ if ((*buf)[i+1] == '\n') {
+ shift_bytes(i + *buf, 2, *to - (i+2));
+ *to -= 2;
+ }
+ break;
+ case '!':
+ case ' ':
+ case '\t':
+ if ((*buf)[i] != '!')
+ (*buf)[i] = ',';
+ /* delete any trailing spaces */
+ for (j=++i; j < *to && ( (c = (*buf)[j]) == ' '
+ || c == '\t' ); ++j);
+ shift_bytes(i + *buf, j-i, (*to)-j );
+ *to -= j-i;
+ break;
+ default:
+ ++i;
+ }
+ }
+ }
+
+ (*buf)[*to] = '\0';
+
+ /* now return the next field (set the from/to markers) */
+ {
+ int i;
+
+ for (i=0; i<*to; ++i) {
+ switch ((*buf)[i]) {
+ case '#':
+ case '\n': /* end of the line/file */
+ (*buf)[i] = '\0';
+ *from = i;
+ return fd;
+ case FIELD_SEPARATOR: /* end of the field */
+ (*buf)[i] = '\0';
+ *from = ++i;
+ return fd;
+ }
+ }
+ *from = i;
+ (*buf)[*from] = '\0';
+ }
+
+ if (*to <= 0) {
+ D(("[end of text]"));
+ *buf = NULL;
+ }
+ return fd;
+}
+
+/* read a member from a field */
+
+static int logic_member(const char *string, int *at)
+{
+ int len,c,to;
+ int done=0;
+ int token=0;
+
+ len=0;
+ to=*at;
+ do {
+ c = string[to++];
+
+ switch (c) {
+
+ case '\0':
+ --to;
+ done = 1;
+ break;
+
+ case '&':
+ case '|':
+ case '!':
+ if (token) {
+ --to;
+ }
+ done = 1;
+ break;
+
+ default:
+ if (isalpha(c) || c == '*' || isdigit(c) || c == '_'
+ || c == '-' || c == '.') {
+ token = 1;
+ } else if (token) {
+ --to;
+ done = 1;
+ } else {
+ ++*at;
+ }
+ }
+ } while (!done);
+
+ return to - *at;
+}
+
+typedef enum { VAL, OP } expect;
+
+static boolean logic_field(const void *me, const char *x, int rule,
+ boolean (*agrees)(const void *, const char *
+ , int, int))
+{
+ boolean left=FALSE, right, not=FALSE;
+ operator oper=OR;
+ int at=0, l;
+ expect next=VAL;
+
+ while ((l = logic_member(x,&at))) {
+ int c = x[at];
+
+ if (next == VAL) {
+ if (c == '!')
+ not = !not;
+ else if (isalpha(c) || c == '*') {
+ right = not ^ agrees(me, x+at, l, rule);
+ if (oper == AND)
+ left &= right;
+ else
+ left |= right;
+ next = OP;
+ } else {
+ _log_err("garbled syntax; expected name (rule #%d)", rule);
+ return FALSE;
+ }
+ } else { /* OP */
+ switch (c) {
+ case '&':
+ oper = AND;
+ break;
+ case '|':
+ oper = OR;
+ break;
+ default:
+ _log_err("garbled syntax; expected & or | (rule #%d)"
+ , rule);
+ D(("%c at %d",c,at));
+ return FALSE;
+ }
+ next = VAL;
+ }
+ at += l;
+ }
+
+ return left;
+}
+
+static boolean is_same(const void *A, const char *b, int len, int rule)
+{
+ int i;
+ const char *a;
+
+ a = A;
+ for (i=0; len > 0; ++i, --len) {
+ if (b[i] != a[i]) {
+ if (b[i++] == '*') {
+ return (!--len || !strncmp(b+i,a+strlen(a)-len,len));
+ } else
+ return FALSE;
+ }
+ }
+ return ( !len );
+}
+
+typedef struct {
+ int day; /* array of 7 bits, one set for today */
+ int minute; /* integer, hour*100+minute for now */
+} TIME;
+
+struct day {
+ const char *d;
+ int bit;
+} static const days[11] = {
+ { "su", 01 },
+ { "mo", 02 },
+ { "tu", 04 },
+ { "we", 010 },
+ { "th", 020 },
+ { "fr", 040 },
+ { "sa", 0100 },
+ { "wk", 076 },
+ { "wd", 0101 },
+ { "al", 0177 },
+ { NULL, 0 }
+};
+
+static TIME time_now(void)
+{
+ struct tm *local;
+ time_t the_time;
+ TIME this;
+
+ the_time = time((time_t *)0); /* get the current time */
+ local = localtime(&the_time);
+ this.day = days[local->tm_wday].bit;
+ this.minute = local->tm_hour*100 + local->tm_min;
+
+ D(("day: 0%o, time: %.4d", this.day, this.minute));
+ return this;
+}
+
+/* take the current date and see if the range "date" passes it */
+static boolean check_time(const void *AT, const char *times, int len, int rule)
+{
+ boolean not,pass;
+ int marked_day, time_start, time_end;
+ const TIME *at;
+ int i,j=0;
+
+ at = AT;
+ D(("checking: 0%o/%.4d vs. %s", at->day, at->minute, times));
+
+ if (times == NULL) {
+ /* this should not happen */
+ _log_err("internal error: " __FILE__ " line %d", __LINE__);
+ return FALSE;
+ }
+
+ if (times[j] == '!') {
+ ++j;
+ not = TRUE;
+ } else {
+ not = FALSE;
+ }
+
+ for (marked_day = 0; len > 0 && isalpha(times[j]); --len) {
+ int this_day=-1;
+
+ D(("%c%c ?", times[j], times[j+1]));
+ for (i=0; days[i].d != NULL; ++i) {
+ if (tolower(times[j]) == days[i].d[0]
+ && tolower(times[j+1]) == days[i].d[1] ) {
+ this_day = days[i].bit;
+ break;
+ }
+ }
+ j += 2;
+ if (this_day == -1) {
+ _log_err("bad day specified (rule #%d)", rule);
+ return FALSE;
+ }
+ marked_day ^= this_day;
+ }
+ if (marked_day == 0) {
+ _log_err("no day specified");
+ return FALSE;
+ }
+ D(("day range = 0%o", marked_day));
+
+ time_start = 0;
+ for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) {
+ time_start *= 10;
+ time_start += times[i+j]-'0'; /* is this portable? */
+ }
+ j += i;
+
+ if (times[j] == '-') {
+ time_end = 0;
+ for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) {
+ time_end *= 10;
+ time_end += times[i+j]-'0'; /* is this portable? */
+ }
+ j += i;
+ } else
+ time_end = -1;
+
+ D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j]));
+ if (i != 5 || time_end == -1) {
+ _log_err("no/bad times specified (rule #%d)", rule);
+ return TRUE;
+ }
+ D(("times(%d to %d)", time_start,time_end));
+ D(("marked_day = 0%o", marked_day));
+
+ /* compare with the actual time now */
+
+ pass = FALSE;
+ if (time_start < time_end) { /* start < end ? --> same day */
+ if ((at->day & marked_day) && (at->minute >= time_start)
+ && (at->minute < time_end)) {
+ D(("time is listed"));
+ pass = TRUE;
+ }
+ } else { /* spans two days */
+ if ((at->day & marked_day) && (at->minute >= time_start)) {
+ D(("caught on first day"));
+ pass = TRUE;
+ } else {
+ marked_day <<= 1;
+ marked_day |= (marked_day & 0200) ? 1:0;
+ D(("next day = 0%o", marked_day));
+ if ((at->day & marked_day) && (at->minute <= time_end)) {
+ D(("caught on second day"));
+ pass = TRUE;
+ }
+ }
+ }
+
+ return (not ^ pass);
+}
+
+static int find_member(const char *string, int *at)
+{
+ int len,c,to;
+ int done=0;
+ int token=0;
+
+ len=0;
+ to=*at;
+ do {
+ c = string[to++];
+
+ switch (c) {
+
+ case '\0':
+ --to;
+ done = 1;
+ break;
+
+ case '&':
+ case '|':
+ case '!':
+ if (token) {
+ --to;
+ }
+ done = 1;
+ break;
+
+ default:
+ if (isalpha(c) || isdigit(c) || c == '_' || c == '*'
+ || c == '-') {
+ token = 1;
+ } else if (token) {
+ --to;
+ done = 1;
+ } else {
+ ++*at;
+ }
+ }
+ } while (!done);
+
+ return to - *at;
+}
+
+#define GROUP_BLK 10
+#define blk_size(len) (((len-1 + GROUP_BLK)/GROUP_BLK)*GROUP_BLK)
+
+static int mkgrplist(char *buf, gid_t **list, int len)
+{
+ int l,at=0;
+ int blks;
+
+ blks = blk_size(len);
+ D(("cf. blks=%d and len=%d", blks,len));
+
+ while ((l = find_member(buf,&at))) {
+ int edge;
+
+ if (len >= blks) {
+ gid_t *tmp;
+
+ D(("allocating new block"));
+ tmp = (gid_t *) realloc((*list)
+ , sizeof(gid_t) * (blks += GROUP_BLK));
+ if (tmp != NULL) {
+ (*list) = tmp;
+ } else {
+ _log_err("out of memory for group list");
+ free(*list);
+ (*list) = NULL;
+ return -1;
+ }
+ }
+
+ /* '\0' terminate the entry */
+
+ edge = (buf[at+l]) ? 1:0;
+ buf[at+l] = '\0';
+ D(("found group: %s",buf+at));
+
+ /* this is where we convert a group name to a gid_t */
+#ifdef WANT_PWDB
+ {
+ int retval;
+ const struct pwdb *pw=NULL;
+
+ retval = pwdb_locate("group", PWDB_DEFAULT, buf+at
+ , PWDB_ID_UNKNOWN, &pw);
+ if (retval != PWDB_SUCCESS) {
+ _log_err("bad group: %s; %s", buf+at, pwdb_strerror(retval));
+ } else {
+ const struct pwdb_entry *pwe=NULL;
+
+ D(("group %s exists", buf+at));
+ retval = pwdb_get_entry(pw, "gid", &pwe);
+ if (retval == PWDB_SUCCESS) {
+ D(("gid = %d [%p]",* (const gid_t *) pwe->value,list));
+ (*list)[len++] = * (const gid_t *) pwe->value;
+ pwdb_entry_delete(&pwe); /* tidy up */
+ } else {
+ _log_err("%s group entry is bad; %s"
+ , pwdb_strerror(retval));
+ }
+ pw = NULL; /* break link - cached for later use */
+ }
+ }
+#else
+ {
+ const struct group *grp;
+
+ grp = getgrnam(buf+at);
+ if (grp == NULL) {
+ _log_err("bad group: %s", buf+at);
+ } else {
+ D(("group %s exists", buf+at));
+ (*list)[len++] = grp->gr_gid;
+ }
+ }
+#endif
+
+ /* next entry along */
+
+ at += l + edge;
+ }
+ D(("returning with [%p/len=%d]->%p",list,len,*list));
+ return len;
+}
+
+
+static int check_account(const char *service, const char *tty
+ , const char *user)
+{
+ int from=0,to=0,fd=-1;
+ char *buffer=NULL;
+ int count=0;
+ TIME here_and_now;
+ int retval=PAM_SUCCESS;
+ gid_t *grps;
+ int no_grps;
+
+ /*
+ * first we get the current list of groups - the application
+ * will have previously done an initgroups(), or equivalent.
+ */
+
+ D(("counting supplementary groups"));
+ no_grps = getgroups(0, NULL); /* find the current number of groups */
+ if (no_grps > 0) {
+ grps = calloc( blk_size(no_grps) , sizeof(gid_t) );
+ D(("copying current list into grps [%d big]",blk_size(no_grps)));
+ (void) getgroups(no_grps, grps);
+#ifdef DEBUG
+ {
+ int z;
+ for (z=0; z<no_grps; ++z) {
+ D(("gid[%d]=%d", z, grps[z]));
+ }
+ }
+#endif
+ } else {
+ D(("no supplementary groups known"));
+ no_grps = 0;
+ grps = NULL;
+ }
+
+ here_and_now = time_now(); /* find current time */
+
+ /* parse the rules in the configuration file */
+ do {
+ int good=TRUE;
+
+ /* here we get the service name field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ /* empty line .. ? */
+ continue;
+ }
+ ++count;
+ D(("working on rule #%d",count));
+
+ good = logic_field(service, buffer, count, is_same);
+ D(("with service: %s", good ? "passes":"fails" ));
+
+ /* here we get the terminal name field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_GROUP_CONF "; no tty entry #%d", count);
+ continue;
+ }
+ good &= logic_field(tty, buffer, count, is_same);
+ D(("with tty: %s", good ? "passes":"fails" ));
+
+ /* here we get the username field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_GROUP_CONF "; no user entry #%d", count);
+ continue;
+ }
+ good &= logic_field(user, buffer, count, is_same);
+ D(("with user: %s", good ? "passes":"fails" ));
+
+ /* here we get the time field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_GROUP_CONF "; no time entry #%d", count);
+ continue;
+ }
+
+ good &= logic_field(&here_and_now, buffer, count, check_time);
+ D(("with time: %s", good ? "passes":"fails" ));
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_GROUP_CONF "; no listed groups for rule #%d"
+ , count);
+ continue;
+ }
+
+ /*
+ * so we have a list of groups, we need to turn it into
+ * something to send to setgroups(2)
+ */
+
+ if (good) {
+ D(("adding %s to gid list", buffer));
+ good = mkgrplist(buffer, &grps, no_grps);
+ if (good < 0) {
+ no_grps = 0;
+ } else {
+ no_grps = good;
+ }
+ }
+
+ /* check the line is terminated correctly */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (buffer && buffer[0]) {
+ _log_err(PAM_GROUP_CONF "; poorly terminated rule #%d", count);
+ }
+
+ if (good > 0) {
+ D(("rule #%d passed, added %d groups", count, good));
+ } else if (good < 0) {
+ retval = PAM_BUF_ERR;
+ } else {
+ D(("rule #%d failed", count));
+ }
+
+ } while (buffer);
+
+ /* now set the groups for the user */
+
+ if (no_grps > 0) {
+ int err;
+ D(("trying to set %d groups", no_grps));
+#ifdef DEBUG
+ for (err=0; err<no_grps; ++err) {
+ D(("gid[%d]=%d", err, grps[err]));
+ }
+#endif
+ if ((err = setgroups(no_grps, grps))) {
+ D(("but couldn't set groups %d", err));
+ _log_err("unable to set the group membership for user (err=%d)"
+ , err);
+ retval = PAM_CRED_ERR;
+ }
+ }
+
+ if (grps) { /* tidy up */
+ memset(grps, 0, sizeof(gid_t) * blk_size(no_grps));
+ _pam_drop(grps);
+ no_grps = 0;
+ }
+
+ return retval;
+}
+
+/* --- public authentication management functions --- */
+
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ return PAM_IGNORE;
+}
+
+PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ const char *service=NULL, *tty=NULL;
+ const char *user=NULL;
+ int retval;
+ unsigned setting;
+
+ /* only interested in establishing credentials */
+
+ setting = flags;
+ if (!(setting & PAM_ESTABLISH_CRED)) {
+ D(("ignoring call - not for establishing credentials"));
+ return PAM_SUCCESS; /* don't fail because of this */
+ }
+
+ /* set service name */
+
+ if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
+ != PAM_SUCCESS || service == NULL) {
+ _log_err("cannot find the current service name");
+ return PAM_ABORT;
+ }
+
+ /* set username */
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL
+ || *user == '\0') {
+ _log_err("cannot determine the user's name");
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* set tty name */
+
+ if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS
+ || tty == NULL) {
+ D(("PAM_TTY not set, probing stdin"));
+ tty = ttyname(STDIN_FILENO);
+ if (tty == NULL) {
+ _log_err("couldn't get the tty name");
+ return PAM_ABORT;
+ }
+ if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) {
+ _log_err("couldn't set tty name");
+ return PAM_ABORT;
+ }
+ }
+
+ if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */
+ tty += 5;
+ }
+
+ /* good, now we have the service name, the user and the terminal name */
+
+ D(("service=%s", service));
+ D(("user=%s", user));
+ D(("tty=%s", tty));
+
+#ifdef WANT_PWDB
+
+ /* We initialize the pwdb library and check the account */
+ retval = pwdb_start(); /* initialize */
+ if (retval == PWDB_SUCCESS) {
+ retval = check_account(service,tty,user); /* get groups */
+ (void) pwdb_end(); /* tidy up */
+ } else {
+ D(("failed to initialize pwdb; %s", pwdb_strerror(retval)));
+ _log_err("unable to initialize libpwdb");
+ retval = PAM_ABORT;
+ }
+
+#else /* WANT_PWDB */
+ retval = check_account(service,tty,user); /* get groups */
+#endif /* WANT_PWDB */
+
+ return retval;
+}
+
+/* end of module definition */
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_group_modstruct = {
+ "pam_group",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
diff --git a/contrib/libpam/modules/pam_lastlog/Makefile b/contrib/libpam/modules/pam_lastlog/Makefile
new file mode 100644
index 000000000000..e51a72d31f50
--- /dev/null
+++ b/contrib/libpam/modules/pam_lastlog/Makefile
@@ -0,0 +1,106 @@
+#
+# $Id: Makefile,v 1.2 1997/04/05 06:17:14 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.2 1997/04/05 06:17:14 morgan
+# fakeroot fixed
+#
+# Revision 1.1 1997/01/04 20:29:28 morgan
+# Initial revision
+#
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/12/8
+#
+
+# Convenient defaults for compiling independently of the full source
+# tree.
+ifndef FULL_LINUX_PAM_SOURCE_TREE
+export DYNAMIC=-DPAM_DYNAMIC
+export CC=gcc
+export CFLAGS=-O2 -Dlinux -DLINUX_PAM \
+ -ansi -D_POSIX_SOURCE -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align -Wtraditional \
+ -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline \
+ -Wshadow -pedantic -fPIC
+export MKDIR=mkdir -p
+export LD_D=gcc -shared -Xlinker -x
+endif
+
+TITLE=pam_lastlog
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+
+####################### don't edit below #######################
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_lastlog/pam_lastlog.c b/contrib/libpam/modules/pam_lastlog/pam_lastlog.c
new file mode 100644
index 000000000000..96714f6bc16d
--- /dev/null
+++ b/contrib/libpam/modules/pam_lastlog/pam_lastlog.c
@@ -0,0 +1,469 @@
+/* pam_lastlog module */
+
+/*
+ * $Id: pam_lastlog.c,v 1.3 1997/04/05 06:18:21 morgan Exp morgan $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ *
+ * This module does the necessary work to display the last login
+ * time+date for this user, it then updates this entry for the
+ * present (login) service.
+ *
+ * $Log: pam_lastlog.c,v $
+ * Revision 1.3 1997/04/05 06:18:21 morgan
+ * removed xstrdup - unused
+ *
+ * Revision 1.2 1997/02/15 17:18:21 morgan
+ * removed fixed buffer in logging
+ *
+ * Revision 1.1 1997/01/04 20:29:28 morgan
+ * Initial revision
+ *
+ */
+
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_UTMP_H
+# include <utmp.h>
+#else
+# include <lastlog.h>
+#endif
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#ifdef WANT_PWDB
+#include <pwdb/pwdb_public.h> /* use POSIX front end */
+#endif
+
+#if defined(hpux) || defined(sunos) || defined(solaris)
+# ifndef _PATH_LASTLOG
+# define _PATH_LASTLOG "/usr/adm/lastlog"
+# endif /* _PATH_LASTLOG */
+# ifndef UT_HOSTSIZE
+# define UT_HOSTSIZE 16
+# endif /* UT_HOSTSIZE */
+# ifndef UT_LINESIZE
+# define UT_LINESIZE 12
+# endif /* UT_LINESIZE */
+#endif
+#if defined(hpux)
+struct lastlog {
+ time_t ll_time;
+ char ll_line[UT_LINESIZE];
+ char ll_host[UT_HOSTSIZE]; /* same as in utmp */
+};
+#endif /* hpux */
+
+/* XXX - time before ignoring lock. Is 1 sec enough? */
+#define LASTLOG_IGNORE_LOCK_TIME 1
+
+#define DEFAULT_HOST "" /* "[no.where]" */
+#define DEFAULT_TERM "" /* "tt???" */
+#define LASTLOG_NEVER_WELCOME "Welcome to your new account!"
+#define LASTLOG_INTRO "Last login:"
+#define LASTLOG_TIME " %s"
+#define _LASTLOG_HOST_FORMAT " from %%.%ds"
+#define _LASTLOG_LINE_FORMAT " on %%.%ds"
+#define LASTLOG_TAIL ""
+#define LASTLOG_MAXSIZE (sizeof(LASTLOG_INTRO)+0 \
+ +sizeof(LASTLOG_TIME)+strlen(the_time) \
+ +sizeof(_LASTLOG_HOST_FORMAT)+UT_HOSTSIZE \
+ +sizeof(_LASTLOG_LINE_FORMAT)+UT_LINESIZE \
+ +sizeof(LASTLOG_TAIL))
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_SESSION
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* some syslogging */
+
+static void _log_err(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-lastlog", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+
+#define LASTLOG_DATE 01 /* display the date of the last login */
+#define LASTLOG_HOST 02 /* display the last host used (if set) */
+#define LASTLOG_LINE 04 /* display the last terminal used */
+#define LASTLOG_NEVER 010 /* display a welcome message for first login */
+#define LASTLOG_DEBUG 020 /* send info to syslog(3) */
+#define LASTLOG_QUIET 040 /* keep quiet about things */
+
+static int _pam_parse(int flags, int argc, const char **argv)
+{
+ int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE);
+
+ /* does the appliction require quiet? */
+ if (flags & PAM_SILENT) {
+ ctrl |= LASTLOG_QUIET;
+ }
+
+ /* step through arguments */
+ for (; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug")) {
+ ctrl |= LASTLOG_DEBUG;
+ } else if (!strcmp(*argv,"nodate")) {
+ ctrl |= ~LASTLOG_DATE;
+ } else if (!strcmp(*argv,"noterm")) {
+ ctrl |= ~LASTLOG_LINE;
+ } else if (!strcmp(*argv,"nohost")) {
+ ctrl |= ~LASTLOG_HOST;
+ } else if (!strcmp(*argv,"silent")) {
+ ctrl |= LASTLOG_QUIET;
+ } else if (!strcmp(*argv,"never")) {
+ ctrl |= LASTLOG_NEVER;
+ } else {
+ _log_err(LOG_ERR,"unknown option; %s",*argv);
+ }
+ }
+
+ D(("ctrl = %o", ctrl));
+ return ctrl;
+}
+
+/* a front end for conversations */
+
+static int converse(pam_handle_t *pamh, int ctrl, int nargs
+ , struct pam_message **message
+ , struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ D(("begin to converse"));
+
+ retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
+ if ( retval == PAM_SUCCESS ) {
+
+ retval = conv->conv(nargs, ( const struct pam_message ** ) message
+ , response, conv->appdata_ptr);
+
+ D(("returned from application's conversation function"));
+
+ if (retval != PAM_SUCCESS && (ctrl & LASTLOG_DEBUG) ) {
+ _log_err(LOG_DEBUG, "conversation failure [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ } else {
+ _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ D(("ready to return from module conversation"));
+
+ return retval; /* propagate error status */
+}
+
+static int make_remark(pam_handle_t *pamh, int ctrl, const char *remark)
+{
+ int retval;
+
+ if (!(ctrl & LASTLOG_QUIET)) {
+ struct pam_message msg[1], *mesg[1];
+ struct pam_response *resp=NULL;
+
+ mesg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = remark;
+
+ retval = converse(pamh, ctrl, 1, mesg, &resp);
+
+ msg[0].msg = NULL;
+ if (resp) {
+ _pam_drop_reply(resp, 1);
+ }
+ } else {
+ D(("keeping quiet"));
+ retval = PAM_SUCCESS;
+ }
+
+ D(("returning %s", pam_strerror(pamh, retval)));
+ return retval;
+}
+
+/*
+ * Values for the announce flags..
+ */
+
+static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid)
+{
+ struct flock last_lock;
+ struct lastlog last_login;
+ int retval = PAM_SESSION_ERR;
+ int last_fd;
+
+ /* obtain the last login date and all the relevant info */
+ last_fd = open(_PATH_LASTLOG, O_RDWR);
+ if (last_fd < 0) {
+ D(("unable to open the %s file", _PATH_LASTLOG));
+ if (announce & LASTLOG_DEBUG) {
+ _log_err(LOG_DEBUG, "unable to open %s file", _PATH_LASTLOG);
+ }
+ retval = PAM_PERM_DENIED;
+ } else {
+ int win;
+
+ /* read the lastlogin file - for this uid */
+ (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET);
+
+ memset(&last_lock, 0, sizeof(last_lock));
+ last_lock.l_type = F_RDLCK;
+ last_lock.l_whence = SEEK_SET;
+ last_lock.l_start = sizeof(last_login) * (off_t) uid;
+ last_lock.l_len = sizeof(last_login);
+
+ if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) {
+ D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
+ _log_err(LOG_ALERT, "%s file is locked/read", _PATH_LASTLOG);
+ sleep(LASTLOG_IGNORE_LOCK_TIME);
+ }
+
+ win = ( read(last_fd, &last_login, sizeof(last_login))
+ == sizeof(last_login) );
+
+ last_lock.l_type = F_UNLCK;
+ (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
+
+ if (!win) {
+ D(("First login for user uid=%d", _PATH_LASTLOG, uid));
+ if (announce & LASTLOG_DEBUG) {
+ _log_err(LOG_DEBUG, "creating lastlog for uid %d", uid);
+ }
+ memset(&last_login, 0, sizeof(last_login));
+ }
+
+ /* rewind */
+ (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET);
+
+ if (!(announce & LASTLOG_QUIET)) {
+ if (last_login.ll_time) {
+ char *the_time;
+ char *remark;
+
+ the_time = ctime(&last_login.ll_time);
+ the_time[-1+strlen(the_time)] = '\0'; /* delete '\n' */
+
+ remark = malloc(LASTLOG_MAXSIZE);
+ if (remark == NULL) {
+ D(("no memory for last login remark"));
+ retval = PAM_BUF_ERR;
+ } else {
+ int at;
+
+ /* printing prefix */
+ at = sprintf(remark, "%s", LASTLOG_INTRO);
+
+ /* we want the date? */
+ if (announce & LASTLOG_DATE) {
+ at += sprintf(remark+at, LASTLOG_TIME, the_time);
+ }
+
+ /* we want & have the host? */
+ if ((announce & LASTLOG_HOST)
+ && (last_login.ll_host[0] != '\0')) {
+ char format[2*sizeof(_LASTLOG_HOST_FORMAT)];
+
+ (void) sprintf(format, _LASTLOG_HOST_FORMAT
+ , UT_HOSTSIZE);
+ D(("format: %s", format));
+ at += sprintf(remark+at, format, last_login.ll_host);
+ _pam_overwrite(format);
+ }
+
+ /* we want and have the terminal? */
+ if ((announce & LASTLOG_LINE)
+ && (last_login.ll_line[0] != '\0')) {
+ char format[2*sizeof(_LASTLOG_LINE_FORMAT)];
+
+ (void) sprintf(format, _LASTLOG_LINE_FORMAT
+ , UT_LINESIZE);
+ D(("format: %s", format));
+ at += sprintf(remark+at, format, last_login.ll_line);
+ _pam_overwrite(format);
+ }
+
+ /* display requested combo */
+ sprintf(remark+at, "%s", LASTLOG_TAIL);
+
+ retval = make_remark(pamh, announce, remark);
+
+ /* free all the stuff malloced */
+ _pam_overwrite(remark);
+ _pam_drop(remark);
+ }
+ } else if ((!last_login.ll_time) && (announce & LASTLOG_NEVER)) {
+ D(("this is the first time this user has logged in"));
+ retval = make_remark(pamh, announce, LASTLOG_NEVER_WELCOME);
+ }
+ } else {
+ D(("no text was requested"));
+ retval = PAM_SUCCESS;
+ }
+
+ /* write latest value */
+ {
+ const char *remote_host=NULL
+ , *terminal_line=DEFAULT_TERM;
+
+ /* set this login date */
+ D(("set the most recent login time"));
+
+ (void) time(&last_login.ll_time); /* set the time */
+
+ /* set the remote host */
+ (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host);
+ if (remote_host == NULL) {
+ remote_host = DEFAULT_HOST;
+ }
+
+ /* copy to last_login */
+ strncpy(last_login.ll_host, remote_host
+ , sizeof(last_login.ll_host));
+ remote_host = NULL;
+
+ /* set the terminal line */
+ (void) pam_get_item(pamh, PAM_TTY, (const void **)&terminal_line);
+ D(("terminal = %s", terminal_line));
+ if (terminal_line == NULL) {
+ terminal_line = DEFAULT_TERM;
+ } else if ( !strncmp("/dev/", terminal_line, 5) ) {
+ /* strip leading "/dev/" from tty.. */
+ terminal_line += 5;
+ }
+ D(("terminal = %s", terminal_line));
+
+ /* copy to last_login */
+ strncpy(last_login.ll_line, terminal_line
+ , sizeof(last_login.ll_line));
+ terminal_line = NULL;
+
+ D(("locking last_log file"));
+
+ /* now we try to lock this file-record exclusively; non-blocking */
+ memset(&last_lock, 0, sizeof(last_lock));
+ last_lock.l_type = F_WRLCK;
+ last_lock.l_whence = SEEK_SET;
+ last_lock.l_start = sizeof(last_login) * (off_t) uid;
+ last_lock.l_len = sizeof(last_login);
+
+ if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) {
+ D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
+ _log_err(LOG_ALERT, "%s file is locked/write", _PATH_LASTLOG);
+ sleep(LASTLOG_IGNORE_LOCK_TIME);
+ }
+
+ D(("writing to the last_log file"));
+ (void) write(last_fd, &last_login, sizeof(last_login));
+
+ last_lock.l_type = F_UNLCK;
+ (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
+ D(("unlocked"));
+
+ close(last_fd); /* all done */
+ }
+ D(("all done with last login"));
+ }
+
+ /* reset the last login structure */
+ memset(&last_login, 0, sizeof(last_login));
+
+ return retval;
+}
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc
+ , const char **argv)
+{
+ int retval, ctrl;
+ const char *user;
+ const struct passwd *pwd;
+ uid_t uid;
+
+ /*
+ * this module gets the uid of the PAM_USER. Uses it to display
+ * last login info and then updates the lastlog for that user.
+ */
+
+ ctrl = _pam_parse(flags, argc, argv);
+
+ /* which user? */
+
+ retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
+ if (retval != PAM_SUCCESS || user == NULL || *user == '\0') {
+ _log_err(LOG_NOTICE, "user unknown");
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* what uid? */
+
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ D(("couldn't identify user %s", user));
+ return PAM_CRED_INSUFFICIENT;
+ }
+ uid = pwd->pw_uid;
+ pwd = NULL; /* tidy up */
+
+ /* process the current login attempt (indicate last) */
+
+ retval = last_login_date(pamh, ctrl, uid);
+
+ /* indicate success or failure */
+
+ uid = -1; /* forget this */
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_lastlog_modstruct = {
+ "pam_lastlog",
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_limits/Makefile b/contrib/libpam/modules/pam_limits/Makefile
new file mode 100644
index 000000000000..f6a0e07ca48b
--- /dev/null
+++ b/contrib/libpam/modules/pam_limits/Makefile
@@ -0,0 +1,102 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# Created by Cristian Gafton <gafton@redhat.com> 1996/09/10
+#
+
+ifeq ($(OS),linux)
+ifeq ($(HAVE_PWDBLIB),yes)
+TITLE=pam_limits
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/limits.conf
+export CONFILE
+
+CFLAGS+=-DLIMITS_FILE=\"$(CONFILE)\"
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) -lpwdb
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ifdef DYNAMIC
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SCONFIGED)
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~ *.so
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+else
+include ../dont_makefile
+endif
+else
+include ../dont_makefile
+endif
diff --git a/contrib/libpam/modules/pam_limits/README b/contrib/libpam/modules/pam_limits/README
new file mode 100644
index 000000000000..06a6857a8135
--- /dev/null
+++ b/contrib/libpam/modules/pam_limits/README
@@ -0,0 +1,87 @@
+
+pam_limits module:
+ Imposing user limits on login.
+
+THEORY OF OPERATION:
+
+First, make a root-only-readable file (/etc/limits by default or LIMITS_FILE
+defined Makefile) that describes the resource limits you wish to impose. No
+limits are imposed on UID 0 accounts.
+
+Each line describes a limit for a user in the form:
+
+<domain> <type> <item> <value>
+
+Where:
+<domain> can be:
+ - an user name
+ - a group name, with @group syntax
+ - the wildcard *, for default entry
+
+<type> can have the two values:
+ - "soft" for enforcinf the soft limits
+ - "hard" for enforcing hard limits
+
+<item> can be one of the following:
+ - core - limits the core file size (KB)
+ - data - max data size (KB)
+ - fsize - maximum filesize (KB)
+ - memlock - max locked-in-memory address space (KB)
+ - nofile - max number of open files
+ - rss - max resident set size (KB)
+ - stack - max stack size (KB)
+ - cpu - max CPU time (MIN)
+ - nproc - max number of processes
+ - as - address space limit
+ - maxlogins - max number of logins for this user
+ - maxsyslogins - max number of logins on the system
+
+To completely disable limits for a user (or a group), a single dash (-)
+will do (Example: 'bin -', '@admin -'). Please remember that individual
+limits have priority over group limits, so if you impose no limits for admin
+group, but one of the members in this group have a limits line, the user
+will have its limits set according to this line.
+
+Also, please note that all limit settings are set PER LOGIN. They are
+not global, nor are they permanent (the session only)
+
+In the LIMITS_FILE, the # character introduces a comment - the rest of the
+line is ignored.
+
+The pam_limits module does its best to report configuration problems found
+in LIMITS_FILE via syslog.
+
+EXAMPLE configuration file:
+===========================
+* soft core 0
+* hard rss 10000
+@student hard nproc 20
+@faculty soft nproc 20
+@faculty hard nproc 50
+ftp hard nproc 0
+@student - maxlogins 4
+
+
+ARGUMENTS RECOGNIZED:
+ debug verbose logging
+
+ conf=/path/to/file the limits configuration file if different from the
+ one set at compile time.
+
+MODULE SERVICES PROVIDED:
+ session _open_session and _close_session (blank)
+
+USAGE:
+ For the services you need resources limits (login for example) put a
+ the following line in /etc/pam.conf as the last line for that
+ service (usually after the pam_unix session line:
+
+ login session required /lib/security/pam_limits.so
+
+ Replace "login" for each service you are using this module, replace
+ "/lib/security" path with your real modules path.
+
+AUTHOR:
+ Cristian Gafton <gafton@redhat.com>
+ Thanks to Elliot Lee <sopwith@redhat.com> for his comments on
+ improving this module.
diff --git a/contrib/libpam/modules/pam_limits/install_conf b/contrib/libpam/modules/pam_limits/install_conf
new file mode 100755
index 000000000000..d92c1f952e46
--- /dev/null
+++ b/contrib/libpam/modules/pam_limits/install_conf
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONFILE=$FAKEROOT"$CONFILE"
+IGNORE_AGE=./.ignore_age
+QUIET_INSTALL=../../.quiet_install
+CONF=./limits.skel
+MODULE=pam_limits
+
+echo
+
+if [ -f "$QUIET_INSTALL" ]; then
+ if [ ! -f "$CONFILE" ]; then
+ yes="y"
+ else
+ yes="skip"
+ fi
+elif [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "An older $MODULE configuration file already exists ($CONFILE)"
+ echo "Do you wish to copy the $CONF file in this distribution"
+ echo "to $CONFILE ? (y/n) [skip] "
+ read yes
+ else
+ yes="y"
+ fi
+else
+ yes="skip"
+fi
+
+if [ "$yes" = "y" ]; then
+ mkdir -p $FAKEROOT$CONFD
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ echo " Skipping $CONF installation"
+ if [ "$yes" = "n" ]; then
+ touch "$IGNORE_AGE"
+ fi
+fi
+
+echo
+
+exit 0
diff --git a/contrib/libpam/modules/pam_limits/limits.skel b/contrib/libpam/modules/pam_limits/limits.skel
new file mode 100644
index 000000000000..ea57e42513e4
--- /dev/null
+++ b/contrib/libpam/modules/pam_limits/limits.skel
@@ -0,0 +1,41 @@
+# /etc/security/limits.conf
+#
+#Each line describes a limit for a user in the form:
+#
+#<domain> <type> <item> <value>
+#
+#Where:
+#<domain> can be:
+# - an user name
+# - a group name, with @group syntax
+# - the wildcard *, for default entry
+#
+#<type> can have the two values:
+# - "soft" for enforcing the soft limits
+# - "hard" for enforcing hard limits
+#
+#<item> can be one of the following:
+# - core - limits the core file size (KB)
+# - data - max data size (KB)
+# - fsize - maximum filesize (KB)
+# - memlock - max locked-in-memory address space (KB)
+# - nofile - max number of open files
+# - rss - max resident set size (KB)
+# - stack - max stack size (KB)
+# - cpu - max CPU time (MIN)
+# - nproc - max number of processes
+# - as - address space limit
+# - maxlogins - max number of logins for this user
+#
+#<domain> <type> <item> <value>
+#
+
+#* soft core 0
+#* hard rss 10000
+#@student hard nproc 20
+#@faculty soft nproc 20
+#@faculty hard nproc 50
+#ftp hard nproc 0
+#@student - maxlogins 4
+
+# End of file
diff --git a/contrib/libpam/modules/pam_limits/pam_limits.c b/contrib/libpam/modules/pam_limits/pam_limits.c
new file mode 100644
index 000000000000..179c43028b4e
--- /dev/null
+++ b/contrib/libpam/modules/pam_limits/pam_limits.c
@@ -0,0 +1,592 @@
+/*
+ * pam_limits - impose resource limits when opening a user session
+ *
+ * 1.5 - Elliot Lee's "max system logins patch"
+ * 1.4 - addressed bug in configuration file parser
+ * 1.3 - modified the configuration file format
+ * 1.2 - added 'debug' and 'conf=' arguments
+ * 1.1 - added @group support
+ * 1.0 - initial release - Linux ONLY
+ *
+ * See end for Copyright information
+ */
+
+#if !(defined(linux))
+#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!!
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#define __USE_POSIX2
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <utmp.h>
+#ifndef UT_USER /* some systems have ut_name instead of ut_user */
+#define UT_USER ut_user
+#endif
+
+/* Module defines */
+#define LINE_LENGTH 1024
+
+#define LIMITS_DEF_USER 0 /* limit was set by an user entry */
+#define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */
+#define LIMITS_DEF_DEFAULT 2 /* limit was set by an default entry */
+#define LIMITS_DEF_NONE 3 /* this limit was not set yet */
+
+/* internal data */
+static char conf_file[BUFSIZ];
+
+struct user_limits_struct {
+ int src_soft;
+ int src_hard;
+ struct rlimit limit;
+};
+
+static struct user_limits_struct limits[RLIM_NLIMITS];
+static int login_limit; /* the max logins limit */
+static int login_limit_def; /* which entry set the login limit */
+static int flag_numsyslogins; /* whether to limit logins only for a
+ specific user or to count all logins */
+
+#define LIMIT_LOGIN RLIM_NLIMITS+1
+#define LIMIT_NUMSYSLOGINS RLIM_NLIMITS+2
+#define LIMIT_SOFT 1
+#define LIMIT_HARD 2
+
+#define PAM_SM_SESSION
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+#include <pwdb/pwdb_map.h>
+
+/* logging */
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_limits", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 0x0001
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strncmp(*argv,"conf=",5))
+ strcpy(conf_file,*argv+5);
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+
+/* limits stuff */
+#ifndef LIMITS_FILE
+#define LIMITS_FILE "/etc/security/limits.conf"
+#endif
+
+#define LIMIT_ERR 1 /* error setting a limit */
+#define LOGIN_ERR 2 /* too many logins err */
+
+/* Counts the number of user logins and check against the limit*/
+static int check_logins(const char *name, int limit, int ctrl)
+{
+ struct utmp *ut;
+ unsigned int count;
+
+ if (ctrl & PAM_DEBUG_ARG) {
+ _pam_log(LOG_DEBUG, "checking logins for '%s' / %d\n", name,limit);
+ }
+
+ if (limit < 0)
+ return 0; /* no limits imposed */
+ if (limit == 0) /* maximum 0 logins ? */ {
+ _pam_log(LOG_WARNING, "No logins allowed for '%s'\n", name);
+ return LOGIN_ERR;
+ }
+
+ setutent();
+ count = 0;
+ while((ut = getutent())) {
+#ifdef USER_PROCESS
+ if (ut->ut_type != USER_PROCESS)
+ continue;
+#endif
+ if (ut->UT_USER[0] == '\0')
+ continue;
+ if (!flag_numsyslogins
+ && strncmp(name, ut->UT_USER, sizeof(ut->UT_USER)) != 0)
+ continue;
+ if (++count >= limit)
+ break;
+ }
+ endutent();
+ if (count >= limit) {
+ if (name) {
+ _pam_log(LOG_WARNING, "Too many logins (max %d) for %s",
+ limit, name);
+ } else {
+ _pam_log(LOG_WARNING, "Too many system logins (max %d)", limit);
+ }
+ return LOGIN_ERR;
+ }
+ return 0;
+}
+
+/* checks if a user is on a list of members of the GID 0 group */
+static int is_on_list(char * const *list, const char *member)
+{
+ while (*list) {
+ if (strcmp(*list, member) == 0)
+ return 1;
+ list++;
+ }
+ return 0;
+}
+
+/* Checks if a user is a member of a group */
+static int is_on_group(const char *user_name, const char *group_name)
+{
+ struct passwd *pwd;
+ struct group *grp, *pgrp;
+ char uname[LINE_LENGTH], gname[LINE_LENGTH];
+
+ if (!strlen(user_name))
+ return 0;
+ if (!strlen(group_name))
+ return 0;
+ memset(uname, 0, sizeof(uname));
+ strncpy(uname, user_name, LINE_LENGTH);
+ memset(gname, 0, sizeof(gname));
+ strncpy(gname, group_name, LINE_LENGTH);
+
+ setpwent();
+ pwd = getpwnam(uname);
+ endpwent();
+ if (!pwd)
+ return 0;
+
+ /* the info about this group */
+ setgrent();
+ grp = getgrnam(gname);
+ endgrent();
+ if (!grp)
+ return 0;
+
+ /* first check: is a member of the group_name group ? */
+ if (is_on_list(grp->gr_mem, uname))
+ return 1;
+
+ /* next check: user primary group is group_name ? */
+ setgrent();
+ pgrp = getgrgid(pwd->pw_gid);
+ endgrent();
+ if (!pgrp)
+ return 0;
+ if (!strcmp(pgrp->gr_name, gname))
+ return 1;
+
+ return 0;
+}
+
+static int init_limits(void)
+{
+ int retval = PAM_SUCCESS;
+
+ D(("called."));
+
+ retval |= getrlimit(RLIMIT_CPU, &limits[RLIMIT_CPU].limit);
+ limits[RLIMIT_CPU].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_CPU].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_FSIZE, &limits[RLIMIT_FSIZE].limit);
+ limits[RLIMIT_FSIZE].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_FSIZE].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_DATA, &limits[RLIMIT_DATA].limit);
+ limits[RLIMIT_DATA].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_DATA].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_STACK, &limits[RLIMIT_STACK].limit);
+ limits[RLIMIT_STACK].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_STACK].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_CORE, &limits[RLIMIT_CORE].limit);
+ limits[RLIMIT_CORE].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_CORE].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_RSS, &limits[RLIMIT_RSS].limit);
+ limits[RLIMIT_RSS].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_RSS].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_NPROC, &limits[RLIMIT_NPROC].limit);
+ limits[RLIMIT_NPROC].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_NPROC].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_NOFILE, &limits[RLIMIT_NOFILE].limit);
+ limits[RLIMIT_NOFILE].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_NOFILE].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_MEMLOCK, &limits[RLIMIT_MEMLOCK].limit);
+ limits[RLIMIT_MEMLOCK].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_MEMLOCK].src_hard = LIMITS_DEF_NONE;
+
+ retval |= getrlimit(RLIMIT_AS, &limits[RLIMIT_AS].limit);
+ limits[RLIMIT_AS].src_soft = LIMITS_DEF_NONE;
+ limits[RLIMIT_AS].src_hard = LIMITS_DEF_NONE;
+
+ login_limit = -2;
+ login_limit_def = LIMITS_DEF_NONE;
+ return retval;
+}
+
+static void process_limit(int source, const char *lim_type,
+ const char *lim_item, const char *lim_value,
+ int ctrl)
+{
+ int limit_item;
+ int limit_type = 0;
+ long limit_value;
+ char **endptr = (char **) &lim_value;
+ const char *value_orig = lim_value;
+
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "%s: processing(%d) %s %s %s\n",
+ __FUNCTION__,source,lim_type,lim_item,lim_value);
+
+ if (strcmp(lim_item, "cpu") == 0)
+ limit_item = RLIMIT_CPU;
+ else if (strcmp(lim_item, "fsize") == 0)
+ limit_item = RLIMIT_FSIZE;
+ else if (strcmp(lim_item, "data") == 0)
+ limit_item = RLIMIT_DATA;
+ else if (strcmp(lim_item, "stack") == 0)
+ limit_item = RLIMIT_STACK;
+ else if (strcmp(lim_item, "core") == 0)
+ limit_item = RLIMIT_CORE;
+ else if (strcmp(lim_item, "rss") == 0)
+ limit_item = RLIMIT_RSS;
+ else if (strcmp(lim_item, "nproc") == 0)
+ limit_item = RLIMIT_NPROC;
+ else if (strcmp(lim_item, "nofile") == 0)
+ limit_item = RLIMIT_NOFILE;
+ else if (strcmp(lim_item, "memlock") == 0)
+ limit_item = RLIMIT_MEMLOCK;
+ else if (strcmp(lim_item, "as") == 0)
+ limit_item = RLIMIT_AS;
+ else if (strcmp(lim_item, "maxlogins") == 0) {
+ limit_item = LIMIT_LOGIN;
+ flag_numsyslogins = 0;
+ } else if (strcmp(lim_item, "maxsyslogins") == 0) {
+ limit_item = LIMIT_NUMSYSLOGINS;
+ flag_numsyslogins = 1;
+ } else {
+ _pam_log(LOG_DEBUG,"unknown limit item '%s'", lim_item);
+ return;
+ }
+
+ if (strcmp(lim_type,"soft")==0)
+ limit_type=LIMIT_SOFT;
+ else if (strcmp(lim_type, "hard")==0)
+ limit_type=LIMIT_HARD;
+ else if (strcmp(lim_type,"-")==0)
+ limit_type=LIMIT_SOFT | LIMIT_HARD;
+ else if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS) {
+ _pam_log(LOG_DEBUG,"unknown limit type '%s'", lim_type);
+ return;
+ }
+
+ limit_value = strtol(lim_value, endptr, 10);
+ if (limit_value == 0 && value_orig == *endptr) { /* no chars read */
+ if (strcmp(lim_value,"-") != 0) {
+ _pam_log(LOG_DEBUG,"wrong limit value '%s'", lim_value);
+ return;
+ } else
+ if (limit_item != LIMIT_LOGIN) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,
+ "'-' limit value valid for maxlogins type only");
+ return;
+ } else
+ limit_value = -1;
+ }
+
+ switch(limit_item) {
+ case RLIMIT_CPU:
+ limit_value *= 60;
+ break;
+ case RLIMIT_FSIZE:
+ case RLIMIT_DATA:
+ case RLIMIT_STACK:
+ case RLIMIT_CORE:
+ case RLIMIT_RSS:
+ case RLIMIT_MEMLOCK:
+ case RLIMIT_AS:
+ limit_value *= 1024;
+ break;
+ }
+
+ if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS) {
+ if (limit_type & LIMIT_SOFT)
+ if (limits[limit_item].src_soft < source)
+ return;
+ else {
+ limits[limit_item].limit.rlim_cur = limit_value;
+ limits[limit_item].src_soft = source;
+ }
+ if (limit_type & LIMIT_HARD)
+ if (limits[limit_item].src_hard < source)
+ return;
+ else {
+ limits[limit_item].limit.rlim_max = limit_value;
+ limits[limit_item].src_hard = source;
+ }
+ } else
+ if (login_limit_def < source)
+ return;
+ else {
+ login_limit = limit_value;
+ login_limit_def = source;
+ }
+
+ return;
+}
+
+static int parse_config_file(const char *uname, int ctrl)
+{
+ FILE *fil;
+ char buf[LINE_LENGTH];
+
+#define CONF_FILE (conf_file[0])?conf_file:LIMITS_FILE
+ /* check for the LIMITS_FILE */
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"reading settings from '%s'", CONF_FILE);
+ fil = fopen(CONF_FILE, "r");
+ if (fil == NULL) {
+ _pam_log (LOG_WARNING, "can not read settings from %s", CONF_FILE);
+ return PAM_SERVICE_ERR;
+ }
+#undef CONF_FILE
+
+ /* init things */
+ memset(buf, 0, sizeof(buf));
+ /* start the show */
+ while (fgets(buf, LINE_LENGTH, fil) != NULL) {
+ char domain[LINE_LENGTH];
+ char ltype[LINE_LENGTH];
+ char item[LINE_LENGTH];
+ char value[LINE_LENGTH];
+ int i,j;
+ char *tptr;
+
+ tptr = buf;
+ /* skip the leading white space */
+ while (*tptr && isspace(*tptr))
+ tptr++;
+ strcpy(buf, (const char *)tptr);
+
+ /* Rip off the comments */
+ tptr = strchr(buf,'#');
+ if (tptr)
+ *tptr = '\0';
+ /* Rip off the newline char */
+ tptr = strchr(buf,'\n');
+ if (tptr)
+ *tptr = '\0';
+ /* Anything left ? */
+ if (!strlen(buf)) {
+ memset(buf, 0, sizeof(buf));
+ continue;
+ }
+
+ memset(domain, 0, sizeof(domain));
+ memset(ltype, 0, sizeof(ltype));
+ memset(item, 0, sizeof(item));
+ memset(value, 0, sizeof(value));
+
+ i = sscanf(buf,"%s%s%s%s", domain, ltype, item, value);
+ for(j=0; j < strlen(domain); j++)
+ domain[j]=tolower(domain[j]);
+ for(j=0; j < strlen(ltype); j++)
+ ltype[j]=tolower(ltype[j]);
+ for(j=0; j < strlen(item); j++)
+ item[j]=tolower(item[j]);
+ for(j=0; j < strlen(value); j++)
+ value[j]=tolower(value[j]);
+
+ if (i == 4) { /* a complete line */
+ if (strcmp(uname, domain) == 0) /* this user have a limit */
+ process_limit(LIMITS_DEF_USER, ltype, item, value, ctrl);
+ else if (domain[0]=='@') {
+ if (is_on_group(uname, domain+1))
+ process_limit(LIMITS_DEF_GROUP, ltype, item, value, ctrl);
+ } else if (strcmp(domain, "*") == 0)
+ process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, ctrl);
+ } else
+ _pam_log(LOG_DEBUG,"invalid line '%s'", buf);
+ }
+ fclose(fil);
+ return PAM_SUCCESS;
+}
+
+static int setup_limits(const char * uname, int ctrl)
+{
+ int i;
+ int retval = PAM_SUCCESS;
+
+ for (i=0; i<RLIM_NLIMITS; i++) {
+ if (limits[i].limit.rlim_cur > limits[i].limit.rlim_max)
+ limits[i].limit.rlim_cur = limits[i].limit.rlim_max;
+ retval |= setrlimit(i, &limits[i].limit);
+ }
+
+ if (retval != PAM_SUCCESS)
+ retval = LIMIT_ERR;
+ if (login_limit > 0) {
+ if (check_logins(uname, login_limit, ctrl) == LOGIN_ERR)
+ retval |= LOGIN_ERR;
+ } else if (login_limit == 0)
+ retval |= LOGIN_ERR;
+ return retval;
+}
+
+/* now the session stuff */
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval;
+ char *user_name;
+ struct passwd *pwd;
+ int ctrl;
+
+ D(("called."));
+
+ memset(conf_file, 0, sizeof(conf_file));
+
+ ctrl = _pam_parse(argc, argv);
+ retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
+ if ( user_name == NULL || retval != PAM_SUCCESS ) {
+ _pam_log(LOG_CRIT, "open_session - error recovering username");
+ return PAM_SESSION_ERR;
+ }
+
+ setpwent();
+ pwd = getpwnam(user_name);
+ endpwent();
+ if (!pwd) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_WARNING, "open_session username '%s' does not exist",
+ user_name);
+ return PAM_SESSION_ERR;
+ }
+
+ /* do not impose limits on UID 0 accounts */
+ if (!pwd->pw_uid) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "user '%s' have UID 0 - no limits imposed",
+ user_name);
+ return PAM_SUCCESS;
+ }
+
+ retval = init_limits();
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "can not initialize");
+ return PAM_IGNORE;
+ }
+
+ retval = parse_config_file(pwd->pw_name,ctrl);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "error parsing the configuration file");
+ return PAM_IGNORE;
+ }
+
+ retval = setup_limits(pwd->pw_name, ctrl);
+ if (retval & LOGIN_ERR) {
+ printf("\nToo many logins for '%s'\n",pwd->pw_name);
+ sleep(2);
+ return PAM_PERM_DENIED;
+ }
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ /* nothing to do */
+ return PAM_SUCCESS;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_limits_modstruct = {
+ "pam_limits",
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ NULL
+};
+#endif
+
+/*
+ * Copyright (c) Cristian Gafton, 1996-1997, <gafton@redhat.com>
+ * All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_listfile/Makefile b/contrib/libpam/modules/pam_listfile/Makefile
new file mode 100644
index 000000000000..02940390b333
--- /dev/null
+++ b/contrib/libpam/modules/pam_listfile/Makefile
@@ -0,0 +1,84 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+
+TITLE=pam_listfile
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_listfile/README b/contrib/libpam/modules/pam_listfile/README
new file mode 100644
index 000000000000..b65e7dbbe701
--- /dev/null
+++ b/contrib/libpam/modules/pam_listfile/README
@@ -0,0 +1,25 @@
+SUMMARY:
+ pam_listfile:
+ Checks a specified item against a list in a file.
+ Options:
+ * item=[tty|user|rhost|ruser|group|shell]
+ * sense=[allow|deny] (action to take if found in file,
+ if the item is NOT found in the file, then
+ the opposite action is requested)
+ * file=/the/file/to/get/the/list/from
+ * onerr=[succeed|fail] (if something weird happens
+ such as unable to open the file, what to do?)
+ * apply=[user|@group]
+ restrict the user class for which the restriction
+ apply. Note that with item=[user|ruser|group] this
+ does not make sense, but for item=[tty|rhost|shell]
+ it have a meaning. (Cristian Gafton)
+
+ Also checks to make sure that the list file is a plain
+ file and not world writable.
+
+ - Elliot Lee <sopwith@redhat.com>, Red Hat Software.
+ v0.9 August 16, 1996.
+
+BUGS:
+ Bugs?
diff --git a/contrib/libpam/modules/pam_listfile/pam_listfile.c b/contrib/libpam/modules/pam_listfile/pam_listfile.c
new file mode 100644
index 000000000000..e54b12aaec0c
--- /dev/null
+++ b/contrib/libpam/modules/pam_listfile/pam_listfile.c
@@ -0,0 +1,436 @@
+/*
+ * $Id: pam_listfile.c,v 1.6 1997/04/05 06:38:35 morgan Exp $
+ *
+ * $Log: pam_listfile.c,v $
+ * Revision 1.6 1997/04/05 06:38:35 morgan
+ * reformat mostly
+ *
+ * Revision 1.5 1997/02/15 17:29:41 morgan
+ * removed fixed length buffer in logging
+ *
+ * Revision 1.4 1997/01/04 20:32:10 morgan
+ * ammendments for pam_listfile handling
+ *
+ * Revision 1.3 1996/11/10 21:02:08 morgan
+ * compiles with .53
+ *
+ * Revision 1.2 1996/09/05 06:22:58 morgan
+ * Michael's patches
+ *
+ */
+
+/*
+ * by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
+ * July 25, 1996.
+ * This code shamelessly ripped from the pam_rootok module.
+ */
+
+#ifdef linux
+# define _SVID_SOURCE
+# define _BSD_SOURCE
+# define __USE_BSD
+# define __USE_SVID
+# define __USE_MISC
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-listfile", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* checks if a user is on a list of members */
+static int is_on_list(char * const *list, const char *member)
+{
+ while (*list) {
+ if (strcmp(*list, member) == 0)
+ return 1;
+ list++;
+ }
+ return 0;
+}
+
+/* Checks if a user is a member of a group */
+static int is_on_group(const char *user_name, const char *group_name)
+{
+ struct passwd *pwd;
+ struct group *grp, *pgrp;
+ char uname[BUFSIZ], gname[BUFSIZ];
+
+ if (!strlen(user_name))
+ return 0;
+ if (!strlen(group_name))
+ return 0;
+ bzero(uname, sizeof(uname));
+ strncpy(uname, user_name, BUFSIZ-1);
+ bzero(gname, sizeof(gname));
+ strncpy(gname, group_name, BUFSIZ-1);
+
+ setpwent();
+ pwd = getpwnam(uname);
+ endpwent();
+ if (!pwd)
+ return 0;
+
+ /* the info about this group */
+ setgrent();
+ grp = getgrnam(gname);
+ endgrent();
+ if (!grp)
+ return 0;
+
+ /* first check: is a member of the group_name group ? */
+ if (is_on_list(grp->gr_mem, uname))
+ return 1;
+
+ /* next check: user primary group is group_name ? */
+ setgrent();
+ pgrp = getgrgid(pwd->pw_gid);
+ endgrent();
+ if (!pgrp)
+ return 0;
+ if (!strcmp(pgrp->gr_name, gname))
+ return 1;
+
+ return 0;
+}
+
+/* --- authentication management functions (only) --- */
+
+/* Extended Items that are not directly available via pam_get_item() */
+#define EI_GROUP (1 << 0)
+#define EI_SHELL (1 << 1)
+
+/* Constants for apply= parameter */
+#define APPLY_TYPE_NULL 0
+#define APPLY_TYPE_NONE 1
+#define APPLY_TYPE_USER 2
+#define APPLY_TYPE_GROUP 3
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2;
+ const char *citemp;
+ char *ifname=NULL;
+ char aline[256];
+ char mybuf[256],myval[256];
+ struct stat fileinfo;
+ FILE *inf;
+ char apply_val[256];
+ int apply_type;
+
+ /* Stuff for "extended" items */
+ struct passwd *userinfo;
+ struct group *grpinfo;
+ char *itemlist[256]; /* Maximum of 256 items */
+
+ D(("called."));
+
+ apply_type=APPLY_TYPE_NULL;
+ memset(apply_val,0,sizeof(apply_val));
+
+ for(i=0; i < argc; i++) {
+ {
+ char *junk;
+ junk = (char *) malloc(strlen(argv[i])+1);
+ if (junk == NULL) {
+ return PAM_BUF_ERR;
+ }
+ strcpy(junk,argv[i]);
+ strncpy(mybuf,strtok(junk,"="),255);
+ strncpy(myval,strtok(NULL,"="),255);
+ free(junk);
+ }
+ if(!strcmp(mybuf,"onerr"))
+ if(!strcmp(myval,"succeed"))
+ onerr = PAM_SUCCESS;
+ else if(!strcmp(myval,"fail"))
+ onerr = PAM_SERVICE_ERR;
+ else
+ return PAM_SERVICE_ERR;
+ else if(!strcmp(mybuf,"sense"))
+ if(!strcmp(myval,"allow"))
+ sense=0;
+ else if(!strcmp(myval,"deny"))
+ sense=1;
+ else
+ return onerr;
+ else if(!strcmp(mybuf,"file")) {
+ ifname = (char *)malloc(strlen(myval)+1);
+ strcpy(ifname,myval);
+ } else if(!strcmp(mybuf,"item"))
+ if(!strcmp(myval,"user"))
+ citem = PAM_USER;
+ else if(!strcmp(myval,"tty"))
+ citem = PAM_TTY;
+ else if(!strcmp(myval,"rhost"))
+ citem = PAM_RHOST;
+ else if(!strcmp(myval,"ruser"))
+ citem = PAM_RUSER;
+ else { /* These items are related to the user, but are not
+ directly gettable with pam_get_item */
+ citem = PAM_USER;
+ if(!strcmp(myval,"group"))
+ extitem = EI_GROUP;
+ else if(!strcmp(myval,"shell"))
+ extitem = EI_SHELL;
+ else
+ citem = 0;
+ } else if(!strcmp(mybuf,"apply")) {
+ apply_type=APPLY_TYPE_NONE;
+ if (myval[0]=='@') {
+ apply_type=APPLY_TYPE_GROUP;
+ strncpy(apply_val,myval+1,sizeof(apply_val)-1);
+ } else {
+ apply_type=APPLY_TYPE_USER;
+ strncpy(apply_val,myval,sizeof(apply_val)-1);
+ }
+ } else {
+ _pam_log(LOG_ERR,"Unknown option: %s",mybuf);
+ return onerr;
+ }
+ }
+
+ if(!citem) {
+ _pam_log(LOG_ERR,"Unknown item or item not specified");
+ return onerr;
+ } else if(!ifname) {
+ _pam_log(LOG_ERR,"List filename not specified");
+ return onerr;
+ } else if(sense == 2) {
+ _pam_log(LOG_ERR,"Unknown sense or sense not specified");
+ return onerr;
+ } else if(
+ (apply_type==APPLY_TYPE_NONE) ||
+ ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0'))
+ ) {
+ _pam_log(LOG_ERR,"Invalid usage for apply= parameter");
+ return onerr;
+ }
+
+ /* Check if it makes sense to use the apply= parameter */
+ if (apply_type != APPLY_TYPE_NULL) {
+ if((citem==PAM_USER) || (citem==PAM_RUSER)) {
+ _pam_log(LOG_WARNING,"Non-sense use for apply= parameter");
+ apply_type=APPLY_TYPE_NULL;
+ }
+ if(extitem && (extitem==EI_GROUP)) {
+ _pam_log(LOG_WARNING,"Non-sense use for apply= parameter");
+ apply_type=APPLY_TYPE_NULL;
+ }
+ }
+
+ /* Short-circuit - test if this session apply for this user */
+ {
+ const char *user_name;
+ int rval;
+
+ rval=pam_get_user(pamh,&user_name,NULL);
+ if((rval==PAM_SUCCESS) && user_name[0]) {
+ /* Got it ? Valid ? */
+ if(apply_type==APPLY_TYPE_USER) {
+ if(strcmp(user_name, apply_val)) {
+ /* Does not apply to this user */
+#ifdef DEBUG
+ _pam_log(LOG_DEBUG,"don't apply: apply=%s, user=%s",
+ apply_val,user_name);
+#endif /* DEBUG */
+ return PAM_IGNORE;
+ }
+ } else if(apply_type==APPLY_TYPE_GROUP) {
+ if(!is_on_group(user_name,apply_val)) {
+ /* Not a member of apply= group */
+#ifdef DEBUG
+ _pam_log(LOG_DEBUG,"don't apply: %s not a member of group %s",
+ user_name,apply_val);
+#endif /* DEBUG */
+ return PAM_IGNORE;
+ }
+ }
+ }
+ }
+
+ retval = pam_get_item(pamh,citem,(const void **)&citemp);
+ if(retval != PAM_SUCCESS) {
+ return onerr;
+ }
+ if((citem == PAM_USER) && !citemp) {
+ pam_get_user(pamh,&citemp,NULL);
+ if (retval != PAM_SUCCESS)
+ return PAM_SERVICE_ERR;
+ }
+
+ if(!citemp || (strlen(citemp) <= 0)) {
+ /* The item was NULL - we are sure not to match */
+ return sense?PAM_SUCCESS:PAM_AUTH_ERR;
+ }
+
+ if(extitem) {
+ switch(extitem) {
+ case EI_GROUP:
+ setpwent();
+ userinfo = getpwnam(citemp);
+ setgrent();
+ grpinfo = getgrgid(userinfo->pw_gid);
+ itemlist[0] = x_strdup(grpinfo->gr_name);
+ setgrent();
+ for (i=1; (i < sizeof(itemlist)/sizeof(itemlist[0])-1) &&
+ (grpinfo = getgrent()); ) {
+ if (is_on_list(grpinfo->gr_mem,citemp)) {
+ itemlist[i++] = x_strdup(grpinfo->gr_name);
+ }
+ }
+ itemlist[i] = NULL;
+ endgrent();
+ endpwent();
+ break;
+ case EI_SHELL:
+ setpwent();
+ userinfo = getpwnam(citemp); /* Assume that we have already gotten
+ PAM_USER in pam_get_item() - a valid
+ assumption since citem gets set to
+ PAM_USER in the extitem switch */
+ citemp = userinfo->pw_shell;
+ endpwent();
+ break;
+ default:
+ _pam_log(LOG_ERR,"Internal weirdness, unknown extended item %d",
+ extitem);
+ return onerr;
+ }
+ }
+#ifdef DEBUG
+ _pam_log(LOG_INFO,"Got file = %s, item = %d, value = %s, sense = %d",
+ ifname, citem, citemp, sense);
+#endif
+ if(lstat(ifname,&fileinfo)) {
+ _pam_log(LOG_ERR,
+ "Couldn't open %s",ifname);
+ return onerr;
+ }
+
+ if((fileinfo.st_mode & S_IWOTH)
+ || !S_ISREG(fileinfo.st_mode)) {
+ /* If the file is world writable or is not a
+ normal file, return error */
+ _pam_log(LOG_ERR,
+ "%s is either world writable or not a normal file",
+ ifname);
+ return PAM_AUTH_ERR;
+ }
+
+ inf = fopen(ifname,"r");
+ if(inf == NULL) { /* Check that we opened it successfully */
+ if (onerr == PAM_SERVICE_ERR) {
+ /* Only report if it's an error... */
+ _pam_log(LOG_ERR, "Error opening %s", ifname);
+ }
+ return onerr;
+ }
+ /* There should be no more errors from here on */
+ retval=PAM_AUTH_ERR;
+ /* This loop assumes that PAM_SUCCESS == 0
+ and PAM_AUTH_ERR != 0 */
+#ifdef DEBUG
+ assert(PAM_SUCCESS == 0);
+ assert(PAM_AUTH_ERR != 0);
+#endif
+ if(extitem == EI_GROUP) {
+ while((fgets(aline,255,inf) != NULL)
+ && retval) {
+ if(aline[strlen(aline) - 1] == '\n')
+ aline[strlen(aline) - 1] = '\0';
+ for(i=0;itemlist[i];)
+ /* If any of the items match, strcmp() == 0, and we get out
+ of this loop */
+ retval = (strcmp(aline,itemlist[i++]) && retval);
+ }
+ for(i=0;itemlist[i];)
+ free(itemlist[i++]);
+ } else {
+ while((fgets(aline,255,inf) != NULL)
+ && retval) {
+ if(aline[strlen(aline) - 1] == '\n')
+ aline[strlen(aline) - 1] = '\0';
+ retval = strcmp(aline,citemp);
+ }
+ }
+ fclose(inf);
+ free(ifname);
+ if(retval) {
+#ifdef DEBUG
+ syslog(LOG_INFO,"Returning %d, retval = %d",
+ sense?PAM_AUTH_ERR:PAM_SUCCESS, retval);
+#endif
+ return sense?PAM_SUCCESS:PAM_AUTH_ERR;
+ }
+ else {
+#ifdef DEBUG
+ syslog(LOG_INFO,"Returning %d, retval = %d",
+ sense?PAM_SUCCESS:PAM_AUTH_ERR, retval);
+#endif
+ return sense?PAM_AUTH_ERR:PAM_SUCCESS;
+ }
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_listfile_modstruct = {
+ "pam_listfile",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
+
diff --git a/contrib/libpam/modules/pam_mail/Makefile b/contrib/libpam/modules/pam_mail/Makefile
new file mode 100644
index 000000000000..5a402ea4015b
--- /dev/null
+++ b/contrib/libpam/modules/pam_mail/Makefile
@@ -0,0 +1,107 @@
+#
+# $Id: Makefile,v 1.3 1997/04/05 06:37:45 morgan Exp $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.3 1997/04/05 06:37:45 morgan
+# fakeroot
+#
+# Revision 1.2 1997/02/15 16:07:22 morgan
+# optional libpwdb compilation
+#
+# Revision 1.1 1997/01/04 20:32:52 morgan
+# Initial revision
+#
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/12/8
+#
+
+TITLE=pam_mail
+
+ifndef STATIC
+ifeq ($(HAVE_PWDBLIB),yes)
+CFLAGS += -DWANT_PWDB
+EXTRALIB = -lpwdb
+endif
+endif
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) $(EXTRALIB)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS) $(EXTRALIB)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_mail/pam_mail.c b/contrib/libpam/modules/pam_mail/pam_mail.c
new file mode 100644
index 000000000000..15160f3d5208
--- /dev/null
+++ b/contrib/libpam/modules/pam_mail/pam_mail.c
@@ -0,0 +1,401 @@
+/* pam_mail module */
+
+/*
+ * $Id: pam_mail.c,v 1.2 1997/02/15 16:06:14 morgan Exp morgan $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ * $HOME additions by David Kinchlea <kinch@kinch.ark.com> 1997/1/7
+ *
+ * $Log: pam_mail.c,v $
+ * Revision 1.2 1997/02/15 16:06:14 morgan
+ * session -> setcred, also added "~"=$HOME
+ *
+ * Revision 1.1 1997/01/04 20:33:02 morgan
+ * Initial revision
+ */
+
+#define DEFAULT_MAIL_DIRECTORY "/var/spool/mail"
+#define MAIL_FILE_FORMAT "%s/%s"
+#define MAIL_ENV_NAME "MAIL"
+#define MAIL_ENV_FORMAT MAIL_ENV_NAME "=%s"
+#define YOUR_MAIL_FORMAT "You have %s mail in %s"
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <ctype.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef WANT_PWDB
+#include <pwdb/pwdb_public.h>
+#endif
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* some syslogging */
+
+static void _log_err(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-mail", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 01
+#define PAM_NO_LOGIN 02
+#define PAM_LOGOUT_TOO 04
+#define PAM_NEW_MAIL_DIR 010
+#define PAM_MAIL_SILENT 020
+#define PAM_NO_ENV 040
+#define PAM_HOME_MAIL 0100
+#define PAM_EMPTY_TOO 0200
+
+static int _pam_parse(int flags, int argc, const char **argv, char **maildir)
+{
+ int ctrl=0;
+
+ if (flags & PAM_SILENT) {
+ ctrl |= PAM_MAIL_SILENT;
+ }
+
+ /* step through arguments */
+ for (; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strncmp(*argv,"dir=",4)) {
+ *maildir = x_strdup(4+*argv);
+ if (*maildir != NULL) {
+ D(("new mail directory: %s", *maildir));
+ ctrl |= PAM_NEW_MAIL_DIR;
+ } else {
+ _log_err(LOG_CRIT,
+ "failed to duplicate mail directory - ignored");
+ }
+ } else if (!strcmp(*argv,"close")) {
+ ctrl |= PAM_LOGOUT_TOO;
+ } else if (!strcmp(*argv,"nopen")) {
+ ctrl |= PAM_NO_LOGIN;
+ } else if (!strcmp(*argv,"noenv")) {
+ ctrl |= PAM_NO_ENV;
+ } else if (!strcmp(*argv,"empty")) {
+ ctrl |= PAM_EMPTY_TOO;
+ } else {
+ _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+/* a front end for conversations */
+
+static int converse(pam_handle_t *pamh, int ctrl, int nargs
+ , struct pam_message **message
+ , struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ D(("begin to converse"));
+
+ retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
+ if ( retval == PAM_SUCCESS ) {
+
+ retval = conv->conv(nargs, ( const struct pam_message ** ) message
+ , response, conv->appdata_ptr);
+
+ D(("returned from application's conversation function"));
+
+ if (retval != PAM_SUCCESS && (PAM_DEBUG_ARG & ctrl) ) {
+ _log_err(LOG_DEBUG, "conversation failure [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ } else {
+ _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ D(("ready to return from module conversation"));
+
+ return retval; /* propagate error status */
+}
+
+static int get_folder(pam_handle_t *pamh, int ctrl
+ , char **path_mail, char **folder_p)
+{
+ int retval;
+ const char *user, *path;
+ char *folder;
+ const struct passwd *pwd=NULL;
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS || user == NULL) {
+ _log_err(LOG_ERR, "no user specified");
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (ctrl & PAM_NEW_MAIL_DIR) {
+ path = *path_mail;
+ if (*path == '~') { /* support for $HOME delivery */
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ _log_err(LOG_ERR, "user [%s] unknown", user);
+ _pam_overwrite(*path_mail);
+ _pam_drop(*path_mail);
+ return PAM_USER_UNKNOWN;
+ }
+ /*
+ * "~/xxx" and "~xxx" are treated as same
+ */
+ if (!*++path || (*path == '/' && !*++path)) {
+ _log_err(LOG_ALERT, "badly formed mail path [%s]", *path_mail);
+ _pam_overwrite(*path_mail);
+ _pam_drop(*path_mail);
+ return PAM_ABORT;
+ }
+ ctrl |= PAM_HOME_MAIL;
+ }
+ } else {
+ path = DEFAULT_MAIL_DIRECTORY;
+ }
+
+ /* put folder together */
+
+ if (ctrl & PAM_HOME_MAIL) {
+ folder = malloc(sizeof(MAIL_FILE_FORMAT)
+ +strlen(pwd->pw_dir)+strlen(path));
+ } else {
+ folder = malloc(sizeof(MAIL_FILE_FORMAT)+strlen(path)+strlen(user));
+ }
+
+ if (folder != NULL) {
+ if (ctrl & PAM_HOME_MAIL) {
+ sprintf(folder, MAIL_FILE_FORMAT, pwd->pw_dir, path);
+ } else {
+ sprintf(folder, MAIL_FILE_FORMAT, path, user);
+ }
+ D(("folder =[%s]", folder));
+ }
+
+ /* tidy up */
+
+ _pam_overwrite(*path_mail);
+ _pam_drop(*path_mail);
+ user = NULL;
+
+ if (folder == NULL) {
+ _log_err(LOG_CRIT, "out of memory for mail folder");
+ return PAM_BUF_ERR;
+ }
+
+ *folder_p = folder;
+ folder = NULL;
+
+ return PAM_SUCCESS;
+}
+
+static const char *get_mail_status(int ctrl, const char *folder)
+{
+ const char *type;
+ struct stat mail_st;
+
+ if (stat(folder, &mail_st) == 0 && mail_st.st_size > 0) {
+ type = (mail_st.st_atime < mail_st.st_mtime) ? "new":"old" ;
+ } else if (ctrl & PAM_EMPTY_TOO) {
+ type = "no";
+ } else {
+ type = NULL;
+ }
+
+ memset(&mail_st, 0, sizeof(mail_st));
+ D(("user has %s mail in %s folder", type, folder));
+ return type;
+}
+
+static int report_mail(pam_handle_t *pamh, int ctrl
+ , const char *type, const char *folder)
+{
+ int retval;
+
+ if (!(ctrl & PAM_MAIL_SILENT)) {
+ char *remark;
+
+ remark = malloc(sizeof(YOUR_MAIL_FORMAT)+strlen(type)+strlen(folder));
+ if (remark == NULL) {
+ retval = PAM_BUF_ERR;
+ } else {
+ struct pam_message msg[1], *mesg[1];
+ struct pam_response *resp=NULL;
+
+ sprintf(remark, YOUR_MAIL_FORMAT, type, folder);
+
+ mesg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = remark;
+
+ retval = converse(pamh, ctrl, 1, mesg, &resp);
+
+ _pam_overwrite(remark);
+ _pam_drop(remark);
+ if (resp)
+ _pam_drop_reply(resp, 1);
+ }
+ } else {
+ D(("keeping quiet"));
+ retval = PAM_SUCCESS;
+ }
+
+ D(("returning %s", pam_strerror(pamh, retval)));
+ return retval;
+}
+
+/* --- authentication management functions (only) --- */
+
+/*
+ * Cannot use mail to authenticate yourself
+ */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_IGNORE;
+}
+
+/*
+ * MAIL is a "credential"
+ */
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc
+ , const char **argv)
+{
+ int retval, ctrl;
+ char *path_mail=NULL, *folder;
+ const char *type;
+
+ /*
+ * this module (un)sets the MAIL environment variable, and checks if
+ * the user has any new mail.
+ */
+
+ ctrl = _pam_parse(flags, argc, argv, &path_mail);
+
+ /* Do we have anything to do? */
+
+ if (!(flags & (PAM_ESTABLISH_CRED|PAM_DELETE_CRED))) {
+ return PAM_SUCCESS;
+ }
+
+ /* which folder? */
+
+ retval = get_folder(pamh, ctrl, &path_mail, &folder);
+ if (retval != PAM_SUCCESS) {
+ D(("failed to find folder"));
+ return retval;
+ }
+
+ /* set the MAIL variable? */
+
+ if (!(ctrl & PAM_NO_ENV) && (flags & PAM_ESTABLISH_CRED)) {
+ char *tmp;
+
+ tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT));
+ if (tmp != NULL) {
+ sprintf(tmp, MAIL_ENV_FORMAT, folder);
+ D(("setting env: %s", tmp));
+ retval = pam_putenv(pamh, tmp);
+ _pam_overwrite(tmp);
+ _pam_drop(tmp);
+ if (retval != PAM_SUCCESS) {
+ _pam_overwrite(folder);
+ _pam_drop(folder);
+ _log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable");
+ return retval;
+ }
+ } else {
+ _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable");
+ _pam_overwrite(folder);
+ _pam_drop(folder);
+ return retval;
+ }
+ } else {
+ D(("not setting " MAIL_ENV_NAME " variable"));
+ }
+
+ /*
+ * OK. we've got the mail folder... what about its status?
+ */
+
+ if (((flags & PAM_ESTABLISH_CRED) && !(ctrl & PAM_NO_LOGIN))
+ || ((flags & PAM_DELETE_CRED) && (ctrl & PAM_LOGOUT_TOO))) {
+ type = get_mail_status(ctrl, folder);
+ if (type != NULL) {
+ retval = report_mail(pamh, ctrl, type, folder);
+ type = NULL;
+ }
+ }
+
+ /*
+ * Delete environment variable?
+ */
+
+ if (flags & PAM_DELETE_CRED) {
+ (void) pam_putenv(pamh, MAIL_ENV_NAME);
+ }
+
+ _pam_overwrite(folder); /* clean up */
+ _pam_drop(folder);
+
+ /* indicate success or failure */
+
+ return retval;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_mail_modstruct = {
+ "pam_mail",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_nologin/Makefile b/contrib/libpam/modules/pam_nologin/Makefile
new file mode 100644
index 000000000000..0769bb993120
--- /dev/null
+++ b/contrib/libpam/modules/pam_nologin/Makefile
@@ -0,0 +1,86 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# Michael K. Johnson <johnsonm@redhat.com> 1996/10/24
+#
+
+TITLE=pam_nologin
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ mkdir -p ./dynamic
+endif
+ifdef STATIC
+ mkdir -p ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ mkdir -p $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ install -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_nologin/README b/contrib/libpam/modules/pam_nologin/README
new file mode 100644
index 000000000000..ab7ccd7d9803
--- /dev/null
+++ b/contrib/libpam/modules/pam_nologin/README
@@ -0,0 +1,12 @@
+# $Id: README,v 1.1 1996/10/25 03:19:36 morgan Exp $
+#
+
+This module always lets root in; it lets other users in only if the file
+/etc/nologin doesn't exist. In any case, if /etc/nologin exists, it's
+contents are displayed to the user.
+
+module services provided:
+
+ auth _authentication and _setcred (blank)
+
+Michael K. Johnson
diff --git a/contrib/libpam/modules/pam_nologin/pam_nologin.c b/contrib/libpam/modules/pam_nologin/pam_nologin.c
new file mode 100644
index 000000000000..2788dcf8f39a
--- /dev/null
+++ b/contrib/libpam/modules/pam_nologin/pam_nologin.c
@@ -0,0 +1,124 @@
+/* pam_nologin module */
+
+/*
+ * $Id: pam_nologin.c,v 1.4 1997/04/05 06:36:47 morgan Exp morgan $
+ *
+ * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24
+ *
+ * $Log: pam_nologin.c,v $
+ * Revision 1.4 1997/04/05 06:36:47 morgan
+ * display message when the user is unknown
+ *
+ * Revision 1.3 1996/12/01 03:00:54 morgan
+ * added prototype to conversation, gave static structure name of module
+ *
+ * Revision 1.2 1996/11/10 21:02:31 morgan
+ * compile against .53
+ *
+ * Revision 1.1 1996/10/25 03:19:36 morgan
+ * Initial revision
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+
+#include <security/_pam_macros.h>
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ int retval = PAM_SUCCESS;
+ int fd;
+ const char *username;
+ char *mtmp=NULL;
+ struct passwd *user_pwd;
+ struct pam_conv *conversation;
+ struct pam_message message;
+ struct pam_message *pmessage = &message;
+ struct pam_response *resp = NULL;
+ struct stat st;
+
+ if ((fd = open("/etc/nologin", O_RDONLY, 0)) >= 0) {
+ /* root can still log in; lusers cannot */
+ if ((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS)
+ || !username) {
+ return PAM_SERVICE_ERR;
+ }
+ user_pwd = getpwnam(username);
+ if (user_pwd && user_pwd->pw_uid == 0) {
+ message.msg_style = PAM_TEXT_INFO;
+ } else {
+ if (!user_pwd) {
+ retval = PAM_USER_UNKNOWN;
+ } else {
+ retval = PAM_AUTH_ERR;
+ }
+ message.msg_style = PAM_ERROR_MSG;
+ }
+
+ /* fill in message buffer with contents of /etc/nologin */
+ if (fstat(fd, &st) < 0) /* give up trying to display message */
+ return retval;
+ message.msg = mtmp = malloc(st.st_size+1);
+ /* if malloc failed... */
+ if (!message.msg) return retval;
+ read(fd, mtmp, st.st_size);
+ mtmp[st.st_size] = '\000';
+
+ /* Use conversation function to give user contents of /etc/nologin */
+ pam_get_item(pamh, PAM_CONV, (const void **)&conversation);
+ conversation->conv(1, (const struct pam_message **)&pmessage,
+ &resp, conversation->appdata_ptr);
+ free(mtmp);
+ if (resp)
+ _pam_drop_reply(resp, 1);
+ }
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_nologin_modstruct = {
+ "pam_nologin",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_permit/Makefile b/contrib/libpam/modules/pam_permit/Makefile
new file mode 100644
index 000000000000..823b62472e35
--- /dev/null
+++ b/contrib/libpam/modules/pam_permit/Makefile
@@ -0,0 +1,126 @@
+#
+# $Id: Makefile,v 1.8 1997/04/05 06:33:25 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.8 1997/04/05 06:33:25 morgan
+# fakeroot
+#
+# Revision 1.7 1997/02/15 19:02:27 morgan
+# updated email address
+#
+# Revision 1.6 1996/11/10 20:14:34 morgan
+# cross platform support
+#
+# Revision 1.5 1996/09/05 06:32:45 morgan
+# ld --> gcc
+#
+# Revision 1.4 1996/05/26 15:49:25 morgan
+# make dynamic and static dirs
+#
+# Revision 1.3 1996/05/26 04:04:26 morgan
+# automated static support
+#
+# Revision 1.2 1996/03/16 17:56:38 morgan
+# tidied up
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+#
+
+# Convenient defaults for compiling independently of the full source
+# tree.
+ifndef FULL_LINUX_PAM_SOURCE_TREE
+export DYNAMIC=-DPAM_DYNAMIC
+export CC=gcc
+export CFLAGS=-O2 -Dlinux -DLINUX_PAM \
+ -ansi -D_POSIX_SOURCE -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align -Wtraditional \
+ -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline \
+ -Wshadow -pedantic -fPIC
+export MKDIR=mkdir -p
+export LD_D=gcc -shared -Xlinker -x
+endif
+
+#
+#
+
+TITLE=pam_permit
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(TARGET_ARCH) -c $< -o $@
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+endif
+
+ifdef DYNAMIC
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+endif
+
+ifdef STATIC
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_permit/README b/contrib/libpam/modules/pam_permit/README
new file mode 100644
index 000000000000..da179a34829c
--- /dev/null
+++ b/contrib/libpam/modules/pam_permit/README
@@ -0,0 +1,4 @@
+# $Id: README,v 1.1 1996/03/16 18:12:51 morgan Exp $
+#
+
+this module always returns PAM_SUCCESS, it ignores all options.
diff --git a/contrib/libpam/modules/pam_permit/pam_permit.c b/contrib/libpam/modules/pam_permit/pam_permit.c
new file mode 100644
index 000000000000..1bdd5644a63b
--- /dev/null
+++ b/contrib/libpam/modules/pam_permit/pam_permit.c
@@ -0,0 +1,122 @@
+/* pam_permit module */
+
+/*
+ * $Id: pam_permit.c,v 1.5 1997/02/15 19:03:15 morgan Exp $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ *
+ * $Log: pam_permit.c,v $
+ * Revision 1.5 1997/02/15 19:03:15 morgan
+ * fixed email address
+ *
+ * Revision 1.4 1997/02/15 16:03:10 morgan
+ * force a name for user
+ *
+ * Revision 1.3 1996/06/02 08:10:14 morgan
+ * updated for new static protocol
+ *
+ */
+
+#define DEFAULT_USER "nobody"
+
+#include <stdio.h>
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* --- authentication management functions --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int retval;
+ const char *user=NULL;
+
+ /*
+ * authentication requires we know who the user wants to be
+ */
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS) {
+ D(("get user returned error: %s", pam_strerror(pamh,retval)));
+ return retval;
+ }
+ if (user == NULL || *user == '\0') {
+ D(("username not known"));
+ pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER);
+ }
+ user = NULL; /* clean up */
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+/* --- account management functions --- */
+
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+/* --- password management --- */
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+/* --- session management --- */
+
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+/* end of module definition */
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_permit_modstruct = {
+ "pam_permit",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok
+};
+
+#endif
diff --git a/contrib/libpam/modules/pam_pwdb/BUGS b/contrib/libpam/modules/pam_pwdb/BUGS
new file mode 100644
index 000000000000..397f367b5372
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/BUGS
@@ -0,0 +1,8 @@
+$Id: BUGS,v 1.2 1996/09/05 06:36:16 morgan Exp $
+
+$Log: BUGS,v $
+Revision 1.2 1996/09/05 06:36:16 morgan
+revised for .52 to be released
+
+
+As of Linux-PAM-0.52 this is new. No known bugs yet.
diff --git a/contrib/libpam/modules/pam_pwdb/CHANGELOG b/contrib/libpam/modules/pam_pwdb/CHANGELOG
new file mode 100644
index 000000000000..0cb21879120b
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/CHANGELOG
@@ -0,0 +1,10 @@
+$Header: /home/morgan/pam/Linux-PAM-0.52/modules/pam_unix/RCS/CHANGELOG,v 1.1 1996/08/29 13:23:29 morgan Exp $
+
+Tue Apr 23 12:28:09 EDT 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu)
+
+ * PAM_DISALLOW_NULL_AUTHTOK implemented in the authentication module
+ * pam_sm_open_session() and pam_sm_close_session() implemented
+ A new "trace" flag added to flags of /etc/pam.conf. Using this
+ flag system administrator is able to make pam_unix module provide
+ very extensive audit trail sent so syslog with LOG_AUTHPRIV level.
+ * pam_sm_set_cred() is done
diff --git a/contrib/libpam/modules/pam_pwdb/Makefile b/contrib/libpam/modules/pam_pwdb/Makefile
new file mode 100644
index 000000000000..7428bb439040
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/Makefile
@@ -0,0 +1,155 @@
+# $Id: Makefile,v 1.7 1997/04/05 06:28:50 morgan Exp morgan $
+#
+# This Makefile controls a build process of the pam_unix module
+# for Linux-PAM. You should not modify this Makefile.
+#
+# rewritten to compile new module Andrew Morgan
+# <morgan@parc.power.net> 1996/11/6
+#
+
+#
+# Note, the STATIC module is commented out because it doesn't work.
+# please fix!
+#
+
+ifndef FULL_LINUX_PAM_SOURCE_TREE
+export DYNAMIC=-DPAM_DYNAMIC
+export CC=gcc
+export CFLAGS=-O2 -Dlinux -DLINUX_PAM \
+ -ansi -D_POSIX_SOURCE -Wall -Wwrite-strings \
+ -Wpointer-arith -Wcast-qual -Wcast-align -Wtraditional \
+ -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline \
+ -Wshadow -pedantic -fPIC
+export MKDIR=mkdir -p
+export LD_D=gcc -shared -Xlinker -x
+export HAVE_PWDBLIB=yes
+endif
+
+ifeq ($(HAVE_PWDBLIB),yes)
+
+TITLE=pam_pwdb
+CHKPWD=pwdb_chkpwd
+
+# compilation flags
+EXTRAS=
+# extra object files
+PLUS=
+# extra files that may be needed to be created
+CREATE=
+
+# NOTE: this module links dynamically to the libpwdb library.
+EXTRALS += -lpwdb
+EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\"
+
+########################### don't edit below ##########################
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+#LIBOBJS = $(addprefix static/,$(LIBOBJ))
+LIBDEPS = pam_unix_acct.-c pam_unix_auth.-c pam_unix_passwd.-c \
+ pam_unix_sess.-c pam_unix_pwupd.-c support.-c bigcrypt.-c
+
+PLUS += md5.o md5_crypt.o
+CFLAGS += $(EXTRAS)
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+#ifdef STATIC
+#LIBSTATIC = lib$(TITLE).o
+#endif
+
+all: info dirs $(PLUS) $(LIBSHARED) $(LIBSTATIC) register $(CHKPWD)
+
+dynamic/$(LIBOBJ) : $(LIBSRC) $(LIBDEPS)
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+#static/$(LIBOBJ) : $(LIBSRC) $(LIBDEPS)
+# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+info:
+ @echo
+ @echo "*** Building PAM_pwdb module..."
+ @echo
+
+$(CHKPWD): pwdb_chkpwd.o md5.o md5_crypt.o
+ $(CC) -o $(CHKPWD) $^ -lpwdb
+
+pwdb_chkpwd.o: pwdb_chkpwd.c pam_unix_md.-c bigcrypt.-c
+
+dirs:
+ifdef DYNAMIC
+ @$(MKDIR) ./dynamic
+endif
+#ifdef STATIC
+# @$(MKDIR) ./static
+#endif
+
+register:
+#ifdef STATIC
+# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+#endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(EXTRALS)
+endif
+
+#ifdef STATIC
+#$(LIBOBJS): $(LIBSRC)
+#
+#$(LIBSTATIC): $(LIBOBJS)
+# $(LD) -r -o $@ $(LIBOBJS) $(PLUS) $(EXTRALS)
+#endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SUPLEMENTED)
+ $(INSTALL) -m 4555 -o root -g root $(CHKPWD) $(FAKEROOT)$(SUPLEMENTED)
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+ rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD)
+
+clean:
+ rm -f $(CHKPWD) $(LIBOBJD) $(LIBOBJS) $(MOREDELS) core *~ *.o *.so
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+else
+
+include ../dont_makefile
+
+endif
+
+#####################################################################
+# $Log: Makefile,v $
+# Revision 1.7 1997/04/05 06:28:50 morgan
+# fakeroot
+#
+# Revision 1.6 1997/02/15 17:25:32 morgan
+# update for .56 . extra commands for new helper binary
+#
+# Revision 1.5 1997/01/04 20:39:08 morgan
+# conditional on having libpwdb
+#
+# Revision 1.4 1996/12/01 03:02:03 morgan
+# changed banner, removed linking libraries
+#
+# Revision 1.3 1996/11/10 20:14:42 morgan
+# cross platform support
+#
+# Revision 1.2 1996/09/05 06:36:49 morgan
+# options added and use of LD altered
+#
+# Revision 1.1 1996/08/29 13:23:29 morgan
+# Initial revision
+#
+#
diff --git a/contrib/libpam/modules/pam_pwdb/README b/contrib/libpam/modules/pam_pwdb/README
new file mode 100644
index 000000000000..351a706008e9
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/README
@@ -0,0 +1,41 @@
+This is the pam_unix module. It has been significantly rewritten since
+.51 was released (due mostly to the efforts of Cristian Gafton), and
+now takes more options and correctly updates vanilla UNIX/shadow/md5
+passwords.
+
+[Please read the source and make a note of all the warnings there, as
+the license suggests -- use at your own risk.]
+
+So far as I am concerned this module is now pretty stable. If you find
+any bugs, PLEASE tell me! <morgan@parc.power.net>
+
+Options recognized by this module are as follows:
+
+ debug - log more debugging info
+ audit - a little more extreme than debug
+ use_first_pass - don't prompt the user for passwords
+ take them from PAM_ items instead
+ try_first_pass - don't prompt the user for the passwords
+ unless PAM_(OLD)AUTHTOK is unset
+ use_authtok - like try_first_pass, but *fail* if the new
+ PAM_AUTHTOK has not been previously set.
+ (intended for stacking password modules only)
+ not_set_pass - don't set the PAM_ items with the passwords
+ used by this module.
+ shadow - try to maintian a shadow based system.
+ unix - when changing passwords, they are placed
+ in the /etc/passwd file
+ md5 - when a user changes their password next,
+ encrypt it with the md5 algorithm.
+ bigcrypt - when a user changes their password next,
+ excrypt it with the DEC C2-algorithm(0).
+ nodelay - used to prevent failed authentication
+ resulting in a delay of about 1 second.
+
+There is some support for building a shadow file on-the-fly from an
+/etc/passwd file. This is VERY alpha. If you want to play with it you
+should read the source to find the appropriate #define that you will
+need.
+
+---------------------
+Andrew Morgan <morgan@parc.power.net>
diff --git a/contrib/libpam/modules/pam_pwdb/TODO b/contrib/libpam/modules/pam_pwdb/TODO
new file mode 100644
index 000000000000..23eb4c163d08
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/TODO
@@ -0,0 +1,34 @@
+$Id: TODO,v 1.3 1996/11/10 21:03:21 morgan Exp $
+
+ * get NIS working
+ * .. including "nonis" argument
+ * add helper binary
+
+Wed Sep 4 23:40:09 PDT 1996 Andrew G. Morgan
+
+ * verify that it works for everyone
+ * look more seriously at the issue of generating a shadow
+ system on the fly
+ * add some more password flavors
+
+Thu Aug 29 06:26:42 PDT 1996 Andrew G. Morgan
+
+ * check that complete rewrite works! ;^)
+ * complete shadow support to the password changing code.
+ Also some code needed here for session managment?
+ (both pam.conf argument to turn it on/off, and some
+ conditional compilation.)
+ * md5 passwords...
+ * make the exclusive nature of the arguments work. That is,
+ only recognize the flags when appropriate.
+
+Wed May 8 19:08:49 EDT 1996 Alexander O. Yuriev
+
+ * support.c should go.
+
+Tue Apr 23 21:43:55 EDT 1996 Alexander O. Yuriev
+
+ * pam_sm_chauth_tok() should be written
+ * QUICK FIX: pam_sm_setcred() probably returns incorrect error code
+
+
diff --git a/contrib/libpam/modules/pam_pwdb/bigcrypt.-c b/contrib/libpam/modules/pam_pwdb/bigcrypt.-c
new file mode 100644
index 000000000000..321f24911296
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/bigcrypt.-c
@@ -0,0 +1,114 @@
+/*
+ * This function implements the "bigcrypt" algorithm specifically for
+ * Linux-PAM.
+ *
+ * This algorithm is algorithm 0 (default) shipped with the C2 secure
+ * implementation of Digital UNIX.
+ *
+ * Disclaimer: This work is not based on the source code to Digital
+ * UNIX, nor am I connected to Digital Equipment Corp, in any way
+ * other than as a customer. This code is based on published
+ * interfaces and reasonable guesswork.
+ *
+ * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8
+ * characters or less. Each block is encrypted using the standard UNIX
+ * libc crypt function. The result of the encryption for one block
+ * provides the salt for the suceeding block.
+ *
+ * Restrictions: The buffer used to hold the encrypted result is
+ * statically allocated. (see MAX_PASS_LEN below). This is necessary,
+ * as the returned pointer points to "static data that are overwritten
+ * by each call", (XPG3: XSI System Interface + Headers pg 109), and
+ * this is a drop in replacement for crypt();
+ *
+ * Andy Phillips <atp@mssl.ucl.ac.uk>
+ */
+
+/*
+ * Max cleartext password length in segments of 8 characters this
+ * function can deal with (16 segments of 8 chars= max 128 character
+ * password).
+ */
+
+#define MAX_PASS_LEN 16
+#define SEGMENT_SIZE 8
+#define SALT_SIZE 2
+#define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE)
+#define ESEGMENT_SIZE 11
+#define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1)
+
+static char *bigcrypt(const char *key, const char *salt)
+{
+ static char dec_c2_cryptbuf[CBUF_SIZE]; /* static storage area */
+
+ unsigned long int keylen,n_seg,j;
+ char *cipher_ptr,*plaintext_ptr,*tmp_ptr,*salt_ptr;
+ char keybuf[KEYBUF_SIZE+1];
+
+ D(("called with key='%s', salt='%s'.", key, salt));
+
+ /* reset arrays */
+ memset(keybuf, 0, KEYBUF_SIZE+1);
+ memset(dec_c2_cryptbuf, 0, CBUF_SIZE);
+
+ /* fill KEYBUF_SIZE with key */
+ strncpy(keybuf, key, KEYBUF_SIZE);
+
+ /* deal with case that we are doing a password check for a
+ conventially encrypted password: the salt will be
+ SALT_SIZE+ESEGMENT_SIZE long. */
+ if (strlen(salt) == (SALT_SIZE+ESEGMENT_SIZE))
+ keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */
+
+ keylen = strlen(keybuf);
+
+ if (!keylen) {
+ n_seg = 1;
+ } else {
+ /* work out how many segments */
+ n_seg = 1 + ((keylen-1)/SEGMENT_SIZE);
+ }
+
+ if (n_seg > MAX_PASS_LEN)
+ n_seg = MAX_PASS_LEN; /* truncate at max length */
+
+ /* set up some pointers */
+ cipher_ptr = dec_c2_cryptbuf;
+ plaintext_ptr = keybuf;
+
+ /* do the first block with supplied salt */
+ tmp_ptr = crypt(plaintext_ptr,salt); /* libc crypt() */
+
+ /* and place in the static area */
+ strncpy(cipher_ptr, tmp_ptr, 13);
+ cipher_ptr += ESEGMENT_SIZE + SALT_SIZE;
+ plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */
+
+ /* change the salt (1st 2 chars of previous block) - this was found
+ by dowsing */
+
+ salt_ptr = cipher_ptr - ESEGMENT_SIZE;
+
+ /* so far this is identical to "return crypt(key, salt);", if
+ there is more than one block encrypt them... */
+
+ if (n_seg > 1) {
+ for (j=2; j <= n_seg; j++) {
+
+ tmp_ptr = crypt(plaintext_ptr, salt_ptr);
+
+ /* skip the salt for seg!=0 */
+ strncpy(cipher_ptr, (tmp_ptr+SALT_SIZE), ESEGMENT_SIZE);
+
+ cipher_ptr += ESEGMENT_SIZE;
+ plaintext_ptr += SEGMENT_SIZE;
+ salt_ptr = cipher_ptr - ESEGMENT_SIZE;
+ }
+ }
+
+ D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf));
+
+ /* this is the <NUL> terminated encrypted password */
+
+ return dec_c2_cryptbuf;
+}
diff --git a/contrib/libpam/modules/pam_pwdb/md5.c b/contrib/libpam/modules/pam_pwdb/md5.c
new file mode 100644
index 000000000000..fdfbdd88f389
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/md5.c
@@ -0,0 +1,259 @@
+/* $Id: md5.c,v 1.1 1996/09/05 06:43:31 morgan Exp $
+ *
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * $Log: md5.c,v $
+ * Revision 1.1 1996/09/05 06:43:31 morgan
+ * Initial revision
+ *
+ */
+
+#include <string.h>
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301U;
+ ctx->buf[1] = 0xefcdab89U;
+ ctx->buf[2] = 0x98badcfeU;
+ ctx->buf[3] = 0x10325476U;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned const char *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
diff --git a/contrib/libpam/modules/pam_pwdb/md5.h b/contrib/libpam/modules/pam_pwdb/md5.h
new file mode 100644
index 000000000000..4949ade27e1f
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/md5.h
@@ -0,0 +1,30 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *);
+void MD5Update(struct MD5Context *, unsigned const char *, unsigned);
+void MD5Final(unsigned char digest[16], struct MD5Context *);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+int i64c(int i);
+
+char *crypt_md5(const char *pw, const char *salt);
+
+/*
+* This is needed to make RSAREF happy on some MS-DOS compilers.
+*/
+
+typedef struct MD5Context MD5_CTX;
+
+#endif /* MD5_H */
diff --git a/contrib/libpam/modules/pam_pwdb/md5_crypt.c b/contrib/libpam/modules/pam_pwdb/md5_crypt.c
new file mode 100644
index 000000000000..88be13b7f001
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/md5_crypt.c
@@ -0,0 +1,164 @@
+/* $Id: md5_crypt.c,v 1.1 1996/09/05 06:43:31 morgan Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp
+ *
+ * $Log: md5_crypt.c,v $
+ * Revision 1.1 1996/09/05 06:43:31 morgan
+ * Initial revision
+ *
+ */
+
+#include <string.h>
+#include "md5.h"
+
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void
+to64(char *s, unsigned long v, int n)
+{
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+/*
+ * i64c - convert an integer to a radix 64 character
+ */
+int i64c(int i)
+{
+ if (i < 0)
+ return ('.');
+ else if (i > 63)
+ return ('z');
+ if (i == 0)
+ return ('.');
+ if (i == 1)
+ return ('/');
+ if (i >= 2 && i <= 11)
+ return ('0' - 2 + i);
+ if (i >= 12 && i <= 37)
+ return ('A' - 12 + i);
+ if (i >= 38 && i <= 63)
+ return ('a' - 38 + i);
+ return ('\0');
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char * crypt_md5(const char *pw, const char *salt)
+{
+ const char *magic = "$1$";
+ /* This string is magic for this algorithm. Having
+ * it this way, we can get get better later on */
+ static char passwd[120], *p;
+ static const char *sp,*ep;
+ unsigned char final[16];
+ int sl,pl,i,j;
+ MD5_CTX ctx,ctx1;
+ unsigned long l;
+
+ /* Refine the Salt first */
+ sp = salt;
+
+ /* If it starts with the magic string, then skip that */
+ if(!strncmp(sp,magic,strlen(magic)))
+ sp += strlen(magic);
+
+ /* It stops at the first '$', max 8 chars */
+ for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+ continue;
+
+ /* get the length of the true salt */
+ sl = ep - sp;
+
+ MD5Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ MD5Update(&ctx,(unsigned const char *)pw,strlen(pw));
+
+ /* Then our magic string */
+ MD5Update(&ctx,(unsigned const char *)magic,strlen(magic));
+
+ /* Then the raw salt */
+ MD5Update(&ctx,(unsigned const char *)sp,sl);
+
+ /* Then just as many characters of the MD5(pw,salt,pw) */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw));
+ MD5Update(&ctx1,(unsigned const char *)sp,sl);
+ MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw));
+ MD5Final(final,&ctx1);
+ for(pl = strlen(pw); pl > 0; pl -= 16)
+ MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final,0,sizeof final);
+
+ /* Then something really weird... */
+ for (j=0,i = strlen(pw); i ; i >>= 1)
+ if(i&1)
+ MD5Update(&ctx, (unsigned const char *)final+j, 1);
+ else
+ MD5Update(&ctx, (unsigned const char *)pw+j, 1);
+
+ /* Now make the output string */
+ strcpy(passwd,magic);
+ strncat(passwd,sp,sl);
+ strcat(passwd,"$");
+
+ MD5Final(final,&ctx);
+
+ /*
+ * and now, just to make sure things don't run too fast
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for(i=0;i<1000;i++) {
+ MD5Init(&ctx1);
+ if(i & 1)
+ MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw));
+ else
+ MD5Update(&ctx1,(unsigned const char *)final,16);
+
+ if(i % 3)
+ MD5Update(&ctx1,(unsigned const char *)sp,sl);
+
+ if(i % 7)
+ MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw));
+
+ if(i & 1)
+ MD5Update(&ctx1,(unsigned const char *)final,16);
+ else
+ MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw));
+ MD5Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
+ l = final[11] ; to64(p,l,2); p += 2;
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final,0,sizeof final);
+
+ return passwd;
+}
+
diff --git a/contrib/libpam/modules/pam_pwdb/pam_pwdb.c b/contrib/libpam/modules/pam_pwdb/pam_pwdb.c
new file mode 100644
index 000000000000..a612f74037b4
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_pwdb.c
@@ -0,0 +1,257 @@
+/*
+ * $Id: pam_pwdb.c,v 1.3 1997/01/04 20:38:33 morgan Exp morgan $
+ *
+ * This is the single file that will be compiled for pam_unix.
+ * it includes each of the modules that have beed defined in the .-c
+ * files in this directory.
+ *
+ * It is a little ugly to do it this way, but it is a simple way of
+ * defining static functions only once, and yet keeping the separate
+ * files modular. If you can think of something better, please email
+ * Andrew Morgan <morgan@linux.kernel.org>
+ *
+ * See the end of this file for Copyright information.
+ */
+
+/*
+ * $Log: pam_pwdb.c,v $
+ * Revision 1.3 1997/01/04 20:38:33 morgan
+ * this is not the unix module!
+ *
+ * Revision 1.2 1996/12/01 03:03:43 morgan
+ * debugging code uses _pam_malloc
+ *
+ * Revision 1.1 1996/11/10 21:21:24 morgan
+ * Initial revision
+ *
+ * Revision 1.3 1996/09/05 06:44:33 morgan
+ * more debugging, fixed static structure name
+ *
+ * Revision 1.2 1996/09/01 01:05:12 morgan
+ * Cristian Gafton's patches.
+ *
+ * Revision 1.1 1996/08/29 13:22:19 morgan
+ * Initial revision
+ *
+ */
+
+static const char rcsid[] =
+"$Id: pam_pwdb.c,v 1.3 1997/01/04 20:38:33 morgan Exp morgan $\n"
+" - PWDB Pluggable Authentication module. <morgan@linux.kernel.org>"
+;
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h> /* for time() */
+#include <fcntl.h>
+#include <ctype.h>
+
+#define _SVID_SOURCE
+#define __USE_BSD
+#define _BSD_COMPAT
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <pwdb/pwdb_public.h>
+
+/* indicate the following groups are defined */
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/_pam_macros.h>
+#include <security/pam_modules.h>
+
+#ifndef LINUX_PAM
+#include <security/pam_appl.h>
+#endif /* LINUX_PAM */
+
+#include "./support.-c"
+
+/*
+ * PAM framework looks for these entry-points to pass control to the
+ * authentication module.
+ */
+
+#include "./pam_unix_auth.-c"
+
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ D(("called."));
+
+ pwdb_start();
+ ctrl = set_ctrl(flags, argc, argv);
+ retval = _unix_auth( pamh, ctrl );
+ pwdb_end();
+
+ return retval;
+}
+
+PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags
+ , int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ D(("called."));
+
+ pwdb_start();
+ ctrl = set_ctrl(flags, argc, argv);
+ retval = _unix_set_credentials(pamh, ctrl) ;
+ pwdb_end();
+
+ return retval;
+}
+
+/*
+ * PAM framework looks for these entry-points to pass control to the
+ * account management module.
+ */
+
+#include "./pam_unix_acct.-c"
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ D(("called."));
+
+ pwdb_start();
+ ctrl = set_ctrl(flags, argc, argv);
+ retval = _unix_acct_mgmt(pamh, ctrl);
+ pwdb_end();
+
+ D(("done."));
+
+ return retval;
+}
+
+/*
+ * PAM framework looks for these entry-points to pass control to the
+ * session module.
+ */
+
+#include "./pam_unix_sess.-c"
+
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ D(("called."));
+
+ pwdb_start();
+ ctrl = set_ctrl(flags, argc, argv);
+ retval = _unix_open_session(pamh, ctrl);
+ pwdb_end();
+
+ return retval;
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ D(("called."));
+
+ pwdb_start();
+ ctrl = set_ctrl(flags, argc, argv);
+ retval = _unix_close_session(pamh, ctrl);
+ pwdb_end();
+
+ return retval;
+}
+
+/*
+ * PAM framework looks for these entry-points to pass control to the
+ * password changing module.
+ */
+
+#include "./pam_unix_passwd.-c"
+
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ D(("called."));
+
+ pwdb_start();
+ ctrl = set_ctrl(flags, argc, argv);
+ retval = _unix_chauthtok(pamh, ctrl);
+ pwdb_end();
+
+ return retval;
+}
+
+/* static module data */
+
+#ifdef PAM_STATIC
+struct pam_module _pam_pwdb_modstruct = {
+ "pam_pwdb",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok
+};
+
+#endif
+
+/*
+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_pwdb/pam_unix_acct.-c b/contrib/libpam/modules/pam_pwdb/pam_unix_acct.-c
new file mode 100644
index 000000000000..dbd13855ed3c
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_unix_acct.-c
@@ -0,0 +1,292 @@
+/*
+ * $Id: pam_unix_acct.-c,v 1.6 1997/01/04 20:37:15 morgan Exp morgan $
+ *
+ * $Log: pam_unix_acct.-c,v $
+ * Revision 1.6 1997/01/04 20:37:15 morgan
+ * extra debugging
+ *
+ * Revision 1.5 1996/12/01 03:05:54 morgan
+ * debugging with _pam_macros.h
+ *
+ * Revision 1.4 1996/11/10 21:03:57 morgan
+ * pwdb conversion
+ *
+ * Revision 1.3 1996/09/05 06:45:45 morgan
+ * tidied shadow acct management
+ *
+ * Revision 1.2 1996/09/01 01:13:14 morgan
+ * Cristian Gafton's patches
+ *
+ * Revision 1.1 1996/08/29 13:27:51 morgan
+ * Initial revision
+ *
+ *
+ * See end of file for copyright information
+ */
+
+static const char rcsid_acct[] =
+"$Id: pam_unix_acct.-c,v 1.6 1997/01/04 20:37:15 morgan Exp morgan $\n"
+" - PAM_PWDB account management <gafton@redhat.com>";
+
+/* the shadow suite has accout managment.. */
+
+static int _shadow_acct_mgmt_exp(pam_handle_t *pamh, unsigned int ctrl,
+ const struct pwdb *pw, const char *uname)
+{
+ const struct pwdb_entry *pwe = NULL;
+ time_t curdays;
+ int last_change, max_change;
+ int retval;
+
+ D(("called."));
+
+ /* Now start the checks */
+
+ curdays = time(NULL)/(60*60*24); /* today */
+
+ /* First: has account expired ? (CG)
+ * - expire < curdays
+ * - or (last_change + max_change + defer_change) < curdays
+ * - in both cases, deny access
+ */
+
+ D(("pwdb_get_entry"));
+ retval = pwdb_get_entry(pw, "expire", &pwe);
+ if (retval == PWDB_SUCCESS) {
+ int expire;
+
+ expire = *( (const int *) pwe->value );
+ (void) pwdb_entry_delete(&pwe); /* no longer needed */
+
+ if ((curdays > expire) && (expire > 0)) {
+
+ _log_err(LOG_NOTICE
+ , "acct: account %s has expired (account expired)"
+ , uname);
+ make_remark(pamh, ctrl, PAM_ERROR_MSG
+ , "Your account has expired; "
+ "please contact your system administrator");
+
+ D(("account expired"));
+ return PAM_ACCT_EXPIRED;
+ }
+ }
+
+ D(("pwdb_get_entry"));
+ retval = pwdb_get_entry(pw, "last_change", &pwe);
+ if ( retval == PWDB_SUCCESS ) {
+ last_change = *( (const int *) pwe->value );
+ } else {
+ last_change = curdays;
+ }
+ (void) pwdb_entry_delete(&pwe);
+
+ D(("pwdb_get_entry"));
+ retval = pwdb_get_entry(pw, "max_change", &pwe);
+ if ( retval == PWDB_SUCCESS ) {
+ max_change = *( (const int *) pwe->value );
+ } else {
+ max_change = -1;
+ }
+ (void) pwdb_entry_delete(&pwe);
+
+ D(("pwdb_get_entry"));
+ retval = pwdb_get_entry(pw, "defer_change", &pwe);
+ if (retval == PWDB_SUCCESS) {
+ int defer_change;
+
+ defer_change = *( (const int *) pwe->value );
+ (void) pwdb_entry_delete(&pwe);
+
+ if ((curdays > (last_change + max_change + defer_change))
+ && (max_change != -1) && (defer_change != -1)
+ && (last_change > 0)) {
+
+ if ( on(UNIX_DEBUG, ctrl) ) {
+ _log_err(LOG_NOTICE, "acct: account %s has expired "
+ "(failed to change password)", uname);
+ }
+ make_remark(pamh, ctrl, PAM_ERROR_MSG
+ , "Your password has expired; "
+ "please see your system administrator");
+
+ D(("account expired2"));
+ return PAM_ACCT_EXPIRED;
+ }
+ }
+
+ /* Now test if the password is expired, but the user still can
+ * change their password. (CG)
+ * - last_change = 0
+ * - last_change + max_change < curdays
+ */
+
+ D(("when was the last change"));
+ if (last_change == 0) {
+
+ if ( on(UNIX_DEBUG, ctrl) ) {
+ _log_err(LOG_NOTICE
+ , "acct: expired password for user %s (root enforced)"
+ , uname);
+ }
+ make_remark(pamh, ctrl, PAM_ERROR_MSG
+ , "You are required to change your password immediately"
+ );
+
+ D(("need a new password"));
+ return PAM_NEW_AUTHTOK_REQD;
+ }
+
+ if (((last_change + max_change) < curdays) &&
+ (max_change < 99999) && (max_change > 0)) {
+
+ if ( on(UNIX_DEBUG, ctrl) ) {
+ _log_err(LOG_DEBUG
+ , "acct: expired password for user %s (password aged)"
+ , uname);
+ }
+ make_remark(pamh, ctrl, PAM_ERROR_MSG
+ , "Your password has expired; please change it!");
+
+ D(("need a new password 2"));
+ return PAM_NEW_AUTHTOK_REQD;
+ }
+
+ /*
+ * Now test if the password is about to expire (CG)
+ * - last_change + max_change - curdays <= warn_change
+ */
+
+ retval = pwdb_get_entry(pw, "warn_change", &pwe);
+ if ( retval == PWDB_SUCCESS ) {
+ int warn_days, daysleft;
+
+ daysleft = last_change + max_change - curdays;
+ warn_days = *((const int *) pwe->value);
+ (void) pwdb_entry_delete(&pwe);
+
+ if ((daysleft <= warn_days) && (warn_days > 0)) {
+ char *s;
+
+ if ( on(UNIX_DEBUG, ctrl) ) {
+ _log_err(LOG_DEBUG
+ , "acct: password for user %s will expire in %d days"
+ , uname, daysleft);
+ }
+
+#define LocalComment "Warning: your password will expire in %d day%s"
+ if ((s = (char *) malloc(30+sizeof(LocalComment))) == NULL) {
+ _log_err(LOG_CRIT, "malloc failure in " __FILE__);
+ retval = PAM_BUF_ERR;
+ } else {
+
+ sprintf(s, LocalComment, daysleft, daysleft == 1 ? "":"s");
+
+ make_remark(pamh, ctrl, PAM_TEXT_INFO, s);
+ free(s);
+ }
+#undef LocalComment
+ }
+ } else {
+ retval = PAM_SUCCESS;
+ }
+
+ D(("all done"));
+ return retval;
+}
+
+
+/*
+ * this function checks for the account details. The user may not be
+ * permitted to log in at this time etc.. Within the context of
+ * vanilla Unix, this function simply does nothing. The shadow suite
+ * added password/account expiry, but PWDB takes care of this
+ * transparently.
+ */
+
+static int _unix_acct_mgmt(pam_handle_t *pamh, unsigned int ctrl)
+{
+ const struct pwdb *pw = NULL;
+
+ char *uname=NULL;
+ int retval;
+
+ D(("called."));
+
+ /* identify user */
+
+ retval = pam_get_item(pamh,PAM_USER,(const void **)&uname);
+ D(("user = `%s'", uname));
+ if (retval != PAM_SUCCESS || uname == NULL) {
+ _log_err(LOG_ALERT
+ , "acct; could not identify user (from uid=%d)"
+ , getuid());
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* get database information for user */
+
+ retval = pwdb_locate("user", PWDB_DEFAULT, uname, PWDB_ID_UNKNOWN, &pw);
+ if (retval != PWDB_SUCCESS || pw == NULL) {
+
+ _log_err(LOG_ALERT, "acct; %s (%s from uid=%d)"
+ , pwdb_strerror(retval), uname, getuid());
+ if ( pw ) {
+ (void) pwdb_delete(&pw);
+ }
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* now check the user's times etc.. */
+
+ retval = _shadow_acct_mgmt_exp(pamh, ctrl, pw, uname);
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, "expiry check failed for '%s'", uname);
+ }
+
+ /* Done with pw */
+
+ (void) pwdb_delete(&pw);
+
+ /* all done */
+
+ D(("done."));
+ return retval;
+}
+
+/*
+ * Copyright (c) Elliot Lee, 1996.
+ * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996.
+ * Copyright (c) Cristian Gafton <gafton@redhat.com> 1996.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_pwdb/pam_unix_auth.-c b/contrib/libpam/modules/pam_pwdb/pam_unix_auth.-c
new file mode 100644
index 000000000000..4a1eed0d6387
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_unix_auth.-c
@@ -0,0 +1,129 @@
+/*
+ * $Id: pam_unix_auth.-c,v 1.4 1996/12/01 03:05:54 morgan Exp $
+ *
+ * $Log: pam_unix_auth.-c,v $
+ * Revision 1.4 1996/12/01 03:05:54 morgan
+ * debugging with _pam_macros.h
+ *
+ * Revision 1.3 1996/11/10 21:04:29 morgan
+ * pwdb conversion
+ *
+ * Revision 1.2 1996/09/05 06:46:53 morgan
+ * fixed comments. Added check for null passwd.
+ * changed data item name
+ *
+ * Revision 1.1 1996/08/29 13:27:51 morgan
+ * Initial revision
+ *
+ * See end of file for Copyright information.
+ */
+
+static const char rcsid_auth[] =
+"$Id: pam_unix_auth.-c,v 1.4 1996/12/01 03:05:54 morgan Exp $: pam_unix_auth.-c,v 1.2 1996/09/05 06:46:53 morgan Exp morgan $\n"
+" - PAM_PWDB authentication functions. <morgan@parc.power.net>";
+
+/*
+ * _unix_auth() is a front-end for UNIX/shadow authentication
+ *
+ * First, obtain the password from the user. Then use a
+ * routine in 'support.-c' to authenticate the user.
+ */
+
+#define _UNIX_AUTHTOK "-UN*X-PASS"
+
+static int _unix_auth(pam_handle_t *pamh, unsigned int ctrl)
+{
+ int retval;
+ const char *name, *p;
+
+ D(("called."));
+
+ /* get the user'name' */
+
+ retval = _unix_get_user(pamh, ctrl, NULL, &name);
+ if (retval != PAM_SUCCESS ) {
+ if ( on(UNIX_DEBUG,ctrl) ) {
+ _log_err(LOG_DEBUG, "auth could not identify user");
+ }
+ return retval;
+ }
+
+ /* if this user does not have a password... */
+
+ if ( _unix_blankpasswd(ctrl, name) ) {
+ D(("user '%s' has blank passwd", name));
+ name = NULL;
+ return PAM_SUCCESS;
+ }
+
+ /* get this user's authentication token */
+
+ retval = _unix_read_password(pamh, ctrl, NULL, "Password: ", NULL
+ , _UNIX_AUTHTOK, &p);
+ if (retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "auth could not identify password for [%s]"
+ , name);
+ name = NULL;
+ return retval;
+ }
+
+ /* verify the password of this user */
+
+ retval = _unix_verify_password(pamh, name, p, ctrl);
+ name = p = NULL;
+
+ return retval;
+}
+
+/*
+ * This function is for setting unix credentials. Sun has indicated
+ * that there are *NO* authentication credentials for unix. The
+ * obvious credentials would be the group membership of the user as
+ * listed in the /etc/group file. However, Sun indicates that it is
+ * the responsibility of the application to set these.
+ */
+
+static int _unix_set_credentials(pam_handle_t *pamh, unsigned int ctrl)
+{
+ D(("called <empty function> returning."));
+
+ return PAM_SUCCESS;
+}
+
+/********************************************************************
+ * Copyright (c) Alexander O. Yuriev, 1996.
+ * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996
+ * Copyright (c) Cristian Gafton <gafton@redhat.com> 1996, 1997
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
diff --git a/contrib/libpam/modules/pam_pwdb/pam_unix_md.-c b/contrib/libpam/modules/pam_pwdb/pam_unix_md.-c
new file mode 100644
index 000000000000..cd90b0ff339b
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_unix_md.-c
@@ -0,0 +1,55 @@
+/*
+ * This function is a front-end for the message digest algorithms used
+ * to compute the user's encrypted passwords. No reversible encryption
+ * is used here and I intend to keep it that way.
+ *
+ * While there are many sources of encryption outside the United
+ * States, it *may* be illegal to re-export reversible encryption
+ * computer code. Until such time as it is legal to export encryption
+ * software freely from the US, please do not send me any. (AGM)
+ */
+
+/* this should have been defined in a header file.. Why wasn't it? AGM */
+extern char *crypt(const char *key, const char *salt);
+
+#include "md5.h"
+#include "bigcrypt.-c"
+
+struct cfns {
+ const char *salt;
+ int len;
+ char * (* mdfn)(const char *key, const char *salt);
+};
+
+/* array of non-standard digest algorithms available */
+
+#define N_MDS 1
+const static struct cfns cfn_list[N_MDS] = {
+ { "$1$", 3, crypt_md5 },
+};
+
+static char *_pam_md(const char *key, const char *salt)
+{
+ char *x,*e=NULL;
+ int i;
+
+ D(("called with key='%s', salt='%s'", key, salt));
+
+ /* check for non-standard salts */
+
+ for (i=0; i<N_MDS; ++i) {
+ if ( !strncmp(cfn_list[i].salt, salt, cfn_list[i].len) ) {
+ e = cfn_list[i].mdfn(key, salt);
+ break;
+ }
+ }
+
+ if ( i >= N_MDS ) {
+ e = bigcrypt(key, salt); /* (defaults to standard algorithm) */
+ }
+
+ x = x_strdup(e); /* put e in malloc()ed memory */
+ _pam_overwrite(e); /* clean up */
+ return x; /* this must be deleted elsewhere */
+}
+
diff --git a/contrib/libpam/modules/pam_pwdb/pam_unix_passwd.-c b/contrib/libpam/modules/pam_pwdb/pam_unix_passwd.-c
new file mode 100644
index 000000000000..402f7f349f88
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_unix_passwd.-c
@@ -0,0 +1,371 @@
+/* $Id: pam_unix_passwd.-c,v 1.6 1997/04/05 06:31:06 morgan Exp morgan $ */
+
+/*
+ * $Log: pam_unix_passwd.-c,v $
+ * Revision 1.6 1997/04/05 06:31:06 morgan
+ * mostly a reformat.
+ *
+ * Revision 1.5 1996/12/01 03:05:54 morgan
+ * debugging with _pam_macros.h
+ *
+ * Revision 1.4 1996/11/10 21:04:51 morgan
+ * pwdb conversion
+ *
+ * Revision 1.3 1996/09/05 06:48:15 morgan
+ * A lot has changed. I'd recommend you study the diff.
+ *
+ * Revision 1.2 1996/09/01 16:33:27 morgan
+ * Cristian Gafton's changes
+ *
+ * Revision 1.1 1996/08/29 13:21:27 morgan
+ * Initial revision
+ *
+ */
+
+static const char rcsid_pass[] =
+"$Id: pam_unix_passwd.-c,v 1.6 1997/04/05 06:31:06 morgan Exp morgan $\n"
+" - PAM_PWDB password module <morgan@parc.power.net>"
+;
+
+#include "pam_unix_pwupd.-c"
+
+/* passwd/salt conversion macros */
+
+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+/* data tokens */
+
+#define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS"
+#define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS"
+
+/* Implementation */
+
+/*
+ * FUNCTION: _pam_unix_chauthtok()
+ *
+ * this function works in two passes. The first, when UNIX__PRELIM is
+ * set, obtains the previous password. It sets the PAM_OLDAUTHTOK item
+ * or stores it as a data item. The second function obtains a new
+ * password (verifying if necessary, that the user types it the same a
+ * second time.) depending on the 'ctrl' flags this new password may
+ * be stored in the PAM_AUTHTOK item or a private data item.
+ *
+ * Having obtained a new password. The function updates the
+ * /etc/passwd (and optionally the /etc/shadow) file(s).
+ *
+ * Provision is made for the creation of a blank shadow file if none
+ * is available, but one is required to update the shadow file -- the
+ * intention being for shadow passwords to be seamlessly implemented
+ * from the generic UNIX scheme. -- THIS BIT IS PRE-ALPHA.. and included
+ * in this release (.52) mostly for the purpose of discussion.
+ */
+
+static int _unix_chauthtok(pam_handle_t *pamh, unsigned int ctrl)
+{
+ int retval;
+ unsigned int lctrl;
+
+ /* <DO NOT free() THESE> */
+ const char *user;
+ const char *pass_old, *pass_new;
+ /* </DO NOT free() THESE> */
+
+ D(("called"));
+
+ /*
+ * First get the name of a user
+ */
+
+ retval = _unix_get_user( pamh, ctrl, "Username: ", &user );
+ if ( retval != PAM_SUCCESS ) {
+ if ( on(UNIX_DEBUG,ctrl) ) {
+ _log_err(LOG_DEBUG, "password - could not identify user");
+ }
+ return retval;
+ }
+
+ if ( on(UNIX__PRELIM, ctrl) ) {
+ /*
+ * obtain and verify the current password (OLDAUTHTOK) for
+ * the user.
+ */
+
+ char *Announce;
+
+ D(("prelim check"));
+
+ if ( _unix_blankpasswd(ctrl, user) ) {
+
+ return PAM_SUCCESS;
+
+ } else if ( off(UNIX__IAMROOT, ctrl) ) {
+
+ /* instruct user what is happening */
+#define greeting "Changing password for "
+ Announce = (char *) malloc(sizeof(greeting)+strlen(user));
+ if (Announce == NULL) {
+ _log_err(LOG_CRIT, "password - out of memory");
+ return PAM_BUF_ERR;
+ }
+ (void) strcpy(Announce, greeting);
+ (void) strcpy(Announce+sizeof(greeting)-1, user);
+#undef greeting
+
+ lctrl = ctrl;
+ set(UNIX__OLD_PASSWD, lctrl);
+ retval = _unix_read_password( pamh, lctrl
+ , Announce
+ , "(current) UNIX password: "
+ , NULL
+ , _UNIX_OLD_AUTHTOK
+ , &pass_old );
+ free(Announce);
+
+ if ( retval != PAM_SUCCESS ) {
+ _log_err(LOG_NOTICE
+ , "password - (old) token not obtained");
+ return retval;
+ }
+
+ /* verify that this is the password for this user */
+
+ retval = _unix_verify_password(pamh, user, pass_old, ctrl);
+ } else {
+ D(("process run by root so do nothing this time around"));
+ pass_old = NULL;
+ retval = PAM_SUCCESS; /* root doesn't have too */
+ }
+
+ if ( retval != PAM_SUCCESS ) {
+ D(("Authentication failed"));
+ pass_old = NULL;
+ return retval;
+ }
+
+ retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
+ pass_old = NULL;
+ if ( retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "failed to set PAM_OLDAUTHTOK");
+ }
+
+ } else if ( on( UNIX__UPDATE, ctrl ) ) {
+ /* tpass is used below to store the _pam_md() return; it
+ * should be _pam_delete()'d. */
+
+ char *tpass=NULL;
+
+ /*
+ * obtain the proposed password
+ */
+
+ D(("do update"));
+
+ /*
+ * get the old token back. NULL was ok only if root [at this
+ * point we assume that this has already been enforced on a
+ * previous call to this function].
+ */
+
+ if ( off(UNIX_NOT_SET_PASS, ctrl) ) {
+ retval = pam_get_item(pamh, PAM_OLDAUTHTOK
+ , (const void **)&pass_old);
+ } else {
+ retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK
+ , (const void **)&pass_old);
+ if (retval == PAM_NO_MODULE_DATA) {
+ retval = PAM_SUCCESS;
+ pass_old = NULL;
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, "user not authenticated");
+ return retval;
+ }
+
+ D(("get new password now"));
+
+ lctrl = ctrl;
+
+ /*
+ * use_authtok is to force the use of a previously entered
+ * password -- needed for pluggable password strength checking
+ */
+
+ if ( on(UNIX_USE_AUTHTOK, lctrl) ) {
+ set(UNIX_USE_FIRST_PASS, lctrl);
+ }
+
+ retval = _unix_read_password( pamh, lctrl
+ , NULL
+ , "Enter new UNIX password: "
+ , "Retype new UNIX password: "
+ , _UNIX_NEW_AUTHTOK
+ , &pass_new );
+
+ if ( retval != PAM_SUCCESS ) {
+ if ( on(UNIX_DEBUG,ctrl) ) {
+ _log_err(LOG_ALERT
+ , "password - new password not obtained");
+ }
+ pass_old = NULL; /* tidy up */
+ return retval;
+ }
+
+ D(("returned to _unix_chauthtok"));
+
+ /*
+ * At this point we know who the user is and what they
+ * propose as their new password. Verify that the new
+ * password is acceptable.
+ */
+
+ if (pass_new[0] == '\0') { /* "\0" password = NULL */
+ pass_new = NULL;
+ }
+
+ retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
+
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, "new password not acceptable");
+ pass_new = pass_old = NULL; /* tidy up */
+ return retval;
+ }
+
+ /*
+ * By reaching here we have approved the passwords and must now
+ * rebuild the password database file.
+ */
+
+ /*
+ * First we encrypt the new password.
+ *
+ * XXX - this is where we might need some code for RADIUS types
+ * of password handling... no encryption needed..
+ */
+
+ if ( on(UNIX_MD5_PASS, ctrl) ) {
+
+ /*
+ * Code lifted from Marek Michalkiewicz's shadow suite. (CG)
+ * removed use of static variables (AGM)
+ */
+
+ struct timeval tv;
+ MD5_CTX ctx;
+ unsigned char result[16];
+ char *cp = (char *)result;
+ unsigned char tmp[16];
+ int i;
+
+ MD5Init(&ctx);
+ gettimeofday(&tv, (struct timezone *) 0);
+ MD5Update(&ctx, (void *) &tv, sizeof tv);
+ i = getpid();
+ MD5Update(&ctx, (void *) &i, sizeof i);
+ i = clock();
+ MD5Update(&ctx, (void *) &i, sizeof i);
+ MD5Update(&ctx, result, sizeof result);
+ MD5Final(tmp, &ctx);
+ strcpy(cp, "$1$"); /* magic for the MD5 */
+ cp += strlen(cp);
+ for (i = 0; i < 8; i++)
+ *cp++ = i64c(tmp[i] & 077);
+ *cp = '\0';
+
+ /* no longer need cleartext */
+ pass_new = tpass = _pam_md(pass_new, (const char *)result);
+
+ } else {
+ /*
+ * Salt manipulation is stolen from Rick Faith's passwd
+ * program. Sorry Rick :) -- alex
+ */
+
+ time_t tm;
+ char salt[3];
+
+ time(&tm);
+ salt[0] = bin_to_ascii(tm & 0x3f);
+ salt[1] = bin_to_ascii((tm >> 6) & 0x3f);
+ salt[2] = '\0';
+
+ if ( off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8 ) {
+ /* to avoid using the _extensions_ of the bigcrypt()
+ function we truncate the newly entered password */
+ char *temp = malloc(9);
+
+ if (temp == NULL) {
+ _log_err(LOG_CRIT, "out of memory for password");
+ pass_new = pass_old = NULL; /* tidy up */
+ return PAM_BUF_ERR;
+ }
+
+ /* copy first 8 bytes of password */
+ strncpy(temp, pass_new, 8);
+ temp[8] = '\0';
+
+ /* no longer need cleartext */
+ pass_new = tpass = _pam_md( temp, salt );
+
+ _pam_delete(temp); /* tidy up */
+ } else {
+ /* no longer need cleartext */
+ pass_new = tpass = _pam_md( pass_new, salt );
+ }
+ }
+
+ D(("password processed"));
+
+ /* update the password database(s) -- race conditions..? */
+
+ retval = unix_update_db(pamh, ctrl, user, pass_old, pass_new);
+ pass_old = pass_new = NULL;
+
+ } else { /* something has broken with the module */
+
+ _log_err(LOG_ALERT, "password received unknown request");
+ retval = PAM_ABORT;
+
+ }
+
+ return retval;
+}
+
+/* ******************************************************************
+ * Copyright (c) Alexander O. Yuriev (alex@bach.cis.temple.edu), 1996.
+ * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996, 1997.
+ * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_pwdb/pam_unix_pwupd.-c b/contrib/libpam/modules/pam_pwdb/pam_unix_pwupd.-c
new file mode 100644
index 000000000000..d50031dcb919
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_unix_pwupd.-c
@@ -0,0 +1,272 @@
+/*
+ * $Id: pam_unix_pwupd.-c,v 1.4 1997/01/04 20:35:32 morgan Exp morgan $
+ *
+ * This file contains the routines to update the passwd databases.
+ *
+ * $Log: pam_unix_pwupd.-c,v $
+ * Revision 1.4 1997/01/04 20:35:32 morgan
+ * minor comment change
+ *
+ * Revision 1.3 1996/12/01 03:05:54 morgan
+ * debugging with _pam_macros.h
+ *
+ * Revision 1.2 1996/11/10 21:05:09 morgan
+ * pwdb conversion
+ *
+ *
+ */
+
+/* Implementation */
+
+static int unix_update_db(pam_handle_t *pamh, int ctrl, const char *user,
+ const char *pass_old, const char *pass_new)
+{
+ const struct pwdb *pw=NULL;
+ const struct pwdb_entry *pwe=NULL;
+ pwdb_flag flag;
+ int retval, i;
+
+ D(("called."));
+
+ /* obtain default user record */
+
+ retval = pwdb_locate("user", PWDB_DEFAULT, user, PWDB_ID_UNKNOWN, &pw);
+ if (retval == PWDB_PASS_PHRASE_REQD) {
+ retval = pwdb_set_entry(pw, "pass_phrase"
+ , pass_old, 1+strlen(pass_old)
+ , NULL, NULL, 0);
+ if (retval == PWDB_SUCCESS)
+ retval = pwdb_locate("user", pw->source, user
+ , PWDB_ID_UNKNOWN, &pw);
+ }
+ pass_old = NULL;
+
+ if ( retval != PWDB_SUCCESS ) {
+ _log_err(LOG_ALERT, "cannot identify user %s (uid=%d)"
+ , user, getuid() );
+ pass_new = NULL;
+ if (pw)
+ (void) pwdb_delete(&pw);
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* check that we can update all of the default databases */
+
+ retval = pwdb_flags("user", pw->source, &flag);
+
+ if ( retval != PWDB_SUCCESS || ( pwdb_on(flag,PWDB_F_NOUPDATE) ) ) {
+ _log_err(LOG_ERR, "cannot update default database for user %s"
+ , user );
+ pass_new = NULL;
+ if (pw)
+ (void) pwdb_delete(&pw);
+ return PAM_PERM_DENIED;
+ }
+
+ /* If there was one, we delete the "last_change" entry */
+ retval = pwdb_get_entry(pw, "last_change", &pwe);
+ if (retval == PWDB_SUCCESS) {
+ (void) pwdb_entry_delete(&pwe);
+ pwdb_set_entry(pw, "last_change", NULL, -1, NULL, NULL, 0);
+ }
+
+ /*
+ * next check for pam.conf specified databases: shadow etc... [In
+ * other words, pam.conf indicates which database the password is
+ * to be subsequently placed in: this is password migration].
+ */
+
+ if ( on(UNIX__SET_DB, ctrl) ) {
+ const char *db_token;
+ pwdb_type pt = _PWDB_MAX_TYPES;
+
+ if ( on(UNIX_UNIX, ctrl) ) {
+ db_token = "U"; /* XXX - should be macro */
+ pt = PWDB_UNIX;
+ } else if ( on(UNIX_SHADOW, ctrl) ) {
+ db_token = "x"; /* XXX - should be macro */
+ pt = PWDB_SHADOW;
+ } else if ( on(UNIX_RADIUS, ctrl) ) {
+ db_token = "R"; /* XXX - is this ok? */
+ pt = PWDB_RADIUS;
+ } else {
+ _log_err(LOG_ALERT
+ , "cannot determine database to use for authtok");
+ pass_new = NULL;
+ if (pw)
+ (void) pwdb_delete(&pw);
+ return PAM_ABORT; /* we're in trouble */
+ }
+
+ /*
+ * Attempt to update the indicated database (only)
+ */
+
+ {
+ pwdb_type tpt[2];
+ tpt[0] = pt;
+ tpt[1] = _PWDB_MAX_TYPES;
+
+ /* Can we set entry in database? */
+ retval = pwdb_flags("user", tpt, &flag);
+ if (retval == PWDB_SUCCESS && !pwdb_on(flag,PWDB_F_NOUPDATE)) {
+ /* YES. This database is available.. */
+
+ /* Only update if it is not already in the default list */
+ for (i=0; pw->source[i] != _PWDB_MAX_TYPES
+ && pw->source[i] != pt ; ++i);
+ if (pw->source[i] == _PWDB_MAX_TYPES) {
+ const struct pwdb *tpw=NULL;
+
+ /* copy database entry */
+ if ((retval = pwdb_new(&tpw, 10)) != PWDB_SUCCESS
+ || (retval = pwdb_merge(tpw, pw, PWDB_TRUE))
+ != PWDB_SUCCESS) {
+ _log_err(LOG_CRIT, "failed to obtain new pwdb: %s"
+ , pwdb_strerror(retval));
+ retval = PAM_ABORT;
+ } else
+ retval = PAM_SUCCESS;
+
+ /* set db_token */
+ if (retval == PAM_SUCCESS) {
+ retval = pwdb_set_entry(tpw, "defer_pass", db_token
+ , 1+strlen(db_token)
+ , NULL, NULL, 0);
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "set defer_pass -> %s"
+ , pwdb_strerror(retval));
+ retval = PAM_PERM_DENIED;
+ } else
+ retval = PAM_SUCCESS;
+ }
+
+ /* update specific database */
+ if (retval == PAM_SUCCESS) {
+ retval = pwdb_replace("user", tpt
+ , user, PWDB_ID_UNKNOWN, &tpw);
+ if (retval != PWDB_SUCCESS) {
+ const char *service=NULL;
+ (void) pam_get_item(pamh, PAM_SERVICE
+ , (const void **)&service);
+ _log_err(LOG_ALERT
+ , "(%s) specified database failed: %s"
+ , service
+ , pwdb_strerror(retval));
+ retval = PAM_PERM_DENIED;
+ } else {
+ retval = PAM_SUCCESS;
+ }
+ }
+
+ /* clean up temporary pwdb */
+ if (tpw)
+ (void) pwdb_delete(&tpw);
+ }
+
+ /* we can properly adopt new defer_pass */
+ if (retval == PAM_SUCCESS) {
+ /* failing here will mean we go back to former
+ password location */
+ (void) pwdb_set_entry(pw, "defer_pass", db_token
+ , 1+strlen(db_token), NULL, NULL, 0);
+ }
+ }
+ }
+ }
+
+ /*
+ * the password will now be placed in appropriate (perhaps original) db
+ */
+
+ retval = pwdb_get_entry(pw, "uid", &pwe);
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "no uid!? (%s); %s", user, pwdb_strerror(retval));
+ pass_new = NULL;
+ if (pw)
+ (void) pwdb_delete(&pw);
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* insert the passwd into the 'pw' structure */
+
+ retval = pwdb_set_entry(pw, "passwd", pass_new, 1+strlen(pass_new)
+ , NULL, NULL, 0);
+ pass_new = NULL;
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "set2 failed; %s", pwdb_strerror(retval));
+ if (pw)
+ (void) pwdb_delete(&pw);
+ return PAM_AUTHTOK_LOCK_BUSY;
+ }
+
+ retval = pwdb_replace("user", pw->source, user
+ , *((uid_t *)pwe->value), &pw);
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "user (%s/%d) update failed; %s"
+ , user, *((uid_t *)pwe->value), pwdb_strerror(retval));
+ if (pw)
+ (void) pwdb_delete(&pw);
+ (void) pwdb_entry_delete(&pwe);
+ return PAM_ABORT;
+ }
+
+ if (retval != PWDB_SUCCESS) {
+
+ _log_err(LOG_ALERT, "user (%s/%d) update failed; %s"
+ , user, *((uid_t *)pwe->value), pwdb_strerror(retval));
+ retval = PAM_ABORT;
+
+ } else {
+ /* password updated */
+
+ _log_err(LOG_INFO, "password for (%s/%d) changed by (%s/%d)"
+ , user, *((uid_t *)pwe->value), getlogin(), getuid());
+ retval = PAM_SUCCESS;
+ }
+
+ /* tidy up */
+
+ (void) pwdb_entry_delete(&pwe);
+ if (pw)
+ (void) pwdb_delete(&pw);
+
+ return retval;
+}
+
+/* ******************************************************************
+ * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996,1997.
+ * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997.
+ * All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_pwdb/pam_unix_sess.-c b/contrib/libpam/modules/pam_pwdb/pam_unix_sess.-c
new file mode 100644
index 000000000000..49ce96cbd16c
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pam_unix_sess.-c
@@ -0,0 +1,112 @@
+/*
+ * $Id: pam_unix_sess.-c,v 1.4 1996/12/01 03:05:54 morgan Exp morgan $
+ *
+ * $Log: pam_unix_sess.-c,v $
+ * Revision 1.4 1996/12/01 03:05:54 morgan
+ * debugging with _pam_macros.h
+ *
+ * Revision 1.3 1996/11/10 21:05:33 morgan
+ * pwdb conversion
+ *
+ * Revision 1.2 1996/09/05 06:49:02 morgan
+ * more informative logging
+ *
+ * Revision 1.1 1996/08/29 13:27:51 morgan
+ * Initial revision
+ *
+ *
+ * See end for Copyright information
+ */
+
+static const char rcsid_sess[] =
+"$Id: pam_unix_sess.-c,v 1.4 1996/12/01 03:05:54 morgan Exp morgan $\n"
+" - PAM_PWDB session management. morgan@parc.power.net";
+
+/* Define internal functions */
+
+static int _unix_open_session(pam_handle_t *pamh, unsigned int ctrl)
+{
+ int retval;
+ char *user_name, *service;
+
+ D(("called."));
+
+ retval = pam_get_item( pamh, PAM_USER, (void *) &user_name );
+ if ( user_name == NULL || retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "open_session - error recovering username");
+ return PAM_SESSION_ERR;
+ }
+
+ retval = pam_get_item( pamh, PAM_SERVICE, (void*) &service );
+ if ( service == NULL || retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "open_session - error recovering service");
+ return PAM_SESSION_ERR;
+ }
+
+ _log_err(LOG_INFO, "(%s) session opened for user %s by %s(uid=%d)"
+ , service, user_name
+ , getlogin() == NULL ? "":getlogin(), getuid() );
+
+ return PAM_SUCCESS;
+}
+
+static int _unix_close_session(pam_handle_t *pamh, unsigned int ctrl)
+{
+ int retval;
+ char *user_name, *service;
+
+ D(("called."));
+
+ retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
+ if ( user_name == NULL || retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "close_session - error recovering username");
+ return PAM_SESSION_ERR;
+ }
+
+ retval = pam_get_item( pamh, PAM_SERVICE, (void*) &service );
+ if ( service == NULL || retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "close_session - error recovering service");
+ return PAM_SESSION_ERR;
+ }
+
+ _log_err(LOG_INFO, "(%s) session closed for user %s"
+ , service, user_name );
+
+ return PAM_SUCCESS;
+}
+
+/*
+ * Copyright (c) Alexander O. Yuriev, 1996. All rights reserved.
+ * Copyright (c) Andrew G. Morgan, 1996, <morgan@parc.power.net>
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_pwdb/pwdb_chkpwd.c b/contrib/libpam/modules/pam_pwdb/pwdb_chkpwd.c
new file mode 100644
index 000000000000..6332eaa7e865
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/pwdb_chkpwd.c
@@ -0,0 +1,208 @@
+/*
+ * $Id: pwdb_chkpwd.c,v 1.1 1997/02/15 17:26:18 morgan Exp $
+ *
+ * This program is designed to run setuid(root) or with sufficient
+ * privilege to read all of the unix password databases. It is designed
+ * to provide a mechanism for the current user (defined by this
+ * process' real uid) to verify their own password.
+ *
+ * The password is read from the standard input. The exit status of
+ * this program indicates whether the user is authenticated or not.
+ *
+ * Copyright information is located at the end of the file.
+ *
+ * $Log: pwdb_chkpwd.c,v $
+ * Revision 1.1 1997/02/15 17:26:18 morgan
+ * Initial revision
+ *
+ * Revision 1.1 1996/11/10 21:20:51 morgan
+ * Initial revision
+ *
+ */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <security/_pam_macros.h>
+
+#define MAXPASS 200 /* the maximum length of a password */
+
+#define UNIX_PASSED (PWDB_SUCCESS)
+#define UNIX_FAILED (PWDB_SUCCESS+1)
+
+#include <pwdb/pwdb_public.h>
+
+/* syslogging function for errors and other information */
+
+static void _log_err(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pwdb_chkpwd", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+#include "pam_unix_md.-c"
+
+static int _unix_verify_passwd(const char *salt, const char *p)
+{
+ char *pp=NULL;
+ int retval;
+
+ if (p == NULL) {
+ if (*salt == '\0') {
+ retval = UNIX_PASSED;
+ } else {
+ retval = UNIX_FAILED;
+ }
+ } else {
+ pp = _pam_md(p, salt);
+ p = NULL; /* no longer needed here */
+
+ if ( strcmp( pp, salt ) == 0 ) {
+ retval = UNIX_PASSED;
+ } else {
+ retval = UNIX_FAILED;
+ }
+ }
+
+ /* clean up */
+ {
+ char *tp = pp;
+ if (pp != NULL) {
+ while(tp && *tp)
+ *tp++ = '\0';
+ free(pp);
+ pp = tp = NULL;
+ }
+ }
+
+ return retval;
+}
+
+void main(void)
+{
+ const struct pwdb *pw=NULL;
+ const struct pwdb_entry *pwe=NULL;
+ char pass[MAXPASS+1];
+ int npass;
+ int retval=UNIX_FAILED;
+
+ /*
+ * we establish that this program is running with non-tty stdin.
+ * this is to discourage casual use. It does *NOT* prevent an
+ * intruder from repeatadly running this program to determine the
+ * password of the current user (brute force attack, but one for
+ * which the attacker must already have gained access to the user's
+ * account).
+ */
+
+ if ( isatty(STDIN_FILENO) ) {
+ _log_err(LOG_NOTICE
+ , "inappropriate use of PWDB helper binary [UID=%d]"
+ , getuid() );
+ fprintf(stderr,
+ "This program is not designed for running in this way\n"
+ "-- the system administrator has been informed\n");
+ exit(UNIX_FAILED);
+ }
+
+ /*
+ * determine the current user's name:
+ */
+
+ retval = pwdb_start();
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "failed to open pwdb");
+ retval = UNIX_FAILED;
+ }
+ if (retval != UNIX_FAILED) {
+ retval = pwdb_locate("user", PWDB_DEFAULT, PWDB_NAME_UNKNOWN
+ , getuid(), &pw);
+ }
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "could not identify user");
+ while (pwdb_end() != PWDB_SUCCESS);
+ exit(UNIX_FAILED);
+ }
+
+ /* read the password from stdin (a pipe from the pam_pwdb module) */
+
+ npass = read(STDIN_FILENO, pass, MAXPASS);
+
+ if (npass < 0) { /* is it a valid password? */
+ _log_err(LOG_DEBUG, "no password supplied");
+ retval = UNIX_FAILED;
+ } else if (npass >= MAXPASS-1) {
+ _log_err(LOG_DEBUG, "password too long");
+ retval = UNIX_FAILED;
+ } else if (pwdb_get_entry(pw, "passwd", &pwe) != PWDB_SUCCESS) {
+ _log_err(LOG_WARNING, "password not found");
+ retval = UNIX_FAILED;
+ } else {
+ if (npass <= 0) {
+ /* the password is NULL */
+
+ retval = _unix_verify_passwd((const char *)(pwe->value), NULL);
+ } else {
+ /* does pass agree with the official one? */
+
+ pass[npass] = '\0'; /* NUL terminate */
+ retval = _unix_verify_passwd((const char *)(pwe->value), pass);
+ }
+ }
+
+ memset(pass, '\0', MAXPASS); /* clear memory of the password */
+ while (pwdb_end() != PWDB_SUCCESS);
+
+ /* return pass or fail */
+
+ exit(retval);
+}
+
+/*
+ * Copyright (c) Andrew G. Morgan, 1997. All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_pwdb/support.-c b/contrib/libpam/modules/pam_pwdb/support.-c
new file mode 100644
index 000000000000..71e212d64195
--- /dev/null
+++ b/contrib/libpam/modules/pam_pwdb/support.-c
@@ -0,0 +1,910 @@
+/*
+ * $Id: support.-c,v 1.7 1997/04/05 06:32:06 morgan Exp morgan $
+ *
+ * $Log: support.-c,v $
+ * Revision 1.7 1997/04/05 06:32:06 morgan
+ * new option and also deleted _readto
+ *
+ * Revision 1.6 1997/02/15 17:27:20 morgan
+ * added helper binary to password checking
+ *
+ * Revision 1.5 1996/12/01 03:05:54 morgan
+ * debugging with _pam_macros.h
+ *
+ * Revision 1.4 1996/11/10 21:06:07 morgan
+ * pwdb conversion
+ *
+ * Copyright information at end of file.
+ */
+
+/*
+ * here is the string to inform the user that the new passwords they
+ * typed were not the same.
+ */
+
+#define MISTYPED_PASS "Sorry, passwords do not match"
+
+/* type definition for the control options */
+
+typedef struct {
+ const char *token;
+ unsigned int mask; /* shall assume 32 bits of flags */
+ unsigned int flag;
+} UNIX_Ctrls;
+
+/*
+ * macro to determine if a given flag is on
+ */
+
+#define on(x,ctrl) (unix_args[x].flag & ctrl)
+
+/*
+ * macro to determine that a given flag is NOT on
+ */
+
+#define off(x,ctrl) (!on(x,ctrl))
+
+/*
+ * macro to turn on/off a ctrl flag manually
+ */
+
+#define set(x,ctrl) (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag)
+#define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag))
+
+/* the generic mask */
+
+#define _ALL_ON_ (~0U)
+
+/* end of macro definitions definitions for the control flags */
+
+/* ****************************************************************** *
+ * ctrl flags proper..
+ */
+
+/*
+ * here are the various options recognized by the unix module. They
+ * are enumerated here and then defined below. Internal arguments are
+ * given NULL tokens.
+ */
+
+#define UNIX__OLD_PASSWD 0 /* internal */
+#define UNIX__VERIFY_PASSWD 1 /* internal */
+#define UNIX__IAMROOT 2 /* internal */
+
+#define UNIX_AUDIT 3 /* print more things than debug..
+ some information may be sensitive */
+#define UNIX_USE_FIRST_PASS 4
+#define UNIX_TRY_FIRST_PASS 5
+#define UNIX_NOT_SET_PASS 6 /* don't set the AUTHTOK items */
+
+#define UNIX__PRELIM 7 /* internal */
+#define UNIX__UPDATE 8 /* internal */
+#define UNIX__NONULL 9 /* internal */
+#define UNIX__QUIET 10 /* internal */
+#define UNIX_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */
+#define UNIX_SHADOW 12 /* signal shadow on */
+#define UNIX_MD5_PASS 13 /* force the use of MD5 passwords */
+#define UNIX__NULLOK 14 /* Null token ok */
+#define UNIX_RADIUS 15 /* wish to use RADIUS for password */
+#define UNIX__SET_DB 16 /* internal - signals redirect to db */
+#define UNIX_DEBUG 17 /* send more info to syslog(3) */
+#define UNIX_NODELAY 18 /* admin does not want a fail-delay */
+#define UNIX_UNIX 19 /* wish to use /etc/passwd for pwd */
+#define UNIX_BIGCRYPT 20 /* use DEC-C2 crypt()^x function */
+/* -------------- */
+#define UNIX_CTRLS_ 21 /* number of ctrl arguments defined */
+
+
+static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = {
+/* symbol token name ctrl mask ctrl *
+ * ------------------ ------------------ -------------- ---------- */
+
+/* UNIX__OLD_PASSWD */ { NULL, _ALL_ON_, 01 },
+/* UNIX__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 },
+/* UNIX__IAMROOT */ { NULL, _ALL_ON_, 04 },
+/* UNIX_AUDIT */ { "audit", _ALL_ON_, 010 },
+/* UNIX_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(060), 020 },
+/* UNIX_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(060), 040 },
+/* UNIX_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 0100 },
+/* UNIX__PRELIM */ { NULL, _ALL_ON_^(0600), 0200 },
+/* UNIX__UPDATE */ { NULL, _ALL_ON_^(0600), 0400 },
+/* UNIX__NONULL */ { NULL, _ALL_ON_, 01000 },
+/* UNIX__QUIET */ { NULL, _ALL_ON_, 02000 },
+/* UNIX_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 04000 },
+/* UNIX_SHADOW */ { "shadow", _ALL_ON_^(0140000), 010000 },
+/* UNIX_MD5_PASS */ { "md5", _ALL_ON_^(02000000), 020000 },
+/* UNIX__NULLOK */ { "nullok", _ALL_ON_^(01000), 0 },
+/* UNIX_RADIUS */ { "radius", _ALL_ON_^(0110000), 040000 },
+/* UNIX__SET_DB */ { NULL, _ALL_ON_, 0100000 },
+/* UNIX_DEBUG */ { "debug", _ALL_ON_, 0200000 },
+/* UNIX_NODELAY */ { "nodelay", _ALL_ON_, 0400000 },
+/* UNIX_UNIX */ { "unix", _ALL_ON_^(050000), 01000000 },
+/* UNIX_BIGCRYPT */ { "bigcrypt", _ALL_ON_^(020000), 02000000 },
+};
+
+#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
+
+/* syslogging function for errors and other information */
+
+static void _log_err(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM_pwdb", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* this is a front-end for module-application conversations */
+
+static int converse(pam_handle_t *pamh, int ctrl, int nargs
+ , struct pam_message **message
+ , struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ D(("begin to converse"));
+
+ retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
+ if ( retval == PAM_SUCCESS ) {
+
+ retval = conv->conv(nargs, ( const struct pam_message ** ) message
+ , response, conv->appdata_ptr);
+
+ D(("returned from application's conversation function"));
+
+ if (retval != PAM_SUCCESS && on(UNIX_DEBUG,ctrl) ) {
+ _log_err(LOG_DEBUG, "conversation failure [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ } else {
+ _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
+ , pam_strerror(pamh, retval));
+ }
+
+ D(("ready to return from module conversation"));
+
+ return retval; /* propagate error status */
+}
+
+static int make_remark(pam_handle_t *pamh, unsigned int ctrl
+ , int type, const char *text)
+{
+ int retval=PAM_SUCCESS;
+
+ if ( off(UNIX__QUIET, ctrl) ) {
+ struct pam_message *pmsg[1], msg[1];
+ struct pam_response *resp;
+
+ pmsg[0] = &msg[0];
+ msg[0].msg = text;
+ msg[0].msg_style = type;
+
+ resp = NULL;
+ retval = converse(pamh, ctrl, 1, pmsg, &resp);
+
+ if (resp) {
+ _pam_drop_reply(resp, 1);
+ }
+ }
+ return retval;
+}
+
+/*
+ * set the control flags for the UNIX module.
+ */
+
+static int set_ctrl(int flags, int argc, const char **argv)
+{
+ unsigned int ctrl;
+
+ D(("called."));
+
+ ctrl = UNIX_DEFAULTS; /* the default selection of options */
+
+ /* set some flags manually */
+
+ if ( getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK) ) {
+ set(UNIX__IAMROOT, ctrl);
+ }
+ if ( flags & PAM_UPDATE_AUTHTOK ) {
+ set(UNIX__UPDATE, ctrl);
+ }
+ if ( flags & PAM_PRELIM_CHECK ) {
+ set(UNIX__PRELIM, ctrl);
+ }
+ if ( flags & PAM_DISALLOW_NULL_AUTHTOK ) {
+ set(UNIX__NONULL, ctrl);
+ }
+ if ( flags & PAM_SILENT ) {
+ set(UNIX__QUIET, ctrl);
+ }
+
+ /* now parse the arguments to this module */
+
+ while (argc-- > 0) {
+ int j;
+
+ D(("pam_pwdb arg: %s",*argv));
+
+ for (j=0; j<UNIX_CTRLS_; ++j) {
+ if (unix_args[j].token
+ && ! strcmp(*argv, unix_args[j].token) ) {
+ break;
+ }
+ }
+
+ if ( j >= UNIX_CTRLS_ ) {
+ _log_err(LOG_ERR, "unrecognized option [%s]",*argv);
+ } else {
+ ctrl &= unix_args[j].mask; /* for turning things off */
+ ctrl |= unix_args[j].flag; /* for turning things on */
+ }
+
+ ++argv; /* step to next argument */
+ }
+
+ /* these are used for updating passwords in specific places */
+
+ if (on(UNIX_SHADOW,ctrl) || on(UNIX_RADIUS,ctrl) || on(UNIX_UNIX,ctrl)) {
+ set(UNIX__SET_DB, ctrl);
+ }
+
+ /* auditing is a more sensitive version of debug */
+
+ if ( on(UNIX_AUDIT,ctrl) ) {
+ set(UNIX_DEBUG, ctrl);
+ }
+
+ /* return the set of flags */
+
+ D(("done."));
+ return ctrl;
+}
+
+/* use this to free strings. ESPECIALLY password strings */
+
+static char *_pam_delete(register char *xx)
+{
+ _pam_overwrite(xx);
+ _pam_drop(xx);
+ return NULL;
+}
+
+static void _cleanup(pam_handle_t *pamh, void *x, int error_status)
+{
+ x = _pam_delete( (char *) x );
+}
+
+/* ************************************************************** *
+ * Useful non-trivial functions *
+ * ************************************************************** */
+
+#include "pam_unix_md.-c"
+
+/*
+ * the following is used to keep track of the number of times a user fails
+ * to authenticate themself.
+ */
+
+#define FAIL_PREFIX "-UN*X-FAIL-"
+#define UNIX_MAX_RETRIES 3
+
+struct _pam_failed_auth {
+ char *user; /* user that's failed to be authenticated */
+ char *name; /* attempt from user with name */
+ int id; /* uid of name'd user */
+ int count; /* number of failures so far */
+};
+
+#ifndef PAM_DATA_REPLACE
+#error "Need to get an updated libpam 0.52 or better"
+#endif
+
+static void _cleanup_failures(pam_handle_t *pamh, void *fl, int err)
+{
+ int quiet;
+ const char *service=NULL;
+ struct _pam_failed_auth *failure;
+
+ D(("called"));
+
+ quiet = err & PAM_DATA_SILENT; /* should we log something? */
+ err &= PAM_DATA_REPLACE; /* are we just replacing data? */
+ failure = (struct _pam_failed_auth *) fl;
+
+ if ( failure != NULL ) {
+
+ if ( !quiet && !err ) { /* under advisement from Sun,may go away */
+
+ /* log the number of authentication failures */
+ if ( failure->count != 0 ) {
+ (void) pam_get_item(pamh, PAM_SERVICE
+ , (const void **)&service);
+ _log_err(LOG_NOTICE
+ , "%d authentication failure%s; %s(uid=%d) -> "
+ "%s for %s service"
+ , failure->count, failure->count==1 ? "":"s"
+ , failure->name
+ , failure->id
+ , failure->user
+ , service == NULL ? "**unknown**":service
+ );
+ if ( failure->count > UNIX_MAX_RETRIES ) {
+ _log_err(LOG_ALERT
+ , "service(%s) ignoring max retries; %d > %d"
+ , service == NULL ? "**unknown**":service
+ , failure->count
+ , UNIX_MAX_RETRIES );
+ }
+ }
+ }
+ failure->user = _pam_delete(failure->user); /* tidy up */
+ failure->name = _pam_delete(failure->name); /* tidy up */
+ free(failure);
+ }
+}
+
+/*
+ * verify the password of a user
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd)
+{
+ int retval, child, fds[2];
+
+ D(("called."));
+ /* create a pipe for the password */
+ if (pipe(fds) != 0) {
+ D(("could not make pipe"));
+ return PAM_AUTH_ERR;
+ }
+
+ /* fork */
+ child = fork();
+ if (child == 0) {
+ static char *args[] = { NULL, NULL };
+ static char *envp[] = { NULL };
+
+ /* XXX - should really tidy up PAM here too */
+ while (pwdb_end() == PWDB_SUCCESS);
+
+ /* reopen stdin as pipe */
+ close(fds[1]);
+ dup2(fds[0], STDIN_FILENO);
+
+ /* exec binary helper */
+ args[0] = x_strdup(CHKPWD_HELPER);
+ execve(CHKPWD_HELPER, args, envp);
+
+ /* should not get here: exit with error */
+ D(("helper binary is not available"));
+ exit(PWDB_SUCCESS+1);
+ } else if (child > 0) {
+ /* wait for child */
+ close(fds[0]);
+ if (passwd != NULL) { /* send the password to the child */
+ write(fds[1], passwd, strlen(passwd)+1);
+ passwd = NULL;
+ } else {
+ write(fds[1], "", 1); /* blank password */
+ }
+ close(fds[1]);
+ (void) waitpid(child, &retval, 0); /* wait for helper to complete */
+ retval = (retval == PWDB_SUCCESS) ? PAM_SUCCESS:PAM_AUTH_ERR;
+ } else {
+ D(("fork failed"));
+ retval = PAM_AUTH_ERR;
+ }
+
+ D(("returning %d", retval));
+ return retval;
+}
+
+static int _unix_verify_password(pam_handle_t *pamh, const char *name
+ , const char *p, unsigned int ctrl)
+{
+ const struct pwdb *pw=NULL;
+ const struct pwdb_entry *pwe=NULL;
+
+ const char *salt;
+ char *pp;
+ char *data_name;
+ int retval;
+
+ D(("called"));
+
+#ifdef HAVE_PAM_FAIL_DELAY
+ if ( off(UNIX_NODELAY, ctrl) ) {
+ D(("setting delay"));
+ (void) pam_fail_delay(pamh, 1000000); /* 1 sec delay for on failure */
+ }
+#endif
+
+ /* locate the entry for this user */
+
+ D(("locating user's record"));
+ retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw);
+ if (retval == PWDB_PASS_PHRASE_REQD) {
+ /*
+ * give the password to the pwdb library. It may be needed to
+ * access the database
+ */
+
+ retval = pwdb_set_entry( pw, "pass_phrase", p, 1+strlen(p)
+ , NULL, NULL, 0);
+ if (retval != PWDB_SUCCESS) {
+ _log_err(LOG_ALERT, "find pass; %s", pwdb_strerror(retval));
+ (void) pwdb_delete(&pw);
+ p = NULL;
+ return PAM_CRED_INSUFFICIENT;
+ }
+
+ retval = pwdb_locate("user", pw->source, name, PWDB_ID_UNKNOWN, &pw);
+ }
+
+ if (retval != PWDB_SUCCESS) {
+ D(("user's record unavailable"));
+ if ( on(UNIX_AUDIT, ctrl) ) {
+ /* this might be a typo and the user has given a password
+ instead of a username. Careful with this. */
+ _log_err(LOG_ALERT, "check pass; user (%s) unknown", name);
+ } else {
+ _log_err(LOG_ALERT, "check pass; user unknown");
+ }
+ (void) pwdb_delete(&pw);
+ p = NULL;
+ return PAM_USER_UNKNOWN;
+ }
+
+ /*
+ * courtesy of PWDB the password for the user is stored in
+ * encrypted form in the "passwd" entry of pw.
+ */
+
+ retval = pwdb_get_entry(pw, "passwd", &pwe);
+ if (retval != PWDB_SUCCESS) {
+ if (geteuid()) {
+ /* we are not root perhaps this is the reason? Run helper */
+ D(("running helper binary"));
+ retval = pwdb_run_helper_binary(pamh, p);
+ } else {
+ retval = PAM_AUTHINFO_UNAVAIL;
+ _log_err(LOG_ALERT, "get passwd; %s", pwdb_strerror(retval));
+ }
+ (void) pwdb_delete(&pw);
+ p = NULL;
+ return retval;
+ }
+ salt = (const char *) pwe->value;
+
+ /*
+ * XXX: Cristian, the above is not the case for RADIUS(?) Some
+ * lines should be added for RADIUS to verify the password in
+ * clear text...
+ */
+
+ if ( ( !salt ) && ( !p ) ) {
+
+ /* the stored password is NULL */
+
+ (void) pwdb_entry_delete(&pwe);
+ (void) pwdb_delete(&pw);
+
+ if ( off(UNIX__NONULL, ctrl ) ) { /* this means we've succeeded */
+ return PAM_SUCCESS;
+ } else {
+ return PAM_AUTH_ERR;
+ }
+ }
+
+ pp = _pam_md(p, salt);
+ p = NULL; /* no longer needed here */
+
+ data_name = (char *) malloc(sizeof(FAIL_PREFIX)+strlen(name));
+ if ( data_name == NULL ) {
+ _log_err(LOG_CRIT, "no memory for data-name");
+ }
+ strcpy(data_name, FAIL_PREFIX);
+ strcpy(data_name + sizeof(FAIL_PREFIX)-1, name);
+
+ /* the moment of truth -- do we agree with the password? */
+
+ if ( strcmp( pp, salt ) == 0 ) {
+
+ retval = PAM_SUCCESS;
+ if (data_name) { /* reset failures */
+ pam_set_data(pamh, data_name, NULL, _cleanup_failures);
+ }
+
+ } else {
+
+ retval = PAM_AUTH_ERR;
+ if (data_name != NULL) {
+ struct _pam_failed_auth *new=NULL;
+ const struct _pam_failed_auth *old=NULL;
+
+ /* get a failure recorder */
+
+ new = (struct _pam_failed_auth *)
+ malloc(sizeof(struct _pam_failed_auth));
+
+ if (new != NULL) {
+
+ /* any previous failures for this user ? */
+ pam_get_data(pamh, data_name, (const void **)&old );
+
+ if (old != NULL) {
+ new->count = old->count +1;
+ if (new->count >= UNIX_MAX_RETRIES) {
+ retval = PAM_MAXTRIES;
+ }
+ } else {
+ new->count = 1;
+ }
+ new->user = x_strdup(name);
+ new->id = getuid();
+ new->name = x_strdup(getlogin() ? getlogin():"" );
+
+ pam_set_data(pamh, data_name, new, _cleanup_failures);
+
+ } else {
+ _log_err(LOG_CRIT, "no memory for failure recorder");
+ }
+ }
+
+ }
+
+ (void) pwdb_entry_delete(&pwe);
+ (void) pwdb_delete(&pw);
+ salt = NULL;
+ _pam_delete(data_name);
+ _pam_delete(pp);
+
+ return retval;
+}
+
+/*
+ * this function obtains the name of the current user and ensures
+ * that the PAM_USER item is set to this value
+ */
+
+static int _unix_get_user(pam_handle_t *pamh, unsigned int ctrl
+ , const char *prompt, const char **user)
+{
+ int retval;
+
+ D(("called"));
+
+ retval = pam_get_user(pamh, user, prompt);
+ if (retval != PAM_SUCCESS) {
+ D(("trouble reading username"));
+ return retval;
+ }
+
+ /*
+ * Various libraries at various times have had bugs related to
+ * '+' or '-' as the first character of a user name. Don't take
+ * any chances here. Require that the username starts with an
+ * alphanumeric character.
+ */
+
+ if (!isalnum(**user)) {
+ if (on(UNIX_DEBUG,ctrl) || **user) {
+ _log_err(LOG_ERR, "bad username [%s]", *user);
+ }
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (retval == PAM_SUCCESS && on(UNIX_DEBUG,ctrl)) {
+ _log_err(LOG_DEBUG, "username [%s] obtained", *user);
+ }
+
+ return retval;
+}
+
+/*
+ * _unix_blankpasswd() is a quick check for a blank password
+ *
+ * returns TRUE if user does not have a password
+ * - to avoid prompting for one in such cases (CG)
+ */
+
+static int _unix_blankpasswd(unsigned int ctrl, const char *name)
+{
+ const struct pwdb *pw=NULL;
+ const struct pwdb_entry *pwe=NULL;
+ int retval;
+
+ D(("called"));
+
+ /*
+ * This function does not have to be too smart if something goes
+ * wrong, return FALSE and let this case to be treated somewhere
+ * else (CG)
+ */
+
+ if ( on(UNIX__NONULL, ctrl) )
+ return 0; /* will fail but don't let on yet */
+
+ /* find the user's database entry */
+
+ retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw);
+ if (retval != PWDB_SUCCESS || pw == NULL ) {
+
+ retval = 0;
+
+ } else {
+
+ /* Does this user have a password? */
+
+ retval = pwdb_get_entry(pw, "passwd", &pwe);
+ if ( retval != PWDB_SUCCESS || pwe == NULL )
+ retval = 0;
+ else if ( pwe->value == NULL || ((char *)pwe->value)[0] == '\0' )
+ retval = 1;
+ else
+ retval = 0;
+
+ }
+
+ /* tidy up */
+
+ if ( pw ) {
+ (void) pwdb_delete(&pw);
+ if ( pwe )
+ (void) pwdb_entry_delete(&pwe);
+ }
+
+ return retval;
+}
+
+/*
+ * obtain a password from the user
+ */
+
+static int _unix_read_password( pam_handle_t *pamh
+ , unsigned int ctrl
+ , const char *comment
+ , const char *prompt1
+ , const char *prompt2
+ , const char *data_name
+ , const char **pass )
+{
+ int authtok_flag;
+ int retval;
+ const char *item;
+ char *token;
+
+ D(("called"));
+
+ /*
+ * make sure nothing inappropriate gets returned
+ */
+
+ *pass = token = NULL;
+
+ /*
+ * which authentication token are we getting?
+ */
+
+ authtok_flag = on(UNIX__OLD_PASSWD,ctrl) ? PAM_OLDAUTHTOK:PAM_AUTHTOK ;
+
+ /*
+ * should we obtain the password from a PAM item ?
+ */
+
+ if ( on(UNIX_TRY_FIRST_PASS,ctrl) || on(UNIX_USE_FIRST_PASS,ctrl) ) {
+ retval = pam_get_item(pamh, authtok_flag, (const void **) &item);
+ if (retval != PAM_SUCCESS ) {
+ /* very strange. */
+ _log_err(LOG_ALERT
+ , "pam_get_item returned error to unix-read-password"
+ );
+ return retval;
+ } else if (item != NULL) { /* we have a password! */
+ *pass = item;
+ item = NULL;
+ return PAM_SUCCESS;
+ } else if (on(UNIX_USE_FIRST_PASS,ctrl)) {
+ return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
+ } else if (on(UNIX_USE_AUTHTOK, ctrl)
+ && off(UNIX__OLD_PASSWD, ctrl)) {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+
+ /*
+ * getting here implies we will have to get the password from the
+ * user directly.
+ */
+
+ {
+ struct pam_message msg[3],*pmsg[3];
+ struct pam_response *resp;
+ int i, replies;
+
+ /* prepare to converse */
+
+ if ( comment != NULL && off(UNIX__QUIET, ctrl) ) {
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = comment;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = prompt1;
+ replies = 1;
+
+ if ( prompt2 != NULL ) {
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = prompt2;
+ ++replies;
+ }
+
+ /* so call the conversation expecting i responses */
+ resp = NULL;
+ retval = converse(pamh, ctrl, i, pmsg, &resp);
+
+ if (resp != NULL) {
+
+ /* interpret the response */
+
+ if (retval == PAM_SUCCESS) { /* a good conversation */
+
+ token = x_strdup(resp[i-replies].resp);
+ if (token != NULL) {
+ if (replies == 2) {
+
+ /* verify that password entered correctly */
+ if (!resp[i-1].resp
+ || strcmp(token,resp[i-1].resp)) {
+ token = _pam_delete(token); /* mistyped */
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ make_remark(pamh, ctrl
+ , PAM_ERROR_MSG, MISTYPED_PASS);
+ }
+ }
+
+ } else {
+ _log_err(LOG_NOTICE
+ , "could not recover authentication token");
+ }
+
+ }
+
+ /*
+ * tidy up the conversation (resp_retcode) is ignored
+ * -- what is it for anyway? AGM
+ */
+
+ _pam_drop_reply(resp, i);
+
+ } else {
+ retval = (retval == PAM_SUCCESS)
+ ? PAM_AUTHTOK_RECOVER_ERR:retval ;
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ if ( on(UNIX_DEBUG,ctrl) )
+ _log_err(LOG_DEBUG,"unable to obtain a password");
+ return retval;
+ }
+
+ /* 'token' is the entered password */
+
+ if ( off(UNIX_NOT_SET_PASS, ctrl) ) {
+
+ /* we store this password as an item */
+
+ retval = pam_set_item(pamh, authtok_flag, token);
+ token = _pam_delete(token); /* clean it up */
+ if ( retval != PAM_SUCCESS
+ || (retval = pam_get_item(pamh, authtok_flag
+ , (const void **)&item))
+ != PAM_SUCCESS ) {
+
+ _log_err(LOG_CRIT, "error manipulating password");
+ return retval;
+
+ }
+
+ } else {
+ /*
+ * then store it as data specific to this module. pam_end()
+ * will arrange to clean it up.
+ */
+
+ retval = pam_set_data(pamh, data_name, (void *) token, _cleanup);
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_CRIT, "error manipulating password data [%s]"
+ , pam_strerror(pamh, retval) );
+ token = _pam_delete(token);
+ return retval;
+ }
+ item = token;
+ token = NULL; /* break link to password */
+ }
+
+ *pass = item;
+ item = NULL; /* break link to password */
+
+ return PAM_SUCCESS;
+}
+
+static int _pam_unix_approve_pass(pam_handle_t *pamh
+ , unsigned int ctrl
+ , const char *pass_old
+ , const char *pass_new)
+{
+ D(("&new=%p, &old=%p",pass_old,pass_new));
+ D(("new=[%s]",pass_new));
+ D(("old=[%s]",pass_old));
+
+ if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) {
+ if ( on(UNIX_DEBUG, ctrl) ) {
+ _log_err(LOG_DEBUG, "bad authentication token");
+ }
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
+ "No password supplied":"Password unchanged" );
+ return PAM_AUTHTOK_ERR;
+ }
+
+ /*
+ * if one wanted to hardwire authentication token strength
+ * checking this would be the place - AGM
+ */
+
+ return PAM_SUCCESS;
+}
+
+/* ****************************************************************** *
+ * Copyright (c) Andrew G. Morgan, <morgan@parc.power.net> 1996.
+ * Copyright (c) Alex O. Yuriev, 1996.
+ * Copyright (c) Cristian Gafton 1996.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
diff --git a/contrib/libpam/modules/pam_radius/Makefile b/contrib/libpam/modules/pam_radius/Makefile
new file mode 100644
index 000000000000..a74b911f4e3b
--- /dev/null
+++ b/contrib/libpam/modules/pam_radius/Makefile
@@ -0,0 +1,99 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# Created by Cristian Gafton <gafton@redhat.com> 1996/09/10
+#
+# STATIC modules are not supported
+#
+
+TITLE=pam_radius
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/radius.conf
+export CONFILE
+
+ifeq ($(HAVE_PWDBLIB),yes)
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+#LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+#static/%.o : %.c
+# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+#ifdef STATIC
+#LIBSTATIC = lib$(TITLE).o
+#endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+#ifdef STATIC
+# $(MKDIR) ./static
+#endif
+
+register:
+#ifdef STATIC
+# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+#endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) -lpwdb
+endif
+
+#ifdef STATIC
+#$(LIBOBJS): $(LIBSRC)
+#
+#$(LIBSTATIC): $(LIBOBJS)
+# $(LD) -r -o $@ $(LIBOBJS) -lpwdb
+#endif
+
+install: all
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+else
+
+include ../dont_makefile
+
+endif
diff --git a/contrib/libpam/modules/pam_radius/README b/contrib/libpam/modules/pam_radius/README
new file mode 100644
index 000000000000..253308fdbdda
--- /dev/null
+++ b/contrib/libpam/modules/pam_radius/README
@@ -0,0 +1,58 @@
+
+pam_radius module:
+ RADIUS session module.
+
+WHAT IT DOES:
+ This module is intended to provide the session service for users
+autheticated with a RADIUS server. At the present stage, the only option
+supported is the use of the RADIUS server as an accounting server. There are
+few things which needs to be cleared out first in the PAM project until one
+will be able to use this module and expect it to magically start pppd in
+response to a RADIUS server command to use PPP for this user, or to initiate
+a telnet connection to another host, or to hang and call back the user using
+parameters provided in the RADIUS server response. Most of these things are
+better suited for the radius login application. I hope to make available
+Real Soon (tm) patches for the login apps to make it work this way.
+
+
+ARGUMENTS RECOGNIZED:
+ debug verbose logging
+
+MODULE SERVICES PROVIDED:
+ session _open_session and _close_session
+
+ When opening a session, this module sends an Accounting-Start
+message to the RADIUS server, which will log/update/whatever a database for
+this user. On close, an Accounting-Stop message is sent to the RADIUS
+server.
+
+This module have no other pre-requisites for making it work. One can install
+a RADIUS server just for fun and use it as a centralized accounting server and
+forget about wtmp/last/sac&comp :-)
+
+USAGE:
+ For the services you need this module (login for example) put
+ the following line in /etc/pam.conf as the last line for that
+ service (usually after the pam_unix session line):
+
+ login session required /lib/security/pam_radius.so
+
+ Replace "login" for each service you are using this module.
+
+ This module make extensive use of the API provided in libpwdb
+ 0.54preB or later. By default, it will read the radius server
+ configuration (hostname and secret) from /etc/raddb/server. This is
+ a default compiled into libpwdb, and curently there is no way to
+ modify this default without recompiling libpwdb. I am working on
+ extending the radius support from libpwdb to provide a possibility
+ to make this runtime-configurable.
+
+ Also please note that libpwdb will require also the RADIUS
+ dictionary to be present (/etc/raddb/dictionary).
+
+TODO:
+ The work is far from complete. Deal with "real" session things.
+
+AUTHOR:
+ Cristian Gafton <gafton@redhat.com>
+
diff --git a/contrib/libpam/modules/pam_radius/pam_radius.c b/contrib/libpam/modules/pam_radius/pam_radius.c
new file mode 100644
index 000000000000..b412edf95828
--- /dev/null
+++ b/contrib/libpam/modules/pam_radius/pam_radius.c
@@ -0,0 +1,193 @@
+/*
+ * pam_radius
+ * Process an user session according to a RADIUS server response
+ *
+ * 1.0 - initial release - Linux ONLY
+ * 1.1 - revised and reorganized for libpwdb 0.54preB or higher
+ * - removed the conf= parameter, since we use libpwdb exclusively now
+ *
+ * See end for Copyright information
+ */
+
+#if !(defined(linux))
+#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!!
+#endif
+
+/* Module defines */
+#define BUFFER_SIZE 1024
+#define LONG_VAL_PTR(ptr) ((*(ptr)<<24)+(*((ptr)+1)<<16)+(*((ptr)+2)<<8)+(*((ptr)+3)))
+
+#define PAM_SM_SESSION
+
+#include "pam_radius.h"
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+static time_t session_time;
+
+/* we need to save these from open_session to close_session, since
+ * when close_session will be called we won't be root anymore and
+ * won't be able to access again the radius server configuration file
+ * -- cristiang */
+
+static RADIUS_SERVER rad_server;
+static char hostname[BUFFER_SIZE];
+static char secret[BUFFER_SIZE];
+
+/* logging */
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_radius", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 0x0001
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+/* now the session stuff */
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval;
+ char *user_name;
+ int ctrl;
+
+ ctrl = _pam_parse(argc, argv);
+ retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
+ if ( user_name == NULL || retval != PAM_SUCCESS ) {
+ _pam_log(LOG_CRIT, "open_session - error recovering username");
+ return PAM_SESSION_ERR;
+ }
+
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "starting RADIUS user session for '%s'",
+ user_name);
+
+ retval = get_server_entries(hostname, secret);
+ if ((retval != PWDB_RADIUS_SUCCESS) ||
+ !strlen(hostname) || !strlen(secret)) {
+ _pam_log(LOG_CRIT, "Could not determine the radius server to talk to");
+ return PAM_IGNORE;
+ }
+ session_time = time(NULL);
+ rad_server.hostname = hostname;
+ rad_server.secret = secret;
+ retval = radius_acct_start(rad_server, user_name);
+ if (retval != PWDB_RADIUS_SUCCESS) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "ERROR communicating with the RADIUS server");
+ return PAM_IGNORE;
+ }
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ctrl;
+ char *user_name;
+ int retval;
+
+ ctrl = _pam_parse(argc, argv);
+ retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
+ if ( user_name == NULL || retval != PAM_SUCCESS ) {
+ _pam_log(LOG_CRIT, "open_session - error recovering username");
+ return PAM_SESSION_ERR;
+ }
+
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "closing RADIUS user session for '%s'",
+ user_name);
+
+ if (!strlen(hostname) || !strlen(secret)) {
+ _pam_log(LOG_CRIT, "Could not determine the radius server to talk to");
+ return PAM_IGNORE;
+ }
+ retval = radius_acct_stop(rad_server, user_name,
+ time(NULL) - session_time);
+ if (retval != PWDB_RADIUS_SUCCESS) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "ERROR communicating with the RADIUS server");
+ return PAM_IGNORE;
+ }
+
+ return PAM_SUCCESS;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_radius_modstruct = {
+ "pam_radius",
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ NULL
+};
+#endif
+
+/*
+ * Copyright (c) Cristian Gafton, 1996, <gafton@redhat.com>
+ * All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/contrib/libpam/modules/pam_radius/pam_radius.h b/contrib/libpam/modules/pam_radius/pam_radius.h
new file mode 100644
index 000000000000..72b1da8aa0cb
--- /dev/null
+++ b/contrib/libpam/modules/pam_radius/pam_radius.h
@@ -0,0 +1,35 @@
+
+#ifndef PAM_RADIUS_H
+#define PAM_RADIUS_H
+
+#define _GNU_SOURCE
+#include <features.h>
+
+#include <stdio.h>
+#define __USE_POSIX2
+
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <utmp.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <netinet/in.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpc/rpc.h>
+
+#include <pwdb/radius.h>
+#include <pwdb/pwdb_radius.h>
+
+/******************************************************************/
+
+#endif /* PAM_RADIUS_H */
diff --git a/contrib/libpam/modules/pam_rhosts/Makefile b/contrib/libpam/modules/pam_rhosts/Makefile
new file mode 100644
index 000000000000..93addbb68119
--- /dev/null
+++ b/contrib/libpam/modules/pam_rhosts/Makefile
@@ -0,0 +1,94 @@
+# This Makefile controls a build process of the pam_rhosts modules
+# for Linux-PAM. You should not modify this Makefile.
+
+LIBAUTHOBJ = pam_rhosts_auth.o
+LIBAUTHSRC = pam_rhosts_auth.c
+LIBSESSOBJ =
+LIBSESSSRC =
+LIBPASSWDSRC =
+LIBPASSWDOBJ =
+LIBOBJ = $(LIBAUTHOBJ) $(LIBSESSOBJ) $(LIBPASSWDOBJ)
+LIBSRC = $(LIBAUTHSRC) $(LIBSESSSRC) $(LIBPASSWDSRC)
+
+ifdef STATIC
+LIBSTATIC = libpam_rhosts.o
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+endif
+
+ifdef DYNAMIC
+LIBSESSSH =
+LIBAUTHSH = pam_rhosts_auth.so
+LIBPASSWDSH =
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBSHARED = $(LIBSESSSH) $(LIBAUTHSH) $(LIBPASSWDSH)
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; \
+ ./register_static pam_rhosts_auth pam_rhosts/libpam_rhosts.o )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+endif
+
+ifdef DYNAMIC
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+endif
+
+ifdef STATIC
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+
+endif
+
+#.c.o:
+# $(CC) -c $(CFLAGS) $<
+
+install: all
+ifdef DYNAMIC
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+# tidy up
+
+remove:
+ cd $(FAKEROOT)$(SECUREDIR) && rm -f $(LIBSHARED)
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) a.out core *~
+
+extraclean:
+ rm -f *.a *.out *.o *.so *.bak dynamic/* static/*
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
diff --git a/contrib/libpam/modules/pam_rhosts/README b/contrib/libpam/modules/pam_rhosts/README
new file mode 100644
index 000000000000..527dfd3864d9
--- /dev/null
+++ b/contrib/libpam/modules/pam_rhosts/README
@@ -0,0 +1,57 @@
+arguments recognized:
+
+"no_hosts_equiv"
+"no_rhosts"
+"debug"
+"nowarn"
+"suppress"
+"promiscuous"
+
+.rhosts/hosts.equiv format:
+
+There are positive entries, when one is matched authentication
+succeeds and terminates. There are negative entries, when one is
+matched authentication fails and terminates. Thus order is
+significant.
+
+Entry hosts.equiv .rhosts
+<host> All users on <host> are ok Same username from <host> is ok
+<host> <user> <user> from <host> is ok ditto
+-<host> No users from <host> are ok ditto
+<host> -<user> <user> from <host> is not ok ditto
+
+<host> can be ip (IPv4) numbers.
+
+Netgroups may be used in either host or user fields, and then applies
+to all hosts, or users, in the netgroup. The syntax is
+
+ +@<ng>
+
+The entries
+
+ <host> +@<ng>
+ +@<ng> +@<ng>
+ +@<ng> <user>
+
+means exactly what you think it does. Negative entries are of the
+form
+
+ -@<ng>
+
+When the "promiscuous" option is given the special character + may be
+used as a wildcard in any field.
+
+ + Allow anyone from any host to connect. DANGEROUS.
+ + + Ditto.
+ + <user> Allow the user to connect from anywhere. DANGEROUS.
+ <host> + Allow any user from the host. Dangerous.
+
+These, perhaps more usefull, forms of the + form is also disallowed
+unless "promiscuous" is specified:
+
+ + -<user> Disallow the user from any host
+ + -@<ng> Disallow all members of the netgroup from any host
+
+When "promiscuous" is not specified a '+' is handled as a negative
+match.
+
diff --git a/contrib/libpam/modules/pam_rhosts/pam_rhosts_auth.c b/contrib/libpam/modules/pam_rhosts/pam_rhosts_auth.c
new file mode 100644
index 000000000000..10dfcf797119
--- /dev/null
+++ b/contrib/libpam/modules/pam_rhosts/pam_rhosts_auth.c
@@ -0,0 +1,788 @@
+/*----------------------------------------------------------------------
+ * Modified for Linux-PAM by Al Longyear <longyear@netcom.com> 96/5/5
+ * Modifications, Cristian Gafton 97/2/8
+ * Modifications, Peter Allgeyer 97/3
+ * Modifications (netgroups and fixes), Nicolai Langfeldt 97/3/21
+ * Security fix: 97/10/2 - gethostbyname called repeatedly without care
+ * Modification (added privategroup option) Andrew <morgan@transmeta.com>
+ *----------------------------------------------------------------------
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#define _BSD_SOURCE
+
+#define USER_RHOSTS_FILE "/.rhosts" /* prefixed by user's home dir */
+
+#ifdef linux
+#include <endian.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h> /* This is supposed(?) to contain the following */
+int innetgr(const char *, const char *, const char *,const char *);
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#ifndef MAXDNAME
+#define MAXDNAME 256
+#endif
+
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <net/if.h>
+#ifdef linux
+# include <linux/sockios.h>
+# ifndef __USE_MISC
+# define __USE_MISC
+# include <sys/fsuid.h>
+# endif /* __USE_MISC */
+#endif
+
+#include <pwd.h>
+#include <grp.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#ifndef _PATH_HEQUIV
+#define _PATH_HEQUIV "/etc/hosts.equiv"
+#endif /* _PATH_HEQUIV */
+
+#define PAM_SM_AUTH /* only defines this management group */
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+/* to the best of my knowledge, all modern UNIX boxes have 32 bit integers */
+#define U32 unsigned int
+
+
+/*
+ * Options for this module
+ */
+
+struct _options {
+ int opt_no_hosts_equiv;
+ int opt_no_rhosts;
+ int opt_debug;
+ int opt_nowarn;
+ int opt_disallow_null_authtok;
+ int opt_silent;
+ int opt_promiscuous;
+ int opt_suppress;
+ int opt_private_group;
+ const char *last_error;
+};
+
+/* logging */
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_rhosts_auth", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+static void set_option (struct _options *opts, const char *arg)
+{
+ if (strcmp(arg, "no_hosts_equiv") == 0) {
+ opts->opt_no_hosts_equiv = 1;
+ return;
+ }
+
+ if (strcmp(arg, "no_rhosts") == 0) {
+ opts->opt_no_rhosts = 1;
+ return;
+ }
+
+ if (strcmp(arg, "debug") == 0) {
+ D(("debugging enabled"));
+ opts->opt_debug = 1;
+ return;
+ }
+
+ if (strcmp(arg, "no_warn") == 0) {
+ opts->opt_nowarn = 1;
+ return;
+ }
+
+ if (strcmp(arg, "promiscuous") == 0) {
+ opts->opt_promiscuous = 1; /* used to permit '+' in ...hosts file */
+ return;
+ }
+
+ if (strcmp(arg, "suppress") == 0) {
+ opts->opt_suppress = 1; /* used to suppress failure warning message */
+ return;
+ }
+
+ if (strcmp(arg, "privategroup") == 0) {
+ opts->opt_private_group = 1; /* used to permit group write on .rhosts
+ file if group has same name as owner */
+ return;
+ }
+
+ /*
+ * All other options are ignored at the present time.
+ */
+ _pam_log(LOG_WARNING, "unrecognized option '%s'", arg);
+}
+
+static void set_parameters (struct _options *opts, int flags,
+ int argc, const char **argv)
+{
+ opts->opt_silent = flags & PAM_SILENT;
+ opts->opt_disallow_null_authtok = flags & PAM_DISALLOW_NULL_AUTHTOK;
+
+ while (argc-- > 0) {
+ set_option (opts, *argv);
+ ++argv;
+ }
+}
+
+/*
+ * Obtain the name of the remote host. Currently, this is simply by
+ * requesting the contents of the PAM_RHOST item.
+ */
+
+static int pam_get_rhost(pam_handle_t *pamh, const char **rhost
+ , const char *prompt)
+{
+ int retval;
+ const char *current;
+
+ retval = pam_get_item (pamh, PAM_RHOST, (const void **)&current);
+ if (retval != PAM_SUCCESS)
+ return retval;
+
+ if (current == NULL) {
+ return PAM_AUTH_ERR;
+ }
+ *rhost = current;
+
+ return retval; /* pass on any error from conversation */
+}
+
+/*
+ * Obtain the name of the remote user. Currently, this is simply by
+ * requesting the contents of the PAM_RUSER item.
+ */
+
+static int pam_get_ruser(pam_handle_t *pamh, const char **ruser
+ , const char *prompt)
+{
+ int retval;
+ const char *current;
+
+ retval = pam_get_item (pamh, PAM_RUSER, (const void **)&current);
+ if (retval != PAM_SUCCESS)
+ return retval;
+
+ if (current == NULL) {
+ return PAM_AUTH_ERR;
+ }
+ *ruser = current;
+
+ return retval; /* pass on any error from conversation */
+}
+
+/*
+ * Returns 1 if positive match, 0 if no match, -1 if negative match.
+ */
+
+static int
+__icheckhost (pam_handle_t *pamh, struct _options *opts, U32 raddr
+ , register char *lhost, const char *rhost)
+{
+ struct hostent *hp;
+ U32 laddr;
+ int negate=1; /* Multiply return with this to get -1 instead of 1 */
+ char **pp, *user;
+
+ /* Check nis netgroup. We assume that pam has done all needed
+ paranoia checking before we are handed the rhost */
+ if (strncmp("+@",lhost,2) == 0)
+ return(innetgr(&lhost[2],rhost,NULL,NULL));
+
+ if (strncmp("-@",lhost,2) == 0)
+ return(-innetgr(&lhost[2],rhost,NULL,NULL));
+
+ /* -host */
+ if (strncmp("-",lhost,1) == 0) {
+ negate=-1;
+ lhost++;
+ } else if (strcmp("+",lhost) == 0) {
+ (void) pam_get_item(pamh, PAM_USER, (const void **)&user);
+ D(("user %s has a `+' host entry", user));
+ if (opts->opt_promiscuous)
+ return (1); /* asking for trouble, but ok.. */
+ /* If not promiscuous: handle as negative */
+ return (-1);
+ }
+
+ /* Try for raw ip address first. */
+ if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1)
+ return (negate*(! (raddr ^ laddr)));
+
+ /* Better be a hostname. */
+ hp = gethostbyname(lhost);
+ if (hp == NULL)
+ return (0);
+
+ /* Spin through ip addresses. */
+ for (pp = hp->h_addr_list; *pp; ++pp)
+ if (!memcmp (&raddr, *pp, sizeof (U32)))
+ return (negate);
+
+ /* No match. */
+ return (0);
+}
+
+/* Returns 1 on positive match, 0 on no match, -1 on negative match */
+
+static int __icheckuser(pam_handle_t *pamh, struct _options *opts
+ , const char *luser, const char *ruser
+ , const char *rhost)
+{
+ /*
+ luser is user entry from .rhosts/hosts.equiv file
+ ruser is user id on remote host
+ rhost is the remote host name
+ */
+ char *user;
+
+ /* [-+]@netgroup */
+ if (strncmp("+@",luser,2) == 0)
+ return (innetgr(&luser[2],NULL,ruser,NULL));
+
+ if (strncmp("-@",luser,2) == 0)
+ return (-innetgr(&luser[2],NULL,ruser,NULL));
+
+ /* -user */
+ if (strncmp("-",luser,1) == 0)
+ return(-(strcmp(&luser[1],ruser) == 0));
+
+ /* + */
+ if (strcmp("+",luser) == 0) {
+ (void) pam_get_item(pamh, PAM_USER, (const void **)&user);
+ _pam_log(LOG_WARNING, "user %s has a `+' user entry", user);
+ if (opts->opt_promiscuous)
+ return(1);
+ /* If not promiscuous we handle it as a negative match */
+ return(-1);
+ }
+
+ /* simple string match */
+ return (strcmp(ruser, luser) == 0);
+}
+
+/*
+ * Returns 1 for blank lines (or only comment lines) and 0 otherwise
+ */
+
+static int __isempty(char *p)
+{
+ while (*p && isspace(*p)) {
+ ++p;
+ }
+
+ return (*p == '\0' || *p == '#') ? 1:0 ;
+}
+
+/*
+ * Returns 0 if positive match, 1 if _not_ ok.
+ */
+
+static int
+__ivaliduser (pam_handle_t *pamh, struct _options *opts,
+ FILE *hostf, U32 raddr,
+ const char *luser, const char *ruser, const char *rhost)
+{
+ register const char *user;
+ register char *p;
+ int hcheck, ucheck;
+ char buf[MAXHOSTNAMELEN + 128]; /* host + login */
+
+ buf[sizeof (buf)-1] = '\0'; /* terminate line */
+
+ while (fgets(buf, sizeof(buf), hostf) != NULL) { /* hostf file line */
+ p = buf; /* from beginning of file.. */
+
+ /* Skip empty or comment lines */
+ if (__isempty(p)) {
+ continue;
+ }
+
+ /* Skip lines that are too long. */
+ if (strchr(p, '\n') == NULL) {
+ int ch = getc(hostf);
+
+ while (ch != '\n' && ch != EOF)
+ ch = getc(hostf);
+ continue;
+ }
+
+ /*
+ * If there is a hostname at the start of the line. Set it to
+ * lower case. A leading ' ' or '\t' indicates no hostname
+ */
+
+ for (;*p && !isspace(*p); ++p) {
+ *p = tolower(*p);
+ }
+
+ /*
+ * next we want to find the permitted name for the remote user
+ */
+
+ if (*p == ' ' || *p == '\t') {
+
+ /* <nul> terminate hostname and skip spaces */
+ for (*p++='\0'; *p && isspace(*p); ++p);
+
+ user = p; /* this is the user's name */
+ while (*p && !isspace(*p))
+ ++p; /* find end of user's name */
+ } else
+ user = p;
+
+ *p = '\0'; /* <nul> terminate username (+host?) */
+
+ /* buf -> host(?) ; user -> username(?) */
+
+ /* First check host part */
+ hcheck=__icheckhost(pamh, opts, raddr, buf, rhost);
+
+ if (hcheck<0)
+ return(1);
+
+ if (hcheck) {
+ /* Then check user part */
+ if (! (*user))
+ user = luser;
+
+ ucheck=__icheckuser(pamh, opts, user, ruser, rhost);
+
+ /* Positive 'host user' match? */
+ if (ucheck>0)
+ return(0);
+
+ /* Negative 'host -user' match? */
+ if (ucheck<0)
+ return(1);
+
+ /* Neither, go on looking for match */
+ }
+ }
+
+ return (1);
+}
+
+/*
+ * New .rhosts strategy: We are passed an ip address. We spin through
+ * hosts.equiv and .rhosts looking for a match. When the .rhosts only
+ * has ip addresses, we don't have to trust a nameserver. When it
+ * contains hostnames, we spin through the list of addresses the nameserver
+ * gives us and look for a match.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+
+static int
+pam_iruserok(pam_handle_t *pamh,
+ struct _options *opts, U32 raddr, int superuser,
+ const char *ruser, const char *luser, const char *rhost)
+{
+ const char *cp;
+ struct stat sbuf;
+ struct passwd *pwd;
+ FILE *hostf;
+ uid_t uid;
+ int answer;
+ char pbuf[MAXPATHLEN]; /* potential buffer overrun */
+
+ if ( !superuser && !opts->opt_no_hosts_equiv ) {
+
+ /* try to open system hosts.equiv file */
+ hostf = fopen (_PATH_HEQUIV, "r");
+ if (hostf) {
+ answer = __ivaliduser(pamh, opts, hostf, raddr, luser
+ , ruser, rhost);
+ (void) fclose(hostf);
+ if (answer == 0)
+ return 0; /* remote host is equivalent to localhost */
+ } /* else {
+ No hosts.equiv file on system.
+ } */
+ }
+
+ if ( opts->opt_no_rhosts )
+ return 1;
+
+ /*
+ * Identify user's local .rhosts file
+ */
+
+ pwd = getpwnam(luser);
+ if (pwd == NULL) {
+ /*
+ * luser is assumed to be valid because of an earlier check for uid = 0
+ * we don't log this error twice. However, this shouldn't happen !
+ * --cristiang
+ */
+ return(1);
+ }
+
+ /* check for buffer overrun */
+ if (strlen(pwd->pw_dir) + sizeof(USER_RHOSTS_FILE) + 2 >= MAXPATHLEN) {
+ if (opts->opt_debug)
+ _pam_log(LOG_DEBUG,"home directory for `%s' is too long", luser);
+ return 1; /* to dangerous to try */
+ }
+
+ (void) strcpy(pbuf, pwd->pw_dir);
+ (void) strcat(pbuf, USER_RHOSTS_FILE);
+
+ /*
+ * Change effective uid while _reading_ .rhosts. (not just
+ * opening). If root and reading an NFS mounted file system,
+ * can't read files that are 0600 as .rhosts files should be.
+ */
+
+ /* We are root, this will not fail */
+#ifdef linux
+ /* If we are on linux the better way is setfsuid */
+ uid = setfsuid(pwd->pw_uid);
+ hostf = fopen(pbuf, "r");
+#else
+ uid = geteuid();
+ (void) seteuid(pwd->pw_uid);
+ hostf = fopen(pbuf, "r");
+#endif
+
+ if (hostf == NULL) {
+ if (opts->opt_debug)
+ _pam_log(LOG_DEBUG,"Could not open %s file",pbuf);
+ answer = 1;
+ goto exit_function;
+ }
+
+ /*
+ * If not a regular file, or is owned by someone other than
+ * user or root or if writeable by anyone but the owner, quit.
+ */
+
+ cp = NULL;
+ if (lstat(pbuf, &sbuf) < 0 || !S_ISREG(sbuf.st_mode))
+ cp = ".rhosts not regular file";
+ else if (fstat(fileno(hostf), &sbuf) < 0)
+ cp = ".rhosts fstat failed";
+ else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
+ cp = "bad .rhosts owner";
+ else if (sbuf.st_mode & S_IWOTH)
+ cp = ".rhosts writable by other!";
+ else if (sbuf.st_mode & S_IWGRP) {
+
+ /* private group caveat */
+ if (opts->opt_private_group) {
+ struct group *grp = getgrgid(sbuf.st_gid);
+
+ if (NULL == grp || NULL == grp->gr_name
+ || strcmp(luser,grp->gr_name)) {
+ cp = ".rhosts writable by public group";
+ } else if (grp->gr_mem) {
+ int gcount;
+
+ /* require at most one member (luser) of this group */
+ for (gcount=0; grp->gr_mem[gcount]; ++gcount) {
+ if (strcmp(grp->gr_mem[gcount], luser)) {
+ gcount = -1;
+ break;
+ }
+ }
+ if (gcount < 0) {
+ cp = ".rhosts writable by other members of group";
+ }
+ }
+ } else {
+ cp = ".rhosts writable by group";
+ }
+
+ } /* It is _NOT_ safe to append an else here... Do so prior to
+ * S_IWGRP check */
+
+ /* If there were any problems, quit. */
+ if (cp) {
+ opts->last_error = cp;
+ answer = 1;
+ goto exit_function;
+ }
+
+ answer = __ivaliduser (pamh, opts, hostf, raddr, luser, ruser, rhost);
+
+exit_function:
+ /*
+ * Go here to exit after the fsuid/euid has been adjusted so that
+ * they are reset before we exit.
+ */
+
+#ifdef linux
+ setfsuid(uid);
+#else
+ (void)seteuid(uid);
+#endif
+
+ if (hostf != NULL)
+ (void) fclose(hostf);
+
+ return answer;
+}
+
+static int
+pam_ruserok (pam_handle_t *pamh,
+ struct _options *opts, const char *rhost, int superuser,
+ const char *ruser, const char *luser)
+{
+ struct hostent *hp;
+ int answer = 1; /* default to failure */
+ U32 *addrs;
+ int n, i;
+
+ opts->last_error = (char *) 0;
+ hp = gethostbyname(rhost); /* identify host */
+
+ if (hp != NULL) {
+ /* First of all check the address length */
+ if (hp->h_length != 4) {
+ _pam_log(LOG_ALERT, "pam_rhosts module can't work with not IPv4 "
+ "addresses");
+ return 1; /* not allowed */
+ }
+
+ /* loop though address list */
+ for (n = 0; hp->h_addr_list[n]; n++);
+ D(("rhosts: %d addresses", n));
+
+ if (n) {
+ addrs = calloc (n, hp->h_length);
+ for (i = 0; i < n; i++)
+ memcpy (addrs+i, hp->h_addr_list[i], hp->h_length);
+
+ for (i = 0; i < n && answer; i++) {
+ D(("rhosts: address %d is %04x", i, addrs[i]));
+ answer = pam_iruserok(pamh, opts, addrs[i], superuser,
+ ruser, luser, rhost);
+ /* answer == 0 means success */
+ }
+
+ free (addrs);
+ }
+ }
+
+ return answer;
+}
+
+/*
+ * Internal function to do authentication
+ */
+
+static int _pam_auth_rhosts (pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv)
+{
+ int retval;
+ const char *luser;
+ const char *ruser,*rhost;
+ struct _options opts;
+ int as_root = 0;
+ /*
+ * Look at the options and set the flags accordingly.
+ */
+ memset (&opts, 0, sizeof (opts));
+ set_parameters (&opts, flags, argc, argv);
+ /*
+ * Obtain the parameters for the various items
+ */
+ for (;;) { /* abuse loop to avoid goto */
+
+ /* get the remotehost */
+ retval = pam_get_rhost(pamh, &rhost, NULL);
+ (void) pam_set_item(pamh, PAM_RHOST, rhost);
+ if (retval != PAM_SUCCESS) {
+ if (opts.opt_debug) {
+ _pam_log(LOG_DEBUG, "could not get the remote host name");
+ }
+ break;
+ }
+
+ /* get the remote user */
+ retval = pam_get_ruser(pamh, &ruser, NULL);
+ (void) pam_set_item(pamh, PAM_RUSER, ruser);
+ if (retval != PAM_SUCCESS) {
+ if (opts.opt_debug)
+ _pam_log(LOG_DEBUG, "could not get the remote username");
+ break;
+ }
+
+ /* get the local user */
+ retval = pam_get_user(pamh, &luser, NULL);
+
+ if (retval != PAM_SUCCESS) {
+ if (opts.opt_debug)
+ _pam_log(LOG_DEBUG, "could not determine name of local user");
+ break;
+ }
+
+ /* check if the luser uid == 0... --cristiang */
+ {
+ struct passwd *luser_pwd;
+
+ luser_pwd = getpwnam(luser);
+ if (luser_pwd == NULL) {
+ if (opts.opt_debug)
+ _pam_log(LOG_DEBUG, "user '%s' unknown to this system",
+ luser);
+ retval = PAM_AUTH_ERR;
+ break;
+ }
+ if (luser_pwd->pw_uid == 0)
+ as_root = 1;
+ luser_pwd = NULL; /* forget */
+ }
+/*
+ * Validate the account information.
+ */
+ if (pam_ruserok (pamh, &opts, rhost, as_root, ruser, luser) != 0) {
+ if ( !opts.opt_suppress ) {
+ _pam_log(LOG_WARNING, "denied to %s@%s as %s: %s",
+ ruser, rhost, luser, (opts.last_error==NULL) ?
+ "access not allowed":opts.last_error);
+ }
+ retval = PAM_AUTH_ERR;
+ } else {
+ _pam_log(LOG_NOTICE, "allowed to %s@%s as %s",
+ ruser, rhost, luser);
+ }
+ break;
+ }
+
+ return retval;
+}
+
+/* --- authentication management functions --- */
+
+PAM_EXTERN
+int pam_sm_authenticate (pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv)
+{
+ int retval;
+
+ if (sizeof(U32) != 4) {
+ _pam_log (LOG_ALERT, "pam_rhosts module can\'t work on this hardware "
+ "(yet)");
+ return PAM_AUTH_ERR;
+ }
+ sethostent(1);
+ retval = _pam_auth_rhosts (pamh, flags, argc, argv);
+ endhostent();
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc,
+ const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+/* end of module definition */
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_rhosts_auth_modstruct = {
+ "pam_rhosts_auth",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/*
+ * $Log: pam_rhosts_auth.c,v $
+ * Revision 1.12 1997/09/27 14:34:01 morgan
+ * fixed comment and renamed iruserok to pam_iruserok.
+ *
+ * Revision 1.11 1997/04/05 06:26:39 morgan
+ * fairly major fixes and enhancements (see CHANGELOG for 0.57 release)
+ *
+ * Revision 1.10 1997/02/09 02:09:30 morgan
+ * - implementation of 'debug' argument (Cristian Gafton)
+ * - we check for uid=0 accounts instead of hardcoded 'root' (Cristian Gafton)
+ *
+ * Revision 1.9 1996/12/01 03:09:47 morgan
+ * *** empty log message ***
+ *
+ * Revision 1.8 1996/11/12 06:08:59 morgan
+ * Oliver Crow's "rootok" patch plus a little clean up of set_option
+ * (AGM)
+ *
+ * Revision 1.7 1996/11/10 20:15:56 morgan
+ * cross platform support
+ *
+ * Revision 1.6 1996/08/09 05:46:29 morgan
+ * removed code for manually setting the remote username etc..
+ *
+ */
diff --git a/contrib/libpam/modules/pam_rootok/Makefile b/contrib/libpam/modules/pam_rootok/Makefile
new file mode 100644
index 000000000000..b37870801193
--- /dev/null
+++ b/contrib/libpam/modules/pam_rootok/Makefile
@@ -0,0 +1,111 @@
+#
+# $Id: Makefile,v 1.7 1997/04/05 06:25:20 morgan Exp $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.7 1997/04/05 06:25:20 morgan
+# fakeroot
+#
+# Revision 1.6 1997/02/15 19:15:50 morgan
+# fixed email
+#
+# Revision 1.5 1996/11/10 20:16:10 morgan
+# cross platform support
+#
+# Revision 1.4 1996/09/05 06:29:36 morgan
+# ld --> gcc
+#
+# Revision 1.3 1996/05/26 15:47:46 morgan
+# make dynamic/static dirs!
+#
+# Revision 1.2 1996/05/26 04:04:53 morgan
+# automated static support
+#
+# Revision 1.1 1996/05/05 17:14:15 morgan
+# Initial revision
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/5/5
+#
+
+TITLE=pam_rootok
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_rootok/README b/contrib/libpam/modules/pam_rootok/README
new file mode 100644
index 000000000000..d7010dd9738d
--- /dev/null
+++ b/contrib/libpam/modules/pam_rootok/README
@@ -0,0 +1,18 @@
+# $Id: README,v 1.1 1996/05/10 04:15:31 morgan Exp $
+#
+
+this module is an authentication module that performs one task: if the
+id of the user is '0' then it returns 'PAM_SUCCESS' with the
+'sufficient' /etc/pam.conf control flag it can be used to allow
+password free access to some service for 'root'
+
+Recognized arguments:
+
+ debug write a message to syslog indicating success or
+ failure.
+
+module services provided:
+
+ auth _authetication and _setcred (blank)
+
+Andrew Morgan
diff --git a/contrib/libpam/modules/pam_rootok/pam_rootok.c b/contrib/libpam/modules/pam_rootok/pam_rootok.c
new file mode 100644
index 000000000000..21327d42e5ea
--- /dev/null
+++ b/contrib/libpam/modules/pam_rootok/pam_rootok.c
@@ -0,0 +1,118 @@
+/* pam_rootok module */
+
+/*
+ * $Id: pam_rootok.c,v 1.5 1997/02/15 17:32:47 morgan Exp $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ *
+ * $Log: pam_rootok.c,v $
+ * Revision 1.5 1997/02/15 17:32:47 morgan
+ * removed fixed syslog buffer
+ *
+ * Revision 1.4 1996/12/01 03:10:14 morgan
+ * reformatted
+ *
+ * Revision 1.3 1996/06/02 08:11:01 morgan
+ * updated for new static protocol
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-rootok", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 01
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int ctrl;
+ int retval = PAM_AUTH_ERR;
+
+ ctrl = _pam_parse(argc, argv);
+ if (getuid() == 0)
+ retval = PAM_SUCCESS;
+
+ if (ctrl & PAM_DEBUG_ARG) {
+ _pam_log(LOG_DEBUG, "authetication %s"
+ , retval==PAM_SUCCESS ? "succeeded":"failed" );
+ }
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_rootok_modstruct = {
+ "pam_rootok",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_securetty/Makefile b/contrib/libpam/modules/pam_securetty/Makefile
new file mode 100644
index 000000000000..d8a09ea13377
--- /dev/null
+++ b/contrib/libpam/modules/pam_securetty/Makefile
@@ -0,0 +1,83 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+
+TITLE=pam_securetty
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
diff --git a/contrib/libpam/modules/pam_securetty/README b/contrib/libpam/modules/pam_securetty/README
new file mode 100644
index 000000000000..1df095c96f95
--- /dev/null
+++ b/contrib/libpam/modules/pam_securetty/README
@@ -0,0 +1,9 @@
+pam_securetty:
+ Allows root logins only if the user is logging in on a
+ "secure" tty, as defined by the listing in /etc/securetty
+
+ Also checks to make sure that /etc/securetty is a plain
+ file and not world writable.
+
+ - Elliot Lee <sopwith@redhat.com>, Red Hat Software.
+ July 25, 1996.
diff --git a/contrib/libpam/modules/pam_securetty/pam_securetty.c b/contrib/libpam/modules/pam_securetty/pam_securetty.c
new file mode 100644
index 000000000000..369fb03dd060
--- /dev/null
+++ b/contrib/libpam/modules/pam_securetty/pam_securetty.c
@@ -0,0 +1,204 @@
+/* pam_securetty module */
+
+#define SECURETTY_FILE "/etc/securetty"
+#define TTY_PREFIX "/dev/"
+
+/*
+ * by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
+ * July 25, 1996.
+ * This code shamelessly ripped from the pam_rootok module.
+ * Slight modifications AGM. 1996/12/3
+ * $Log: pam_securetty.c,v $
+ * Revision 1.7 1997/04/05 06:24:23 morgan
+ * changed return value on user unknown error
+ *
+ * Revision 1.6 1997/02/15 17:30:36 morgan
+ * removed fixed length syslog buffer
+ *
+ * Revision 1.5 1997/02/09 02:22:24 morgan
+ * added "debug" flag handling (Cristian Gafton)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <pwd.h>
+#include <strings.h>
+
+#define PAM_SM_AUTH
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-securetty", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 0x0001
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int retval = PAM_AUTH_ERR;
+ const char *username;
+ char *uttyname;
+ char ttyfileline[256];
+ struct stat ttyfileinfo;
+ struct passwd *user_pwd;
+ FILE *ttyfile;
+ int ctrl;
+
+ /* parse the arguments */
+ ctrl = _pam_parse(argc, argv);
+
+ retval = pam_get_item(pamh,PAM_USER,(const void **)&username);
+ if (retval == PAM_SUCCESS)
+ retval = pam_get_item(pamh,PAM_TTY,(const void **)&uttyname);
+ if (retval != PAM_SUCCESS || uttyname == NULL) {
+ /* If we couldn't get the username or the tty return error */
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_WARNING, "can not determine tty I'm running on !");
+ return PAM_SERVICE_ERR;
+ }
+
+ /* The PAM_TTY item may be prefixed with "/dev/" - skip that */
+ if (strncmp(TTY_PREFIX, uttyname, sizeof(TTY_PREFIX)-1) == 0)
+ uttyname += sizeof(TTY_PREFIX)-1;
+
+ /* If we didn't get a username, get one */
+ if(!username || (strlen(username) <= 0)) {
+ /* Don't let them use a NULL username... */
+ (void) pam_set_item(pamh, PAM_USER, NULL);
+ pam_get_user(pamh,&username,NULL);
+ if (retval != PAM_SUCCESS || username == NULL || *username == '\0') {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_WARNING,
+ "can not determine username for this service!");
+ return PAM_SERVICE_ERR;
+ }
+ }
+
+ user_pwd = getpwnam(username);
+ if (user_pwd == NULL)
+ return PAM_IGNORE;
+ else if (user_pwd->pw_uid != 0) /* If the user is not root,
+ securetty's does not apply to them */
+ return PAM_SUCCESS;
+
+ if(stat(SECURETTY_FILE,&ttyfileinfo)) {
+ _pam_log(LOG_NOTICE,
+ "Couldn't open " SECURETTY_FILE);
+ return PAM_SUCCESS; /* for compatibility with old securetty handling,
+ this needs to succeed. But we still log the
+ error. */
+ }
+
+ if((ttyfileinfo.st_mode & S_IWOTH)
+ || !S_ISREG(ttyfileinfo.st_mode)) {
+ /* If the file is world writable or is not a
+ normal file, return error */
+ _pam_log(LOG_ERR, SECURETTY_FILE
+ " is either world writable or not a normal file");
+ return PAM_AUTH_ERR;
+ }
+
+ ttyfile = fopen(SECURETTY_FILE,"r");
+ if(ttyfile == NULL) { /* Check that we opened it successfully */
+ _pam_log(LOG_ERR,
+ "Error opening " SECURETTY_FILE);
+ return PAM_SERVICE_ERR;
+ }
+ /* There should be no more errors from here on */
+ retval=PAM_AUTH_ERR;
+ /* This loop assumes that PAM_SUCCESS == 0
+ and PAM_AUTH_ERR != 0 */
+ while((fgets(ttyfileline,sizeof(ttyfileline)-1, ttyfile) != NULL)
+ && retval) {
+ if(ttyfileline[strlen(ttyfileline) - 1] == '\n')
+ ttyfileline[strlen(ttyfileline) - 1] = '\0';
+ retval = strcmp(ttyfileline,uttyname);
+ }
+ fclose(ttyfile);
+ if(retval) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_WARNING, "access denied: tty '%s' is not secure !",
+ uttyname);
+ retval = PAM_AUTH_ERR;
+ }
+ if ((retval == PAM_SUCCESS) && (ctrl & PAM_DEBUG_ARG))
+ _pam_log(LOG_DEBUG, "access allowed for '%s' on '%s'",
+ username, uttyname);
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_securetty_modstruct = {
+ "pam_securetty",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_shells/Makefile b/contrib/libpam/modules/pam_shells/Makefile
new file mode 100644
index 000000000000..121b19a00863
--- /dev/null
+++ b/contrib/libpam/modules/pam_shells/Makefile
@@ -0,0 +1,84 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+
+TITLE=pam_shells
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_shells/README b/contrib/libpam/modules/pam_shells/README
new file mode 100644
index 000000000000..cbd5bfb55655
--- /dev/null
+++ b/contrib/libpam/modules/pam_shells/README
@@ -0,0 +1,10 @@
+pam_shells:
+ Authentication is granted if the users shell is listed in
+ /etc/shells. If no shell is in /etc/passwd (empty), the
+ /bin/sh is used (following ftpd's convention).
+
+ Also checks to make sure that /etc/shells is a plain
+ file and not world writable.
+
+ - Erik Troan <ewt@redhat.com>, Red Hat Software.
+ August 5, 1996.
diff --git a/contrib/libpam/modules/pam_shells/pam_shells.c b/contrib/libpam/modules/pam_shells/pam_shells.c
new file mode 100644
index 000000000000..edc9134b3274
--- /dev/null
+++ b/contrib/libpam/modules/pam_shells/pam_shells.c
@@ -0,0 +1,131 @@
+/* pam_securetty module */
+
+#define SHELL_FILE "/etc/shells"
+
+/*
+ * by Erik Troan <ewt@redhat.com>, Red Hat Software.
+ * August 5, 1996.
+ * This code shamelessly ripped from the pam_securetty module.
+ */
+
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <unistd.h>
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-shells", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int retval = PAM_AUTH_ERR;
+ const char *userName;
+ char *userShell;
+ char shellFileLine[256];
+ struct stat sb;
+ struct passwd * pw;
+ FILE * shellFile;
+
+ retval = pam_get_user(pamh,&userName,NULL);
+ if(retval != PAM_SUCCESS)
+ return PAM_SERVICE_ERR;
+
+ if(!userName || (strlen(userName) <= 0)) {
+ /* Don't let them use a NULL username... */
+ pam_get_user(pamh,&userName,NULL);
+ if (retval != PAM_SUCCESS)
+ return PAM_SERVICE_ERR;
+ }
+
+ pw = getpwnam(userName);
+ if (!pw)
+ return PAM_AUTH_ERR; /* user doesn't exist */
+ userShell = pw->pw_shell;
+
+ if(stat(SHELL_FILE,&sb)) {
+ _pam_log(LOG_ERR, SHELL_FILE, " cannot be stat'd (it probably does "
+ "not exist)");
+ return PAM_AUTH_ERR; /* must have /etc/shells */
+ }
+
+ if((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) {
+ _pam_log(LOG_ERR,
+ SHELL_FILE " is either world writable or not a normal file");
+ return PAM_AUTH_ERR;
+ }
+
+ shellFile = fopen(SHELL_FILE,"r");
+ if(shellFile == NULL) { /* Check that we opened it successfully */
+ _pam_log(LOG_ERR,
+ "Error opening " SHELL_FILE);
+ return PAM_SERVICE_ERR;
+ }
+ /* There should be no more errors from here on */
+ retval=PAM_AUTH_ERR;
+ /* This loop assumes that PAM_SUCCESS == 0
+ and PAM_AUTH_ERR != 0 */
+ while((fgets(shellFileLine,255,shellFile) != NULL)
+ && retval) {
+ if (shellFileLine[strlen(shellFileLine) - 1] == '\n')
+ shellFileLine[strlen(shellFileLine) - 1] = '\0';
+ retval = strcmp(shellFileLine, userShell);
+ }
+ fclose(shellFile);
+ if(retval)
+ retval = PAM_AUTH_ERR;
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_shells_modstruct = {
+ "pam_shells",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_stress/Makefile b/contrib/libpam/modules/pam_stress/Makefile
new file mode 100644
index 000000000000..52e8e21881a3
--- /dev/null
+++ b/contrib/libpam/modules/pam_stress/Makefile
@@ -0,0 +1,109 @@
+#
+# $Id: Makefile,v 1.7 1997/04/05 06:23:08 morgan Exp $
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.7 1997/04/05 06:23:08 morgan
+# fakeroot
+#
+# Revision 1.6 1997/02/15 19:05:55 morgan
+# fixed email
+#
+# Revision 1.5 1996/11/10 20:17:55 morgan
+# cross platform support
+#
+# Revision 1.4 1996/09/05 06:31:09 morgan
+# ld --> gcc
+#
+# Revision 1.3 1996/05/26 15:50:43 morgan
+# make dynamic and static dirs
+#
+# Revision 1.2 1996/05/26 04:11:56 morgan
+# automated static support
+#
+#
+#
+
+TITLE=pam_stress
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_stress/README b/contrib/libpam/modules/pam_stress/README
new file mode 100644
index 000000000000..1cb7c14b73c3
--- /dev/null
+++ b/contrib/libpam/modules/pam_stress/README
@@ -0,0 +1,66 @@
+#
+# $Id: README,v 1.7 1997/02/15 19:07:08 morgan Exp $
+#
+# This describes the behavior of this module with respect to the
+# /etc/pam.conf file.
+#
+# writen by Andrew Morgan <morgan@parc.power.net>
+#
+
+This module recognizes the following arguments.
+
+debug put lots of information in syslog.
+ *NOTE* this option writes passwords to syslog, so
+ don't use anything sensitive when testing.
+
+no_warn don't give warnings about things (otherwise warnings are issued
+ via the conversation function)
+
+use_first_pass don't prompt for a password, for pam_sm_authentication
+ function just use item PAM_AUTHTOK.
+
+try_first_pass don't prompt for a password unless there has been no
+ previous authentication token (item PAM_AUTHTOK is NULL)
+
+rootok This is intended for the pam_sm_chauthtok function and
+ it instructs this function to permit root to change
+ the user's password without entering the old password.
+
+The following arguments are acted on by the module. They are intended
+to make the module give the impression of failing as a fully
+functioning module might.
+
+expired an argument intended for the account and chauthtok module
+ parts. It instructs the module to act as if the user's
+ password has expired
+
+fail_1 this instructs the module to make its first function fail.
+
+fail_2 this instructs the module to make its second function (if there
+ is one) fail.
+
+ The function break up is indicated in the Module
+ Developers' Guide. Listed here it is:
+
+ service function 1 function 2
+ ------- ---------- ----------
+ auth pam_sm_authenticate pam_sm_setcred
+ password pam_sm_chauthtok
+ session pam_sm_open_session pam_sm_close_session
+ account pam_sm_acct_mgmt
+
+prelim for pam_sm_chauthtok, means fail on PAM_PRELIM_CHECK.
+
+required for pam_sm_chauthtok, means fail if the user hasn't already
+ been authenticated by this module. (See stress_new_pwd data
+ item below.)
+
+#
+# data strings that this module uses are the following:
+#
+
+data name value(s) Comments
+--------- -------- --------
+stress_new_pwd yes tells pam_sm_chauthtok that
+ pam_sm_acct_mgmt says we need a new
+ password
diff --git a/contrib/libpam/modules/pam_stress/pam_stress.c b/contrib/libpam/modules/pam_stress/pam_stress.c
new file mode 100644
index 000000000000..501541850461
--- /dev/null
+++ b/contrib/libpam/modules/pam_stress/pam_stress.c
@@ -0,0 +1,581 @@
+/* pam_stress module */
+
+/* $Id: pam_stress.c,v 1.12 1997/02/15 19:06:30 morgan Exp morgan $
+ *
+ * created by Andrew Morgan <morgan@parc.power.net> 1996/3/12
+ *
+ * $Log: pam_stress.c,v $
+ * Revision 1.12 1997/02/15 19:06:30 morgan
+ * fixed email
+ *
+ * Revision 1.11 1997/02/15 17:33:24 morgan
+ * removed fixed syslog buffer
+ *
+ * Revision 1.10 1996/12/01 03:11:35 morgan
+ * using _pam_macros.h now
+ *
+ * Revision 1.9 1996/11/10 20:18:10 morgan
+ * changes for .53 compilation
+ *
+ * Revision 1.8 1996/09/05 06:31:59 morgan
+ * changed return value of wipe_up from int to void
+ *
+ * Revision 1.7 1996/06/02 08:12:28 morgan
+ * updated for new static protocol, added STRESS to various user prompts
+ * and added rootok flag for pam_sm_chauthtok to look out for
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+static char *_strdup(const char *x)
+{
+ char *new;
+ new = malloc(strlen(x)+1);
+ strcpy(new,x);
+ return new;
+}
+
+/* log errors */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* ---------- */
+
+/* an internal function to turn all possible test arguments into bits
+ of a ctrl number */
+
+/* generic options */
+
+#define PAM_ST_DEBUG 01
+#define PAM_ST_NO_WARN 02
+#define PAM_ST_USE_PASS1 04
+#define PAM_ST_TRY_PASS1 010
+#define PAM_ST_ROOTOK 020
+
+/* simulation options */
+
+#define PAM_ST_EXPIRED 040
+#define PAM_ST_FAIL_1 0100
+#define PAM_ST_FAIL_2 0200
+#define PAM_ST_PRELIM 0400
+#define PAM_ST_REQUIRE_PWD 01000
+
+/* some syslogging */
+
+static void _pam_report(int ctrl, const char *name, int flags,
+ int argc, const char **argv)
+{
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG, "CALLED: %s", name);
+ _pam_log(LOG_DEBUG, "FLAGS : 0%o%s", flags,
+ (flags & PAM_SILENT) ? " (silent)":"");
+ _pam_log(LOG_DEBUG, "CTRL = 0%o",ctrl);
+ _pam_log(LOG_DEBUG, "ARGV :");
+ while (argc--) {
+ _pam_log(LOG_DEBUG, " \"%s\"", *argv++);
+ }
+ }
+}
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_ST_DEBUG;
+ else if (!strcmp(*argv,"no_warn"))
+ ctrl |= PAM_ST_NO_WARN;
+ else if (!strcmp(*argv,"use_first_pass"))
+ ctrl |= PAM_ST_USE_PASS1;
+ else if (!strcmp(*argv,"try_first_pass"))
+ ctrl |= PAM_ST_TRY_PASS1;
+ else if (!strcmp(*argv,"rootok"))
+ ctrl |= PAM_ST_ROOTOK;
+
+ /* simulation options */
+
+ else if (!strcmp(*argv,"expired")) /* signal password needs
+ renewal */
+ ctrl |= PAM_ST_EXPIRED;
+ else if (!strcmp(*argv,"fail_1")) /* instruct fn 1 to fail */
+ ctrl |= PAM_ST_FAIL_1;
+ else if (!strcmp(*argv,"fail_2")) /* instruct fn 2 to fail */
+ ctrl |= PAM_ST_FAIL_2;
+ else if (!strcmp(*argv,"prelim")) /* instruct pam_sm_setcred
+ to fail on first call */
+ ctrl |= PAM_ST_PRELIM;
+ else if (!strcmp(*argv,"required")) /* module is fussy about the
+ user being authenticated */
+ ctrl |= PAM_ST_REQUIRE_PWD;
+
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+static int converse(pam_handle_t *pamh, int nargs
+ , struct pam_message **message
+ , struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv))
+ == PAM_SUCCESS) {
+ retval = conv->conv(nargs, (const struct pam_message **) message
+ , response, conv->appdata_ptr);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR,"(pam_stress) converse returned %d",retval);
+ _pam_log(LOG_ERR,"that is: %s",pam_strerror(pamh, retval));
+ }
+ } else {
+ _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv");
+ }
+
+ return retval;
+}
+
+/* authentication management functions */
+
+static int stress_get_password(pam_handle_t *pamh, int flags
+ , int ctrl, char **password)
+{
+ char *pass;
+
+ if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
+ && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass)
+ == PAM_SUCCESS)
+ && (pass != NULL) ) {
+ pass = _strdup(pass);
+ } else if ((ctrl & PAM_ST_USE_PASS1)) {
+ _pam_log(LOG_WARNING, "pam_stress: no forwarded password");
+ return PAM_PERM_DENIED;
+ } else { /* we will have to get one */
+ struct pam_message msg[1],*pmsg[1];
+ struct pam_response *resp;
+ int retval;
+
+ /* set up conversation call */
+
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[0].msg = "STRESS Password: ";
+ resp = NULL;
+
+ if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
+ return retval;
+ }
+
+ if (resp) {
+ if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
+ _pam_log(LOG_DEBUG,
+ "pam_sm_authenticate: NULL authtok given");
+ }
+ if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
+ && resp[0].resp == NULL) {
+ free(resp);
+ return PAM_AUTH_ERR;
+ }
+
+ pass = resp[0].resp; /* remember this! */
+
+ resp[0].resp = NULL;
+ } else if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_authenticate: no error reported");
+ _pam_log(LOG_DEBUG,"getting password, but NULL returned!?");
+ return PAM_CONV_ERR;
+ }
+ free(resp);
+ }
+
+ *password = pass; /* this *MUST* be free()'d by this module */
+
+ return PAM_SUCCESS;
+}
+
+/* function to clean up data items */
+
+static void wipe_up(pam_handle_t *pamh, void *data, int error)
+{
+ free(data);
+}
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username;
+ int retval=PAM_SUCCESS;
+ char *pass;
+ int ctrl;
+
+ D(("called."));
+
+ ctrl = _pam_parse(argc,argv);
+ _pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv);
+
+ /* try to get the username */
+
+ retval = pam_get_user(pamh, &username, "username: ");
+ if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) {
+ _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username);
+ } else if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username");
+ return retval;
+ }
+
+ /* now get the password */
+
+ retval = stress_get_password(pamh,flags,ctrl,&pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "pam_sm_authenticate: "
+ "failed to get a password");
+ return retval;
+ }
+
+ /* try to set password item */
+
+ retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "pam_sm_authenticate: "
+ "failed to store new password");
+ _pam_overwrite(pass);
+ free(pass);
+ return retval;
+ }
+
+ /* clean up local copy of password */
+
+ _pam_overwrite(pass);
+ free(pass);
+ pass = NULL;
+
+ /* if we are debugging then we print the password */
+
+ if (ctrl & PAM_ST_DEBUG) {
+ (void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass);
+ _pam_log(LOG_DEBUG,
+ "pam_st_authenticate: password entered is: [%s]\n",pass);
+ pass = NULL;
+ }
+
+ /* if we signal a fail for this function then fail */
+
+ if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
+ return PAM_PERM_DENIED;
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl, "pam_sm_setcred", flags, argc, argv);
+
+ if (ctrl & PAM_ST_FAIL_2)
+ return PAM_CRED_ERR;
+
+ return PAM_SUCCESS;
+}
+
+/* account management functions */
+
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
+
+ if (ctrl & PAM_ST_FAIL_1)
+ return PAM_PERM_DENIED;
+ else if (ctrl & PAM_ST_EXPIRED) {
+ void *text = malloc(sizeof("yes")+1);
+ strcpy(text,"yes");
+ pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password");
+ }
+ return PAM_NEW_AUTHTOK_REQD;
+ }
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ char *username,*service;
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv);
+
+ if ((pam_get_item(pamh, PAM_USER, (const void **) &username)
+ != PAM_SUCCESS)
+ || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service)
+ != PAM_SUCCESS)) {
+ _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?");
+ return PAM_SESSION_ERR;
+ }
+
+ _pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]"
+ , service, username);
+
+ if (ctrl & PAM_ST_FAIL_1)
+ return PAM_SESSION_ERR;
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username,*service;
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv);
+
+ if ((pam_get_item(pamh, PAM_USER, (const void **)&username)
+ != PAM_SUCCESS)
+ || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
+ != PAM_SUCCESS)) {
+ _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?");
+ return PAM_SESSION_ERR;
+ }
+
+ _pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]"
+ , service, username);
+
+ if (ctrl & PAM_ST_FAIL_2)
+ return PAM_SESSION_ERR;
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval;
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv);
+
+ /* this function should be called twice by the Linux-PAM library */
+
+ if (flags & PAM_PRELIM_CHECK) { /* first call */
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check");
+ }
+ if (ctrl & PAM_ST_PRELIM)
+ return PAM_TRY_AGAIN;
+
+ return PAM_SUCCESS;
+ } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */
+ struct pam_message msg[3],*pmsg[3];
+ struct pam_response *resp;
+ const char *text;
+ char *txt=NULL;
+ int i;
+
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password");
+ }
+
+ if (ctrl & PAM_ST_FAIL_1)
+ return PAM_AUTHTOK_LOCK_BUSY;
+
+ if ( !(ctrl && PAM_ST_EXPIRED)
+ && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
+ && (pam_get_data(pamh,"stress_new_pwd",(const void **)&text)
+ != PAM_SUCCESS || strcmp(text,"yes"))) {
+ return PAM_SUCCESS; /* the token has not expired */
+ }
+
+ /* the password should be changed */
+
+ if ((ctrl & PAM_ST_REQUIRE_PWD)
+ && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
+ ) { /* first get old one? */
+ char *pass;
+
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG
+ ,"pam_sm_chauthtok: getting old password");
+ }
+ retval = stress_get_password(pamh,flags,ctrl,&pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_DEBUG
+ ,"pam_sm_chauthtok: no password obtained");
+ return retval;
+ }
+ retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_DEBUG
+ ,"pam_sm_chauthtok: could not set OLDAUTHTOK");
+ _pam_overwrite(pass);
+ free(pass);
+ return retval;
+ }
+ _pam_overwrite(pass);
+ free(pass);
+ }
+
+ /* set up for conversation */
+
+ if (!(flags & PAM_SILENT)) {
+ char *username;
+
+ if ( pam_get_item(pamh, PAM_USER, (const void **)&username)
+ || username == NULL ) {
+ _pam_log(LOG_ERR,"no username set");
+ return PAM_USER_UNKNOWN;
+ }
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+#define _LOCAL_STRESS_COMMENT "Changing STRESS password for "
+ txt = (char *) malloc(sizeof(_LOCAL_STRESS_COMMENT)
+ +strlen(username)+1);
+ strcpy(txt, _LOCAL_STRESS_COMMENT);
+#undef _LOCAL_STRESS_COMMENT
+ strcat(txt, username);
+ msg[0].msg = txt;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = "Enter new STRESS password: ";
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = "Retype new STRESS password: ";
+ resp = NULL;
+
+ retval = converse(pamh,i,pmsg,&resp);
+ if (txt) {
+ free(txt);
+ txt = NULL; /* clean up */
+ }
+ if (retval != PAM_SUCCESS) {
+ return retval;
+ }
+
+ if (resp == NULL) {
+ _pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv");
+ return PAM_CONV_ERR;
+ }
+
+ /* store the password */
+
+ if (resp[i-2].resp && resp[i-1].resp) {
+ if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
+ /* passwords are not the same; forget and return error */
+
+ _pam_drop_reply(resp, i);
+
+ if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_ERROR_MSG;
+ msg[0].msg = "Verification mis-typed; "
+ "password unchaged";
+ resp = NULL;
+ (void) converse(pamh,1,pmsg,&resp);
+ if (resp) {
+ _pam_drop_reply(resp, 1);
+ }
+ }
+ return PAM_AUTHTOK_ERR;
+ }
+
+ if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text)
+ == PAM_SUCCESS) {
+ (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
+ text = NULL;
+ }
+ (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
+ } else {
+ _pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp");
+ retval = PAM_SYSTEM_ERR;
+ }
+
+ _pam_drop_reply(resp, i); /* clean up the passwords */
+ } else {
+ _pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error");
+ return PAM_SYSTEM_ERR;
+ }
+
+ return retval;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_stress_modstruct = {
+ "pam_stress",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok
+};
+
+#endif
diff --git a/contrib/libpam/modules/pam_tally/Makefile b/contrib/libpam/modules/pam_tally/Makefile
new file mode 100644
index 000000000000..ec17ff31fa8e
--- /dev/null
+++ b/contrib/libpam/modules/pam_tally/Makefile
@@ -0,0 +1,93 @@
+#
+# $Id: Makefile,v 1.1 1997/04/05 06:19:04 morgan Exp $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.1 1997/04/05 06:19:04 morgan
+# Initial revision
+#
+#
+
+TITLE=pam_tally
+
+#
+## Should add some more rules to make the application too.
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_tally/README b/contrib/libpam/modules/pam_tally/README
new file mode 100644
index 000000000000..aaa8512bade4
--- /dev/null
+++ b/contrib/libpam/modules/pam_tally/README
@@ -0,0 +1,51 @@
+
+SUMMARY:
+ pam_tally:
+
+ Maintains a count of attempted accesses, can reset count on success,
+ can deny access if too many attempts fail.
+
+ Options:
+
+ * onerr=[succeed|fail] (if something weird happens
+ such as unable to open the file, what to do?)
+ * file=/where/to/keep/counts (default /var/log/faillog)
+
+ (auth)
+ * no_magic_root (root DOES increment counter. Use for
+ daemon-based stuff, like telnet/rsh/login)
+
+ (account)
+ * deny=n (deny access if tally for this user exceeds n;
+ The presence of deny=n changes the default for
+ reset/no_reset to reset, unless the user trying to
+ gain access is root and the no_magic_root option
+ has NOT been specified.)
+
+ * no_magic_root (access attempts by root DON'T ignore deny.
+ Use this for daemon-based stuff, like telnet/rsh/login)
+ * even_deny_root_account (Root can become unavailable. BEWARE.
+ Note that magic root trying to gain root bypasses this,
+ but normal users can be locked out.)
+
+ * reset (reset count to 0 on successful entry, even for
+ magic root)
+ * no_reset (don't reset count on successful entry)
+ This is the default unless deny exists and the
+ user attempting access is NOT magic root.
+
+ Also checks to make sure that the list file is a plain
+ file and not world writable.
+
+ - Tim Baverstock <warwick@mmm.co.uk>, Multi Media Machine Ltd.
+ v0.1 5 March 1997
+
+BUGS:
+
+pam_tally is very dependant on getpw*(): a database of usernames
+would be much more flexible.
+
+The (4.0 Redhat) utilities seem to do funny things with uid, and I'm
+not wholly sure I understood what I should have been doing anyway so
+the `keep a count of current logins' bit has been #ifdef'd out and you
+can only reset the counter on successful authentication, for now.
diff --git a/contrib/libpam/modules/pam_tally/pam_tally.c b/contrib/libpam/modules/pam_tally/pam_tally.c
new file mode 100644
index 000000000000..a1b65c04e958
--- /dev/null
+++ b/contrib/libpam/modules/pam_tally/pam_tally.c
@@ -0,0 +1,634 @@
+/*
+ * pam_tally.c
+ *
+ * Revision history? :) 0.1
+ */
+
+
+/* By Tim Baverstock <warwick@mmm.co.uk>, Multi Media Machine Ltd.
+ * 5 March 1997
+ *
+ * Stuff stolen from pam_rootok and pam_listfile
+ */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <pwd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#ifndef TRUE
+#define TRUE 1L
+#define FALSE 0L
+#endif
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+/* #define PAM_SM_SESSION */
+/* #define PAM_SM_PASSWORD */
+
+#include <security/pam_modules.h>
+
+/*---------------------------------------------------------------------*/
+
+#define DEFAULT_LOGFILE "/var/log/faillog"
+#define MODULE_NAME "pam_tally"
+
+enum TALLY_RESET {
+ TALLY_RESET_DEFAULT,
+ TALLY_RESET_RESET,
+ TALLY_RESET_NO_RESET
+};
+
+#define tally_t unsigned short int
+#define TALLY_FMT "%hu"
+#define TALLY_HI ((tally_t)~0L)
+
+#define UID_FMT "%hu"
+
+#ifndef FILENAME_MAX
+# define FILENAME_MAX MAXPATHLEN
+#endif
+
+/*---------------------------------------------------------------------*/
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+#ifdef MAIN
+ vfprintf(stderr,format,args);
+#else
+ openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ closelog();
+#endif
+ va_end(args);
+}
+
+/*---------------------------------------------------------------------*/
+
+/* --- Support function: get uid (and optionally username) from PAM or
+ cline_user --- */
+
+#ifdef MAIN
+static char *cline_user=0; /* cline_user is used in the administration prog */
+#endif
+
+static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp )
+ {
+ const char *user;
+ struct passwd *pw;
+
+#ifdef MAIN
+ user = cline_user;
+#else
+ pam_get_user( pamh, &user, NULL );
+#endif
+
+ if ( !user || !*user ) {
+ _pam_log(LOG_ERR, MODULE_NAME ": pam_get_uid; user?");
+ return PAM_AUTH_ERR;
+ }
+
+ if ( ! ( pw = getpwnam( user ) ) ) {
+ _pam_log(LOG_ERR,MODULE_NAME ": pam_get_uid; no such user %s",user);
+ return PAM_USER_UNKNOWN;
+ }
+
+ if ( uid ) *uid = pw->pw_uid;
+ if ( userp ) *userp = user;
+ return PAM_SUCCESS;
+ }
+
+/*---------------------------------------------------------------------*/
+
+/* --- Support function: open/create tallyfile and return tally for uid --- */
+
+/* If on entry *tally==TALLY_HI, tallyfile is opened READONLY */
+/* Otherwise, if on entry tallyfile doesn't exist, creation is attempted. */
+
+static int get_tally( tally_t *tally,
+ uid_t uid,
+ const char *filename,
+ FILE **TALLY )
+ {
+ struct stat fileinfo;
+ int lstat_ret = lstat(filename,&fileinfo);
+
+ if ( lstat_ret && *tally!=TALLY_HI ) {
+ if ( ( *TALLY=fopen(filename, "a") ) ) {
+ /* Create file, or append-open in pathological case. */
+ _pam_log(LOG_ALERT, "Couldn't create %s",filename);
+ return PAM_AUTH_ERR;
+ }
+ fclose(*TALLY);
+ lstat_ret = lstat(filename,&fileinfo);
+ }
+
+ if ( lstat_ret ) {
+ _pam_log(LOG_ALERT, "Couldn't stat %s",filename);
+ return PAM_AUTH_ERR;
+ }
+
+ if((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) {
+ /* If the file is world writable or is not a
+ normal file, return error */
+ _pam_log(LOG_ALERT,
+ "%s is either world writable or not a normal file",
+ filename);
+ return PAM_AUTH_ERR;
+ }
+
+ if ( ! ( *TALLY = fopen(filename,(*tally!=TALLY_HI)?"r+":"r") ) ) {
+ _pam_log(LOG_ALERT, "Error opening %s for update", filename);
+
+/* Discovering why account service fails: e/uid are target user.
+ *
+ * perror(MODULE_NAME);
+ * fprintf(stderr,"uid %d euid %d\n",getuid(), geteuid());
+ */
+ return PAM_AUTH_ERR;
+ }
+
+ if ( fseek( *TALLY, uid * sizeof (tally_t), SEEK_SET ) ) {
+ _pam_log(LOG_ALERT, "fseek failed %s", filename);
+ return PAM_AUTH_ERR;
+ }
+
+ if ( ( fread(tally, sizeof(tally_t), 1, *TALLY) )==0 ) {
+ *tally=0; /* Assuming a gappy filesystem */
+ }
+ return PAM_SUCCESS;
+ }
+
+/*---------------------------------------------------------------------*/
+
+/* --- Support function: update and close tallyfile with tally!=TALLY_HI --- */
+
+static int set_tally( tally_t tally,
+ uid_t uid,
+ const char *filename,
+ FILE **TALLY )
+ {
+ if ( tally!=TALLY_HI )
+ {
+ if ( fseek( *TALLY, uid * sizeof(tally_t), SEEK_SET ) ) {
+ _pam_log(LOG_ALERT, "fseek failed %s", filename);
+ return PAM_AUTH_ERR;
+ }
+
+ if ( fwrite(&tally, sizeof(tally_t), 1, *TALLY)==0 ) {
+ _pam_log(LOG_ALERT, "tally update (fputc) failed.", filename);
+ return PAM_AUTH_ERR;
+ }
+ }
+
+ if ( fclose(*TALLY) ) {
+ _pam_log(LOG_ALERT, "tally update (fclose) failed.", filename);
+ return PAM_AUTH_ERR;
+ }
+ *TALLY=NULL;
+ return PAM_SUCCESS;
+ }
+
+/*---------------------------------------------------------------------*/
+
+/* --- PAM bits --- */
+
+#ifndef MAIN
+
+#define PAM_FUNCTION(name) \
+ PAM_EXTERN int name (pam_handle_t *pamh,int flags,int argc,const char **argv)
+
+#define RETURN_ERROR(i) return ((fail_on_error)?(i):(PAM_SUCCESS))
+
+/*---------------------------------------------------------------------*/
+
+/* --- tally bump function: bump tally for uid by (signed) inc --- */
+
+static int tally_bump (int inc,
+ pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv) {
+ uid_t uid;
+
+ int
+ fail_on_error = FALSE;
+ tally_t
+ tally = 0; /* !TALLY_HI --> Log opened for update */
+
+ char
+ no_magic_root = FALSE;
+
+ char
+ filename[ FILENAME_MAX ] = DEFAULT_LOGFILE;
+
+ /* Should probably decode the parameters before anything else. */
+
+ {
+ for ( ; argc-- > 0; ++argv ) {
+
+ /* generic options.. um, ignored. :] */
+
+ if ( ! strcmp( *argv, "no_magic_root" ) ) {
+ no_magic_root = TRUE;
+ }
+ else if ( ! strncmp( *argv, "file=", 5 ) ) {
+ char const
+ *from = (*argv)+5;
+ char
+ *to = filename;
+ if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) {
+ _pam_log(LOG_ERR,
+ MODULE_NAME ": filename not /rooted or too long; ",
+ *argv);
+ RETURN_ERROR( PAM_AUTH_ERR );
+ }
+ while ( ( *to++ = *from++ ) );
+ }
+ else if ( ! strcmp( *argv, "onerr=fail" ) ) {
+ fail_on_error=TRUE;
+ }
+ else if ( ! strcmp( *argv, "onerr=succeed" ) ) {
+ fail_on_error=FALSE;
+ }
+ else {
+ _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv);
+ }
+ } /* for() */
+ }
+
+ {
+ FILE
+ *TALLY = NULL;
+ const char
+ *user = NULL;
+
+ int i=pam_get_uid(pamh, &uid, &user);
+ if ( i != PAM_SUCCESS ) RETURN_ERROR( i );
+
+ i=get_tally( &tally, uid, filename, &TALLY );
+ if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); }
+
+ if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */
+
+ tally+=inc;
+
+ if ( tally==TALLY_HI ) { /* Overflow *and* underflow. :) */
+ tally-=inc;
+ _pam_log(LOG_ALERT,"Tally %sflowed for user %s",
+ (inc<0)?"under":"over",user);
+ }
+ }
+
+ i=set_tally( tally, uid, filename, &TALLY );
+ if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); }
+ }
+
+ return PAM_SUCCESS;
+}
+
+/*---------------------------------------------------------------------*/
+
+/* --- authentication management functions (only) --- */
+
+#ifdef PAM_SM_AUTH
+
+PAM_FUNCTION( pam_sm_authenticate ) {
+ return tally_bump( 1, pamh, flags, argc, argv);
+}
+
+/* --- Seems to need this function. Ho hum. --- */
+
+PAM_FUNCTION( pam_sm_setcred ) { return PAM_SUCCESS; }
+
+#endif
+
+/*---------------------------------------------------------------------*/
+
+/* --- session management functions (only) --- */
+
+/*
+ * Unavailable until .so files can be suid
+ */
+
+#ifdef PAM_SM_SESSION
+
+/* To maintain a balance-tally of successful login/outs */
+
+PAM_FUNCTION( pam_sm_open_session ) {
+ return tally_bump( 1, pamh, flags, argc, argv);
+}
+
+PAM_FUNCTION( pam_sm_close_session ) {
+ return tally_bump(-1, pamh, flags, argc, argv);
+}
+
+#endif
+
+/*---------------------------------------------------------------------*/
+
+/* --- authentication management functions (only) --- */
+
+#ifdef PAM_SM_AUTH
+
+/* To lock out a user with an unacceptably high tally */
+
+PAM_FUNCTION( pam_sm_acct_mgmt ) {
+ uid_t
+ uid;
+
+ int
+ fail_on_error = FALSE;
+ tally_t
+ deny = 0;
+ tally_t
+ tally = 0; /* !TALLY_HI --> Log opened for update */
+
+ char
+ no_magic_root = FALSE,
+ even_deny_root_account = FALSE;
+
+ const char
+ *user = NULL;
+
+ enum TALLY_RESET
+ reset = TALLY_RESET_DEFAULT;
+
+ char
+ filename[ FILENAME_MAX ] = DEFAULT_LOGFILE;
+
+ /* Should probably decode the parameters before anything else. */
+
+ {
+ for ( ; argc-- > 0; ++argv ) {
+
+ /* generic options.. um, ignored. :] */
+
+ if ( ! strcmp( *argv, "no_magic_root" ) ) {
+ no_magic_root = TRUE;
+ }
+ else if ( ! strcmp( *argv, "even_deny_root_account" ) ) {
+ even_deny_root_account = TRUE;
+ }
+ else if ( ! strcmp( *argv, "reset" ) ) {
+ reset = TALLY_RESET_RESET;
+ }
+ else if ( ! strcmp( *argv, "no_reset" ) ) {
+ reset = TALLY_RESET_NO_RESET;
+ }
+ else if ( ! strncmp( *argv, "file=", 5 ) ) {
+ char const
+ *from = (*argv)+5;
+ char
+ *to = filename;
+ if ( *from != '/' || strlen(from) > FILENAME_MAX-1 ) {
+ _pam_log(LOG_ERR,
+ MODULE_NAME ": filename not /rooted or too long; ",
+ *argv);
+ RETURN_ERROR( PAM_AUTH_ERR );
+ }
+ while ( ( *to++ = *from++ ) );
+ }
+ else if ( ! strncmp( *argv, "deny=", 5 ) ) {
+ if ( sscanf((*argv)+5,TALLY_FMT,&deny) != 1 ) {
+ _pam_log(LOG_ERR,"bad number supplied; %s",*argv);
+ RETURN_ERROR( PAM_AUTH_ERR );
+ }
+ }
+ else if ( ! strcmp( *argv, "onerr=fail" ) ) {
+ fail_on_error=TRUE;
+ }
+ else if ( ! strcmp( *argv, "onerr=succeed" ) ) {
+ fail_on_error=FALSE;
+ }
+ else {
+ _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv);
+ }
+ } /* for() */
+ }
+
+ {
+ FILE *TALLY=0;
+ int i=pam_get_uid(pamh, &uid, &user);
+ if ( i != PAM_SUCCESS ) RETURN_ERROR( i );
+
+ i=get_tally( &tally, uid, filename, &TALLY );
+ if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); }
+
+ if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */
+
+ /* To deny or not to deny; that is the question */
+
+ if (
+ ( deny != 0 ) && /* deny==0 means no deny */
+ ( tally > deny ) && /* tally>deny means exceeded */
+ ( even_deny_root_account || uid ) /* even_deny stops uid check */
+ ) {
+ _pam_log(LOG_NOTICE,"user %s ("UID_FMT") tally "TALLY_FMT", deny "TALLY_FMT,
+ user, uid, tally, deny);
+ return PAM_AUTH_ERR; /* Only unconditional failure */
+ }
+
+ /* resets for explicit reset
+ * or by default if deny exists and not magic-root
+ */
+
+ if ( ( reset == TALLY_RESET_RESET ) ||
+ ( reset == TALLY_RESET_DEFAULT && deny ) ) { tally=0; }
+ }
+ else /* is magic root */ {
+
+ /* Magic root skips deny test... */
+
+ /* Magic root only resets on explicit reset, regardless of deny */
+
+ if ( reset == TALLY_RESET_RESET ) { tally=0; }
+ }
+
+ i=set_tally( tally, uid, filename, &TALLY );
+ if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); }
+ }
+
+ return PAM_SUCCESS;
+}
+
+#endif /* #ifdef PAM_SM_AUTH */
+
+/*-----------------------------------------------------------------------*/
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_tally_modstruct = {
+ MODULE_NAME,
+#ifdef PAM_SM_AUTH
+ pam_sm_authenticate,
+ pam_sm_setcred,
+#else
+ NULL,
+ NULL,
+#endif
+#ifdef PAM_SM_ACCOUNT
+ pam_sm_acct_mgmt,
+#else
+ NULL,
+#endif
+#ifdef PAM_SM_SESSION
+ pam_sm_open_session,
+ pam_sm_close_session,
+#else
+ NULL,
+ NULL,
+#endif
+#ifdef PAM_SM_PASSWORD
+ pam_sm_chauthtok,
+#else
+ NULL,
+#endif
+};
+
+#endif /* #ifdef PAM_STATIC */
+
+/*-----------------------------------------------------------------------*/
+
+#else /* #ifndef MAIN */
+
+static const char *cline_filename = DEFAULT_LOGFILE;
+static tally_t cline_reset = TALLY_HI; /* Default is `interrogate only' */
+static int cline_quiet = 0;
+
+/*
+ * Not going to link with pamlib just for these.. :)
+ */
+
+static const char * pam_errors( int i ) {
+ switch (i) {
+ case PAM_AUTH_ERR: return "Authentication error";
+ case PAM_SERVICE_ERR: return "Service error";
+ case PAM_USER_UNKNOWN: return "Unknown user";
+ default: return "Unknown error";
+ }
+}
+
+static int getopts( int argc, char **argv ) {
+ const char *pname = *argv;
+ for ( ; *argv ; (void)(*argv && ++argv) ) {
+ if ( !strcmp (*argv,"--file") ) cline_filename=*++argv;
+ else if ( !strncmp(*argv,"--file=",7) ) cline_filename=*argv+7;
+ else if ( !strcmp (*argv,"--user") ) cline_user=*++argv;
+ else if ( !strncmp(*argv,"--user=",7) ) cline_user=*argv+7;
+ else if ( !strcmp (*argv,"--reset") ) cline_reset=0;
+ else if ( !strncmp(*argv,"--reset=",8)) {
+ if ( sscanf(*argv+8,TALLY_FMT,&cline_reset) != 1 )
+ fprintf(stderr,"%s: Bad number given to --reset=\n",pname), exit(0);
+ }
+ else if ( !strcmp (*argv,"--quiet") ) cline_quiet=1;
+ else {
+ fprintf(stderr,"%s: Unrecognised option %s\n",pname,*argv);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+int main ( int argc, char **argv ) {
+
+ if ( ! getopts( argc, argv+1 ) ) {
+ printf("%s: [--file rooted-filename] [--user username] "
+ "[--reset[=n]] [--quiet]\n",
+ *argv);
+ exit(0);
+ }
+
+ /*
+ * Major difference between individual user and all users:
+ * --user just handles one user, just like PAM.
+ * --user=* handles all users, sniffing cline_filename for nonzeros
+ */
+
+ if ( cline_user ) {
+ uid_t uid;
+ tally_t tally=cline_reset;
+ FILE *TALLY=0;
+ int i=pam_get_uid( NULL, &uid, NULL);
+ if ( i != PAM_SUCCESS ) {
+ fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
+ exit(0);
+ }
+
+ i=get_tally( &tally, uid, cline_filename, &TALLY );
+ if ( i != PAM_SUCCESS ) {
+ if (TALLY) fclose(TALLY);
+ fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
+ exit(0);
+ }
+
+ if ( !cline_quiet )
+ printf("User %s\t("UID_FMT")\t%s "TALLY_FMT"\n",cline_user,uid,
+ (cline_reset!=TALLY_HI)?"had":"has",tally);
+
+ i=set_tally( cline_reset, uid, cline_filename, &TALLY );
+ if ( i != PAM_SUCCESS ) {
+ if (TALLY) fclose(TALLY);
+ fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
+ exit(0);
+ }
+ }
+ else /* !cline_user (ie, operate on all users) */ {
+ FILE *TALLY=fopen(cline_filename, "r");
+ uid_t uid=0;
+ if ( !TALLY ) perror(*argv), exit(0);
+
+ for ( ; !feof(TALLY); uid++ ) {
+ tally_t tally;
+ struct passwd *pw;
+ if ( ! fread(&tally, sizeof(tally_t), 1, TALLY) || ! tally ) continue;
+
+ if ( ( pw=getpwuid(uid) ) ) {
+ printf("User %s\t("UID_FMT")\t%s "TALLY_FMT"\n",pw->pw_name,uid,
+ (cline_reset!=TALLY_HI)?"had":"has",tally);
+ }
+ else {
+ printf("User [NONAME]\t("UID_FMT")\t%s "TALLY_FMT"\n",uid,
+ (cline_reset!=TALLY_HI)?"had":"has",tally);
+ }
+ }
+ fclose(TALLY);
+ if ( cline_reset!=0 && cline_reset!=TALLY_HI ) {
+ fprintf(stderr,"%s: Can't reset all users to non-zero\n",*argv);
+ }
+ else if ( !cline_reset ) {
+ TALLY=fopen(cline_filename, "w");
+ if ( !TALLY ) perror(*argv), exit(0);
+ fclose(TALLY);
+ }
+ }
+ return 0;
+}
+
+
+#endif
diff --git a/contrib/libpam/modules/pam_time/Makefile b/contrib/libpam/modules/pam_time/Makefile
new file mode 100644
index 000000000000..bc297d4f9853
--- /dev/null
+++ b/contrib/libpam/modules/pam_time/Makefile
@@ -0,0 +1,121 @@
+#
+# $Id: Makefile,v 1.6 1997/04/05 06:22:32 morgan Exp morgan $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.6 1997/04/05 06:22:32 morgan
+# fakeroot
+#
+# Revision 1.5 1997/02/15 19:16:16 morgan
+# fixed email
+#
+# Revision 1.4 1996/11/10 20:18:21 morgan
+# cross platform support
+#
+# Revision 1.3 1996/09/05 06:27:37 morgan
+# ld --> gcc
+#
+# Revision 1.2 1996/08/09 05:48:19 morgan
+# inherit installation files from parent
+#
+# Revision 1.1 1996/07/07 23:42:48 morgan
+# Initial revision
+#
+# Revision 1.1 1996/06/24 05:48:49 morgan
+# Initial revision
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/6/11
+#
+
+TITLE=pam_time
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/time.conf
+export CONFILE
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+DEFS=-DCONFILE=\"$(CONFILE)\"
+
+CFLAGS += $(DEFS)
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ifdef DYNAMIC
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SCONFIGED)
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+ rm -f $(FAKEROOT)$(CONFILE)
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+ rm -f ./.ignore_age
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_time/README b/contrib/libpam/modules/pam_time/README
new file mode 100644
index 000000000000..0c3f976b4012
--- /dev/null
+++ b/contrib/libpam/modules/pam_time/README
@@ -0,0 +1,37 @@
+$Id: README,v 1.3 1997/01/04 20:42:43 morgan Exp $
+
+This is a help file for the pam_time module. It explains the need for
+pam_time and also the syntax of the /etc/security/time.conf file.
+[a lot of the syntax is freely adapted from the porttime file of the
+shadow suite.]
+
+1. Introduction
+===============
+
+It is desirable to restrict access to a system and or specific
+applications at various times of the day and on specific days or over
+various terminal lines.
+
+The pam_time module is intended to offer a configurable module that
+satisfies this purpose, within the context of Linux-PAM.
+
+2. the /etc/security/time.conf file
+===================================
+
+This file is the configuration script for defining time/port access
+control to the system/applications.
+
+Its syntax is described in the sample ./time.conf provided in this
+directory.
+
+unrecognised rules are ignored (but an error is logged to syslog(3))
+
+--------------------
+Bugs to Andrew <morgan@parc.power.net> or the list <pam-list@redhat.com>
+
+########################################################################
+# $Log: README,v $
+# Revision 1.3 1997/01/04 20:42:43 morgan
+# I want email on parc now
+#
+# \ No newline at end of file
diff --git a/contrib/libpam/modules/pam_time/install_conf b/contrib/libpam/modules/pam_time/install_conf
new file mode 100755
index 000000000000..051d8b7013d7
--- /dev/null
+++ b/contrib/libpam/modules/pam_time/install_conf
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONFILE=$FAKEROOT"$CONFILE"
+IGNORE_AGE=./.ignore_age
+QUIET_INSTALL=../../.quiet_install
+CONF=./time.conf
+MODULE=pam_time
+
+echo
+
+if [ -f "$QUIET_INSTALL" ]; then
+ if [ ! -f "$CONFILE" ]; then
+ yes="y"
+ else
+ yes="skip"
+ fi
+elif [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "An older $MODULE configuration file already exists ($CONFILE)"
+ echo "Do you wish to copy the $CONF file in this distribution"
+ echo "to $CONFILE ? (y/n) [skip] "
+ read yes
+ else
+ yes="y"
+ fi
+else
+ yes="skip"
+fi
+
+if [ "$yes" = "y" ]; then
+ mkdir -p $FAKEROOT$CONFD
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ echo " Skipping $CONF installation"
+ if [ "$yes" = "n" ]; then
+ touch "$IGNORE_AGE"
+ fi
+fi
+
+echo
+
+exit 0
diff --git a/contrib/libpam/modules/pam_time/pam_time.c b/contrib/libpam/modules/pam_time/pam_time.c
new file mode 100644
index 000000000000..489c1d734ae0
--- /dev/null
+++ b/contrib/libpam/modules/pam_time/pam_time.c
@@ -0,0 +1,614 @@
+/* pam_time module */
+
+/*
+ * $Id: pam_time.c,v 1.7 1997/02/15 17:32:21 morgan Exp $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/6/22
+ * (File syntax and much other inspiration from the shadow package
+ * shadow-960129)
+ *
+ * $Log: pam_time.c,v $
+ * Revision 1.7 1997/02/15 17:32:21 morgan
+ * time parsing more robust
+ *
+ * Revision 1.6 1997/01/04 20:43:15 morgan
+ * fixed buffer underflow, reformatted to 4 spaces
+ *
+ */
+
+const static char rcsid[] =
+"$Id: pam_time.c,v 1.7 1997/02/15 17:32:21 morgan Exp $;\n"
+"\t\tVersion 0.22 for Linux-PAM\n"
+"Copyright (C) Andrew G. Morgan 1996 <morgan@parc.power.net>\n";
+
+#include <sys/file.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define PAM_TIME_CONF CONFILE /* from external define */
+#define PAM_TIME_BUFLEN 1000
+#define FIELD_SEPARATOR ';' /* this is new as of .02 */
+
+typedef enum { FALSE, TRUE } boolean;
+typedef enum { AND, OR } operator;
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_ACCOUNT
+
+#include <security/_pam_macros.h>
+#include <security/pam_modules.h>
+
+/* --- static functions for checking whether the user should be let in --- */
+
+static void _log_err(const char *format, ... )
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_time", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(LOG_CRIT, format, args);
+ va_end(args);
+ closelog();
+}
+
+static void shift_bytes(char *mem, int from, int by)
+{
+ while (by-- > 0) {
+ *mem = mem[from];
+ ++mem;
+ }
+}
+
+static int read_field(int fd, char **buf, int *from, int *to)
+{
+ /* is buf set ? */
+
+ if (! *buf) {
+ *buf = (char *) malloc(PAM_TIME_BUFLEN);
+ if (! *buf) {
+ _log_err("out of memory");
+ D(("no memory"));
+ return -1;
+ }
+ *from = *to = 0;
+ fd = open(PAM_TIME_CONF, O_RDONLY);
+ }
+
+ /* do we have a file open ? return error */
+
+ if (fd < 0 && *to <= 0) {
+ _log_err( PAM_TIME_CONF " not opened");
+ memset(*buf, 0, PAM_TIME_BUFLEN);
+ _pam_drop(*buf);
+ return -1;
+ }
+
+ /* check if there was a newline last time */
+
+ if ((*to > *from) && (*to > 0)
+ && ((*buf)[*from] == '\0')) { /* previous line ended */
+ (*from)++;
+ (*buf)[0] = '\0';
+ return fd;
+ }
+
+ /* ready for more data: first shift the buffer's remaining data */
+
+ *to -= *from;
+ shift_bytes(*buf, *from, *to);
+ *from = 0;
+ (*buf)[*to] = '\0';
+
+ while (fd >= 0 && *to < PAM_TIME_BUFLEN) {
+ int i;
+
+ /* now try to fill the remainder of the buffer */
+
+ i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to);
+ if (i < 0) {
+ _log_err("error reading " PAM_TIME_CONF);
+ return -1;
+ } else if (!i) {
+ fd = -1; /* end of file reached */
+ } else
+ *to += i;
+
+ /*
+ * contract the buffer. Delete any comments, and replace all
+ * multiple spaces with single commas
+ */
+
+ i = 0;
+#ifdef DEBUG_DUMP
+ D(("buffer=<%s>",*buf));
+#endif
+ while (i < *to) {
+ if ((*buf)[i] == ',') {
+ int j;
+
+ for (j=++i; j<*to && (*buf)[j] == ','; ++j);
+ if (j!=i) {
+ shift_bytes(i + (*buf), j-i, (*to) - j);
+ *to -= j-i;
+ }
+ }
+ switch ((*buf)[i]) {
+ int j,c;
+ case '#':
+ for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j);
+ if (j >= *to) {
+ (*buf)[*to = ++i] = '\0';
+ } else if (c == '\n') {
+ shift_bytes(i + (*buf), j-i, (*to) - j);
+ *to -= j-i;
+ ++i;
+ } else {
+ _log_err("internal error in " __FILE__
+ " at line %d", __LINE__ );
+ return -1;
+ }
+ break;
+ case '\\':
+ if ((*buf)[i+1] == '\n') {
+ shift_bytes(i + *buf, 2, *to - (i+2));
+ *to -= 2;
+ }
+ break;
+ case '!':
+ case ' ':
+ case '\t':
+ if ((*buf)[i] != '!')
+ (*buf)[i] = ',';
+ /* delete any trailing spaces */
+ for (j=++i; j < *to && ( (c = (*buf)[j]) == ' '
+ || c == '\t' ); ++j);
+ shift_bytes(i + *buf, j-i, (*to)-j );
+ *to -= j-i;
+ break;
+ default:
+ ++i;
+ }
+ }
+ }
+
+ (*buf)[*to] = '\0';
+
+ /* now return the next field (set the from/to markers) */
+ {
+ int i;
+
+ for (i=0; i<*to; ++i) {
+ switch ((*buf)[i]) {
+ case '#':
+ case '\n': /* end of the line/file */
+ (*buf)[i] = '\0';
+ *from = i;
+ return fd;
+ case FIELD_SEPARATOR: /* end of the field */
+ (*buf)[i] = '\0';
+ *from = ++i;
+ return fd;
+ }
+ }
+ *from = i;
+ (*buf)[*from] = '\0';
+ }
+
+ if (*to <= 0) {
+ D(("[end of text]"));
+ *buf = NULL;
+ }
+
+ return fd;
+}
+
+/* read a member from a field */
+
+static int logic_member(const char *string, int *at)
+{
+ int len,c,to;
+ int done=0;
+ int token=0;
+
+ len=0;
+ to=*at;
+ do {
+ c = string[to++];
+
+ switch (c) {
+
+ case '\0':
+ --to;
+ done = 1;
+ break;
+
+ case '&':
+ case '|':
+ case '!':
+ if (token) {
+ --to;
+ }
+ done = 1;
+ break;
+
+ default:
+ if (isalpha(c) || c == '*' || isdigit(c) || c == '_'
+ || c == '-' || c == '.') {
+ token = 1;
+ } else if (token) {
+ --to;
+ done = 1;
+ } else {
+ ++*at;
+ }
+ }
+ } while (!done);
+
+ return to - *at;
+}
+
+typedef enum { VAL, OP } expect;
+
+static boolean logic_field(const void *me, const char *x, int rule,
+ boolean (*agrees)(const void *, const char *
+ , int, int))
+{
+ boolean left=FALSE, right, not=FALSE;
+ operator oper=OR;
+ int at=0, l;
+ expect next=VAL;
+
+ while ((l = logic_member(x,&at))) {
+ int c = x[at];
+
+ if (next == VAL) {
+ if (c == '!')
+ not = !not;
+ else if (isalpha(c) || c == '*') {
+ right = not ^ agrees(me, x+at, l, rule);
+ if (oper == AND)
+ left &= right;
+ else
+ left |= right;
+ next = OP;
+ } else {
+ _log_err("garbled syntax; expected name (rule #%d)", rule);
+ return FALSE;
+ }
+ } else { /* OP */
+ switch (c) {
+ case '&':
+ oper = AND;
+ break;
+ case '|':
+ oper = OR;
+ break;
+ default:
+ _log_err("garbled syntax; expected & or | (rule #%d)"
+ , rule);
+ D(("%c at %d",c,at));
+ return FALSE;
+ }
+ next = VAL;
+ }
+ at += l;
+ }
+
+ return left;
+}
+
+static boolean is_same(const void *A, const char *b, int len, int rule)
+{
+ int i;
+ const char *a;
+
+ a = A;
+ for (i=0; len > 0; ++i, --len) {
+ if (b[i] != a[i]) {
+ if (b[i++] == '*') {
+ return (!--len || !strncmp(b+i,a+strlen(a)-len,len));
+ } else
+ return FALSE;
+ }
+ }
+ return ( !len );
+}
+
+typedef struct {
+ int day; /* array of 7 bits, one set for today */
+ int minute; /* integer, hour*100+minute for now */
+} TIME;
+
+struct day {
+ const char *d;
+ int bit;
+} static const days[11] = {
+ { "su", 01 },
+ { "mo", 02 },
+ { "tu", 04 },
+ { "we", 010 },
+ { "th", 020 },
+ { "fr", 040 },
+ { "sa", 0100 },
+ { "wk", 076 },
+ { "wd", 0101 },
+ { "al", 0177 },
+ { NULL, 0 }
+};
+
+static TIME time_now(void)
+{
+ struct tm *local;
+ time_t the_time;
+ TIME this;
+
+ the_time = time((time_t *)0); /* get the current time */
+ local = localtime(&the_time);
+ this.day = days[local->tm_wday].bit;
+ this.minute = local->tm_hour*100 + local->tm_min;
+
+ D(("day: 0%o, time: %.4d", this.day, this.minute));
+ return this;
+}
+
+/* take the current date and see if the range "date" passes it */
+static boolean check_time(const void *AT, const char *times, int len, int rule)
+{
+ boolean not,pass;
+ int marked_day, time_start, time_end;
+ const TIME *at;
+ int i,j=0;
+
+ at = AT;
+ D(("chcking: 0%o/%.4d vs. %s", at->day, at->minute, times));
+
+ if (times == NULL) {
+ /* this should not happen */
+ _log_err("internal error: " __FILE__ " line %d", __LINE__);
+ return FALSE;
+ }
+
+ if (times[j] == '!') {
+ ++j;
+ not = TRUE;
+ } else {
+ not = FALSE;
+ }
+
+ for (marked_day = 0; len > 0 && isalpha(times[j]); --len) {
+ int this_day=-1;
+
+ D(("%c%c ?", times[j], times[j+1]));
+ for (i=0; days[i].d != NULL; ++i) {
+ if (tolower(times[j]) == days[i].d[0]
+ && tolower(times[j+1]) == days[i].d[1] ) {
+ this_day = days[i].bit;
+ break;
+ }
+ }
+ j += 2;
+ if (this_day == -1) {
+ _log_err("bad day specified (rule #%d)", rule);
+ return FALSE;
+ }
+ marked_day ^= this_day;
+ }
+ if (marked_day == 0) {
+ _log_err("no day specified");
+ return FALSE;
+ }
+ D(("day range = 0%o", marked_day));
+
+ time_start = 0;
+ for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) {
+ time_start *= 10;
+ time_start += times[i+j]-'0'; /* is this portable? */
+ }
+ j += i;
+
+ if (times[j] == '-') {
+ time_end = 0;
+ for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) {
+ time_end *= 10;
+ time_end += times[i+j]-'0'; /* is this portable */
+ }
+ j += i;
+ } else
+ time_end = -1;
+
+ D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j]));
+ if (i != 5 || time_end == -1) {
+ _log_err("no/bad times specified (rule #%d)", rule);
+ return TRUE;
+ }
+ D(("times(%d to %d)", time_start,time_end));
+ D(("marked_day = 0%o", marked_day));
+
+ /* compare with the actual time now */
+
+ pass = FALSE;
+ if (time_start < time_end) { /* start < end ? --> same day */
+ if ((at->day & marked_day) && (at->minute >= time_start)
+ && (at->minute < time_end)) {
+ D(("time is listed"));
+ pass = TRUE;
+ }
+ } else { /* spans two days */
+ if ((at->day & marked_day) && (at->minute >= time_start)) {
+ D(("caught on first day"));
+ pass = TRUE;
+ } else {
+ marked_day <<= 1;
+ marked_day |= (marked_day & 0200) ? 1:0;
+ D(("next day = 0%o", marked_day));
+ if ((at->day & marked_day) && (at->minute <= time_end)) {
+ D(("caught on second day"));
+ pass = TRUE;
+ }
+ }
+ }
+
+ return (not ^ pass);
+}
+
+static int check_account(const char *service
+ , const char *tty, const char *user)
+{
+ int from=0,to=0,fd=-1;
+ char *buffer=NULL;
+ int count=0;
+ TIME here_and_now;
+ int retval=PAM_SUCCESS;
+
+ here_and_now = time_now(); /* find current time */
+ do {
+ boolean good=TRUE,intime;
+
+ /* here we get the service name field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+
+ if (!buffer || !buffer[0]) {
+ /* empty line .. ? */
+ continue;
+ }
+ ++count;
+
+ good = logic_field(service, buffer, count, is_same);
+ D(("with service: %s", good ? "passes":"fails" ));
+
+ /* here we get the terminal name field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_TIME_CONF "; no tty entry #%d", count);
+ continue;
+ }
+ good &= logic_field(tty, buffer, count, is_same);
+ D(("with tty: %s", good ? "passes":"fails" ));
+
+ /* here we get the username field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_TIME_CONF "; no user entry #%d", count);
+ continue;
+ }
+ good &= logic_field(user, buffer, count, is_same);
+ D(("with user: %s", good ? "passes":"fails" ));
+
+ /* here we get the time field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_TIME_CONF "; no time entry #%d", count);
+ continue;
+ }
+
+ intime = logic_field(&here_and_now, buffer, count, check_time);
+ D(("with time: %s", intime ? "passes":"fails" ));
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (buffer && buffer[0]) {
+ _log_err(PAM_TIME_CONF "; poorly terminated rule #%d", count);
+ continue;
+ }
+
+ if (good && !intime) {
+ /*
+ * for security parse whole file.. also need to ensure
+ * that the buffer is free()'d and the file is closed.
+ */
+ retval = PAM_PERM_DENIED;
+ } else {
+ D(("rule passed"));
+ }
+ } while (buffer);
+
+ return retval;
+}
+
+/* --- public account management functions --- */
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ const char *service=NULL, *tty=NULL;
+ const char *user=NULL;
+
+ /* set service name */
+
+ if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
+ != PAM_SUCCESS || service == NULL) {
+ _log_err("cannot find the current service name");
+ return PAM_ABORT;
+ }
+
+ /* set username */
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL
+ || *user == '\0') {
+ _log_err("cannot determine the user's name");
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* set tty name */
+
+ if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS
+ || tty == NULL) {
+ D(("PAM_TTY not set, probing stdin"));
+ tty = ttyname(STDIN_FILENO);
+ if (tty == NULL) {
+ _log_err("couldn't get the tty name");
+ return PAM_ABORT;
+ }
+ if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) {
+ _log_err("couldn't set tty name");
+ return PAM_ABORT;
+ }
+ }
+
+ if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */
+ tty += 5;
+ }
+
+ /* good, now we have the service name, the user and the terminal name */
+
+ D(("service=%s", service));
+ D(("user=%s", user));
+ D(("tty=%s", tty));
+
+ return check_account(service,tty,user);
+}
+
+/* end of module definition */
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_time_modstruct = {
+ "pam_time",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
diff --git a/contrib/libpam/modules/pam_time/time.conf b/contrib/libpam/modules/pam_time/time.conf
new file mode 100644
index 000000000000..d2062fdb5a37
--- /dev/null
+++ b/contrib/libpam/modules/pam_time/time.conf
@@ -0,0 +1,64 @@
+# this is an example configuration file for the pam_time module. Its syntax
+# was initially based heavily on that of the shadow package (shadow-960129).
+#
+# the syntax of the lines is as follows:
+#
+# services;ttys;users;times
+#
+# white space is ignored and lines maybe extended with '\\n' (escaped
+# newlines). As should be clear from reading these comments,
+# text following a '#' is ignored to the end of the line.
+#
+# the combination of individual users/terminals etc is a logic list
+# namely individual tokens that are optionally prefixed with '!' (logical
+# not) and separated with '&' (logical and) and '|' (logical or).
+#
+# services
+# is a logic list of PAM service names that the rule applies to.
+#
+# ttys
+# is a logic list of terminal names that this rule applies to.
+#
+# users
+# is a logic list of users to whom this rule applies.
+#
+# NB. For these items the simple wildcard '*' may be used only once.
+#
+# times
+# the format here is a logic list of day/time-range
+# entries the days are specified by a sequence of two character
+# entries, MoTuSa for example is Monday Tuesday and Saturday. Note
+# that repeated days are unset MoMo = no day, and MoWk = all weekdays
+# bar Monday. The two character combinations accepted are
+#
+# Mo Tu We Th Fr Sa Su Wk Wd Al
+#
+# the last two being week-end days and all 7 days of the week
+# respectively. As a final example, AlFr means all days except Friday.
+#
+# each day/time-range can be prefixed with a '!' to indicate "anything
+# but"
+#
+# The time-range part is two 24-hour times HHMM separated by a hyphen
+# indicating the start and finish time (if the finish time is smaller
+# than the start time it is deemed to apply on the following day).
+#
+# for a rule to be active, ALL of service+ttys+users must be satisfied
+# by the applying process.
+#
+
+#
+# Here is a simple example: running blank on tty* (any ttyXXX device),
+# the users 'you' and 'me' are denied service all of the time
+#
+
+#blank;tty* & !ttyp*;you|me;!Al0000-2400
+
+# Another silly example, user 'root' is denied xsh access
+# from pseudo terminals at the weekend and on mondays.
+
+#xsh;ttyp*;root;!WdMo0000-2400
+
+#
+# End of example file.
+# \ No newline at end of file
diff --git a/contrib/libpam/modules/pam_unix/CHANGELOG b/contrib/libpam/modules/pam_unix/CHANGELOG
new file mode 100644
index 000000000000..37e4c8501c9d
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/CHANGELOG
@@ -0,0 +1,6 @@
+$Id: CHANGELOG,v 1.1 1996/11/09 19:42:41 morgan Exp $
+
+$Log: CHANGELOG,v $
+Revision 1.1 1996/11/09 19:42:41 morgan
+Initial revision
+
diff --git a/contrib/libpam/modules/pam_unix/Makefile b/contrib/libpam/modules/pam_unix/Makefile
new file mode 100644
index 000000000000..ad1f47f185e4
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/Makefile
@@ -0,0 +1,155 @@
+# $Header$
+#
+# This Makefile controls a build process of the pam_unix modules
+# for Linux-PAM. You should not modify this Makefile.
+#
+# $Log$
+# Revision 1.1.1.2 1998/06/03 03:43:56 adam
+# Import from archive
+#
+# Revision 1.3 1998/05/31 23:48:13 adam
+# Link crypt library as necessary.
+#
+# Revision 1.3 1997/04/05 06:20:58 morgan
+# fakeroot and also lockpwdf is in libc now
+#
+# Revision 1.2 1996/11/10 20:18:59 morgan
+# cross platform support
+#
+# Revision 1.1 1996/11/09 19:44:16 morgan
+# Initial revision
+#
+#
+
+########################################################################
+# some options... uncomment to take effect
+########################################################################
+
+# do you want shadow?
+USE_SHADOW=-D"HAVE_SHADOW_H"
+
+# do you want cracklib?
+ifeq ($(HAVE_CRACKLIB),yes)
+USE_CRACKLIB=-D"USE_CRACKLIB"
+endif
+
+# do you want to use lckpwdf?
+USE_LCKPWDF=-D"USE_LCKPWDF"
+
+# do you need to include the locking functions in the source?
+#NEED_LCKPWDF=-D"NEED_LCKPWDF"
+
+########################################################################
+
+CFLAGS += $(USE_SHADOW) $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF)
+
+ifdef DYNAMIC
+LIBSESSSH = pam_unix_session.so
+LIBAUTHSH = pam_unix_auth.so
+LIBPASSWDSH = pam_unix_passwd.so
+LIBACCOUNT = pam_unix_acct.so
+endif
+
+ifdef STATIC
+LIBSTATIC = libpam_unix.o
+endif
+
+ifdef USE_CRACKLIB
+CRACKLIB = -lcrack
+endif
+
+LIBAUTHOBJ = pam_unix_auth.o support.o
+LIBAUTHSRC = pam_unix_auth.c support.c
+LIBSESSOBJ = pam_unix_sess.o
+LIBSESSSRC = pam_unix_sess.c
+LIBPASSWDSRC = pam_unix_passwd.c
+LIBPASSWDOBJ = pam_unix_passwd.o
+LIBACCOUNTSRC = pam_unix_acct.c
+LIBACCOUNTOBJ = pam_unix_acct.o
+LIBOBJ = $(LIBAUTHOBJ) $(LIBSESSOBJ) $(LIBPASSWDOBJ) $(LIBACCOUNTOBJ)
+LIBSRC = $(LIBAUTHSRC) $(LIBSESSSRC) $(LIBPASSWDSRC) $(LIBACCOUNTSRC)
+
+LIBSHARED = $(LIBSESSSH) $(LIBAUTHSH) $(LIBPASSWDSH) $(LIBACCOUNT)
+
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) -c $< -o $@
+
+static/%.o: %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) -c $< -o $@
+
+
+########################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+info:
+ @echo
+ @echo "*** Building pam-unix(alpha) module of the framework..."
+ @echo
+
+all: dirs info $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ mkdir -p ./dynamic
+endif
+ifdef STATIC
+ mkdir -p ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; \
+ ./register_static pam_unix_auth pam_unix/$(LIBSTATIC) ; \
+ ./register_static pam_unix_acct "" ; \
+ )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBAUTHSH): $(LIBAUTHSRC) $(LIBOBJD)
+ $(LD_D) -o $@ $(addprefix dynamic/,$(LIBAUTHOBJ)) -lcrypt
+
+$(LIBSESSSH): $(LIBSESSSRC) $(LIBOBJD)
+ $(LD_D) -o $@ $(addprefix dynamic/,$(LIBSESSOBJ))
+
+$(LIBPASSWDSH): $(LIBPASSWDSRC) $(LIBOBJD)
+ $(LD_D) -o $@ $(addprefix dynamic/,$(LIBPASSWDOBJ)) $(CRACKLIB) -lcrypt
+
+$(LIBACCOUNT): $(LIBACCOUNTSRC) $(LIBOBJD)
+ $(LD_D) -o $@ $(addprefix dynamic/,$(LIBACCOUNTOBJ))
+endif
+
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ mkdir -p $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ install -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ cd $(FAKEROOT)$(SECUREDIR) && rm -f $(LIBSHARED)
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) a.out core *~
+
+extraclean: clean
+ rm -f *.a *.out *.o *.so *.bak
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
diff --git a/contrib/libpam/modules/pam_unix/README b/contrib/libpam/modules/pam_unix/README
new file mode 100644
index 000000000000..082e99697da2
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/README
@@ -0,0 +1,39 @@
+This is the README for pam_unix in Linux-PAM-0.53.
+--------------------------------------------------
+
+pam_unix comes as four separate modules:
+
+pam_unix_auth: authentication module providing
+ pam_authenticate() and pam_setcred() hooks
+
+ NO options are recognized. Credential facilities are trivial
+ (function simply returns)
+
+pam_unix_sess: session module, providing session logging
+
+ "debug" and "trace" arguments are accepted, which indicate the
+ logging-level for syslog.
+
+ "debug" -> LOG_DEBUG [ also default ]
+ "trace" -> LOG_AUTHPRIV
+
+pam_unix_acct: account management, providing shadow account
+ managment features, password aging etc..
+
+ NO options are recognized. Account managment trivial without
+ shadow active.
+
+pam_unix_passwd: password updating facilities providing
+ cracklib password strength checking facilities.
+
+ if compiled, the default behavior is to check passwords
+ strictly using CrackLib. This behavior can be turned off
+ with the argument
+
+ "strict=false"
+
+ invalid arguments are logged to syslog.
+
+------------------------------
+- Andrew 1996/11/9
+------------------------------
diff --git a/contrib/libpam/modules/pam_unix/pam_unix_acct.c b/contrib/libpam/modules/pam_unix/pam_unix_acct.c
new file mode 100644
index 000000000000..5c0546aa1f8f
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/pam_unix_acct.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright Elliot Lee, 1996. All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+/* pam_unix_acct.c module, different track */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#define __USE_MISC
+#include <pwd.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+#include <time.h>
+
+#define PAM_SM_ACCOUNT
+
+#ifndef LINUX
+# include <security/pam_appl.h>
+#endif
+
+#define _PAM_EXTERN_FUNCTIONS
+#include <security/pam_modules.h>
+
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+#ifdef HAVE_SHADOW_H
+ const char *uname;
+ int retval;
+ time_t curdays;
+ struct spwd *spent;
+ struct passwd *pwent;
+
+ setpwent();
+ setspent();
+ retval = pam_get_item(pamh,PAM_USER,(const void **)&uname);
+ if(retval != PAM_SUCCESS || uname == NULL) {
+ return PAM_SUCCESS; /* Couldn't get username, just ignore this
+ (i.e. they don't have any expiry info available */
+ }
+ pwent = getpwnam(uname);
+ if(!pwent)
+ return PAM_USER_UNKNOWN;
+ if(strcmp(pwent->pw_passwd,"x"))
+ return PAM_SUCCESS; /* They aren't using shadow passwords & expiry
+ info */
+ spent = getspnam(uname);
+ if(!spent)
+ return PAM_SUCCESS; /* Couldn't get username from shadow, just ignore this
+ (i.e. they don't have any expiry info available */
+ curdays = time(NULL)/(60*60*24);
+ if((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact))
+ && (spent->sp_max != -1) && (spent->sp_inact != -1))
+ return PAM_ACCT_EXPIRED;
+ if((curdays > spent->sp_expire) && (spent->sp_expire != -1))
+ return PAM_ACCT_EXPIRED;
+ endspent();
+ endpwent();
+#endif
+ return PAM_SUCCESS;
+}
+
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_unix_acct_modstruct = {
+ "pam_unix_acct",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL,
+};
+#endif
diff --git a/contrib/libpam/modules/pam_unix/pam_unix_auth.c b/contrib/libpam/modules/pam_unix/pam_unix_auth.c
new file mode 100644
index 000000000000..95f13d0abdc6
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/pam_unix_auth.c
@@ -0,0 +1,307 @@
+/* $Header: /home/morgan/pam/Linux-PAM-0.59/modules/pam_unix/RCS/pam_unix_auth.c,v 1.1 1996/11/09 19:44:35 morgan Exp morgan $ */
+
+/*
+ * Copyright Alexander O. Yuriev, 1996. All rights reserved.
+ * NIS+ support by Thorsten Kukuk <kukuk@weber.uni-paderborn.de>
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+/*
+ * $Log: pam_unix_auth.c,v $
+ *
+ * Revision 1.9 1996/05/26 04:13:04 morgan
+ * added static support
+ *
+ * Revision 1.8 1996/05/21 03:51:58 morgan
+ * added "const" to rcsid[] definition
+ *
+ * Revision 1.7 1996/04/19 03:25:57 alex
+ * minor corrections.
+ *
+ * Revision 1.6 1996/04/17 01:05:05 alex
+ * _pam_auth_unix() cleaned up - non-authentication code is made into funcs
+ * and mostly moved out to support.c.
+ *
+ * Revision 1.5 1996/04/16 21:12:46 alex
+ * unix authentication works on Bach again. This is a tranitional stage.
+ * I really don't like that _pam_unix_auth() grew into a monster that does
+ * prompts etc etc. They should go into other functions.
+ *
+ * Revision 1.4 1996/04/07 08:06:12 morgan
+ * tidied up a little
+ *
+ * Revision 1.3 1996/04/07 07:34:07 morgan
+ * added conversation support. Now the module is capable of obtaining a
+ * username and a password all by itself.
+ *
+ * Revision 1.2 1996/03/29 02:31:19 morgan
+ * Marek Michalkiewicz's small patches for shadow support.
+ *
+ * Revision 1.1 1996/03/09 09:10:57 morgan
+ * Initial revision
+ *
+ */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#define __USE_BSD
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+#ifndef NDEBUG
+
+#include <syslog.h>
+
+#endif /* NDEBUG */
+
+#ifdef HAVE_SHADOW_H
+
+#include <shadow.h>
+
+#endif /* HAVE_SHADOW_H */
+
+#ifndef LINUX
+
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#define _PAM_EXTERN_FUNCTIONS
+#include <security/pam_modules.h>
+
+static const char rcsid[] = "$Id: pam_unix_auth.c,v 1.1 1996/11/09 19:44:35 morgan Exp morgan $ pam_unix authentication functions. alex@bach.cis.temple.edu";
+
+/* Define function phototypes */
+
+extern char *crypt(const char *key, const char *salt); /* This should have
+ been in unistd.h
+ but it is not */
+extern int converse( pam_handle_t *pamh,
+ int nargs,
+ struct pam_message **message,
+ struct pam_response **response );
+
+extern int _set_auth_tok( pam_handle_t *pamh,
+ int flags, int argc,
+ const char **argv );
+
+static int _pam_auth_unix( pam_handle_t *pamh,
+ int flags, int argc,
+ const char **argv );
+
+static int _pam_set_credentials_unix ( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char ** argv ) ;
+
+
+/* Fun starts here :)
+ *
+ * _pam_auth_unix() actually performs UNIX/shadow authentication
+ *
+ * First, if shadow support is available, attempt to perform
+ * authentication using shadow passwords. If shadow is not
+ * available, or user does not have a shadow password, fallback
+ * onto a normal UNIX authentication
+ */
+
+static int _pam_auth_unix( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+{
+ int retval;
+ struct passwd *pw;
+ const char *name;
+ char *p, *pp;
+ const char *salt;
+
+#ifdef HAVE_SHADOW_H
+
+ struct spwd *sp;
+
+#endif
+
+ /* get the user'name' */
+
+ if ( (retval = pam_get_user( pamh, &name, "login: ") ) != PAM_SUCCESS )
+ return retval;
+
+ /*
+ * at some point we will have to make this module pay
+ * attention to arguments, like 'pam_first_pass' etc...
+ */
+
+ pw = getpwnam ( name );
+
+ /* For NIS+, root cannot get password for lesser user */
+ if (pw) {
+ uid_t save_euid, save_uid;
+
+ save_uid = getuid ();
+ save_euid = geteuid();
+ if (setreuid (0,pw->pw_uid) >= 0) {
+ pw = getpwnam ( name );
+ setreuid (save_uid,save_euid);
+ }
+ }
+
+ if ( pw && (!pw->pw_passwd || pw->pw_passwd[0] == '\0') &&
+ !(flags & PAM_DISALLOW_NULL_AUTHTOK)) {
+ return PAM_SUCCESS;
+ }
+ pam_get_item( pamh, PAM_AUTHTOK, (void*) &p );
+
+ if ( !p )
+ {
+ retval = _set_auth_tok( pamh, flags, argc, argv );
+ if ( retval != PAM_SUCCESS )
+ return retval;
+ }
+
+ /*
+ We have to call pam_get_item() again because value of p should
+ change
+ */
+
+ pam_get_item( pamh, PAM_AUTHTOK, (void*) &p );
+
+
+ if (pw)
+ {
+
+#ifdef HAVE_SHADOW_H
+
+ /*
+ * Support for shadow passwords on Linux and SVR4-based
+ * systems. Shadow passwords are optional on Linux - if
+ * there is no shadow password, use the non-shadow one.
+ */
+
+ sp = getspnam( name );
+ if (sp && (!strcmp(pw->pw_passwd,"x")))
+ {
+ /* TODO: check if password has expired etc. */
+ salt = sp->sp_pwdp;
+ }
+ else
+#endif
+ salt = pw->pw_passwd;
+ }
+ else
+ return PAM_USER_UNKNOWN;
+
+ /* The 'always-encrypt' method does not make sense in PAM
+ because the framework requires return of a different
+ error code for non-existant users -- alex */
+
+ if ( ( !pw->pw_passwd ) && ( !p ) )
+ if ( flags && PAM_DISALLOW_NULL_AUTHTOK )
+ return PAM_SUCCESS;
+ else
+ return PAM_AUTH_ERR;
+
+ pp = crypt(p, salt);
+
+ if ( strcmp( pp, salt ) == 0 )
+ return PAM_SUCCESS;
+
+ return PAM_AUTH_ERR;
+}
+
+/*
+ * The only thing _pam_set_credentials_unix() does is initialization of
+ * UNIX group IDs.
+ *
+ * Well, everybody but me on linux-pam is convinced that it should not
+ * initialize group IDs, so I am not doing it but don't say that I haven't
+ * warned you. -- AOY
+ */
+
+static int _pam_set_credentials_unix ( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+
+{ /* FIX ME: incorrect error code */
+
+ return PAM_SUCCESS; /* This is a wrong result code. From what I
+ remember from reafing one of the guides
+ there's an error-level saying 'N/A func'
+ -- AOY
+ */
+}
+
+/*
+ * PAM framework looks for these entry-points to pass control to the
+ * authentication module.
+ */
+
+PAM_EXTERN
+int pam_sm_authenticate( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+{
+ return _pam_auth_unix( pamh, flags, argc, argv );
+}
+
+PAM_EXTERN
+int pam_sm_setcred( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv)
+{
+ return _pam_set_credentials_unix ( pamh, flags, argc, argv ) ;
+}
+
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_unix_auth_modstruct = {
+ "pam_unix_auth",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+#endif
diff --git a/contrib/libpam/modules/pam_unix/pam_unix_passwd.c b/contrib/libpam/modules/pam_unix/pam_unix_passwd.c
new file mode 100644
index 000000000000..de1345e85285
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/pam_unix_passwd.c
@@ -0,0 +1,813 @@
+
+/* Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
+ Copyright (C) 1996. */
+
+/*
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+/*
+ How it works:
+ Gets in username (has to be done) from the calling program
+ Does authentication of user (only if we are not running as root)
+ Gets new password/checks for sanity
+ Sets it.
+ */
+
+#define PAM_SM_PASSWORD
+
+/* #define DEBUG 1 */
+
+#include <stdio.h>
+#include <sys/time.h>
+#define _BSD_SOURCE
+#define _SVID_SOURCE
+#include <errno.h>
+#define __USE_BSD
+#define _BSD_SOURCE
+#include <pwd.h>
+#include <sys/types.h>
+
+/* why not defined? */
+void setpwent(void);
+void endpwent(void);
+int chmod(const char *path, mode_t mode);
+struct passwd *fgetpwent(FILE *stream);
+int putpwent(const struct passwd *p, FILE *stream);
+
+#include <unistd.h>
+char *crypt(const char *key, const char *salt);
+#ifdef USE_CRACKLIB
+#include <crack.h>
+#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <security/_pam_macros.h>
+
+#ifndef LINUX /* AGM added this as of 0.2 */
+#include <security/pam_appl.h>
+#endif /* ditto */
+#include <security/pam_modules.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#define MAX_PASSWD_TRIES 3
+#define OLD_PASSWORD_PROMPT "Password: "
+#define NEW_PASSWORD_PROMPT "New password: "
+#define AGAIN_PASSWORD_PROMPT "New password (again): "
+#define PW_TMPFILE "/etc/npasswd"
+#define SH_TMPFILE "/etc/nshadow"
+#define CRACKLIB_DICTS "/usr/lib/cracklib_dict"
+
+/* Various flags for the getpass routine to send back in... */
+#define PPW_EXPIRED 1
+#define PPW_EXPIRING 2
+#define PPW_WILLEXPIRE 4
+#define PPW_NOSUCHUSER 8
+#define PPW_SHADOW 16
+#define PPW_TOOEARLY 32
+#define PPW_ERROR 64
+
+#ifndef DO_TEST
+#define STATIC static
+#else
+#define STATIC
+#endif
+/* Sets a password for the specified user to the specified password
+ Returns flags PPW_*, or'd. */
+STATIC int _do_setpass(char *forwho, char *towhat, int flags);
+/* Gets a password for the specified user
+ Returns flags PPW_*, or'd. */
+STATIC int _do_getpass(char *forwho, char **theirpass);
+/* Checks whether the password entered is same as listed in the database
+ 'entered' should not be crypt()'d or anything (it should be as the
+ user entered it...), 'listed' should be as it is listed in the
+ password database file */
+STATIC int _do_checkpass(const char *entered, char *listed);
+
+/* sends a one-way message to the user, either error or info... */
+STATIC int conv_sendmsg(struct pam_conv *aconv, const char *message, int style);
+/* sends a message and returns the results of the conversation */
+STATIC int conv_getitem(struct pam_conv *aconv, char *message, int style,
+ char **result);
+
+PAM_EXTERN
+int pam_sm_chauthtok( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv);
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-unix_passwd", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+#ifdef NEED_LCKPWDF
+/* This is a hack, but until libc and glibc both include this function
+ * by default (libc only includes it if nys is not being used, at the
+ * moment, and glibc doesn't appear to have it at all) we need to have
+ * it here, too. :-(
+ *
+ * This should not become an official part of PAM.
+ *
+ * BEGIN_HACK
+*/
+
+/*
+ * lckpwdf.c -- prevent simultaneous updates of password files
+ *
+ * Before modifying any of the password files, call lckpwdf(). It may block
+ * for up to 15 seconds trying to get the lock. Return value is 0 on success
+ * or -1 on failure. When you are done, call ulckpwdf() to release the lock.
+ * The lock is also released automatically when the process exits. Only one
+ * process at a time may hold the lock.
+ *
+ * These functions are supposed to be conformant with AT&T SVID Issue 3.
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * public domain.
+ */
+
+#include <fcntl.h>
+#include <signal.h>
+
+#define LOCKFILE "/etc/.pwd.lock"
+#define TIMEOUT 15
+
+static int lockfd = -1;
+
+static int
+set_close_on_exec(int fd)
+{
+ int flags = fcntl(fd, F_GETFD, 0);
+ if (flags == -1)
+ return -1;
+ flags |= FD_CLOEXEC;
+ return fcntl(fd, F_SETFD, flags);
+}
+
+static int
+do_lock(int fd)
+{
+ struct flock fl;
+
+ memset(&fl, 0, sizeof fl);
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ return fcntl(fd, F_SETLKW, &fl);
+}
+
+static void
+alarm_catch(int sig)
+{
+/* does nothing, but fcntl F_SETLKW will fail with EINTR */
+}
+
+static int lckpwdf(void)
+{
+ struct sigaction act, oldact;
+ sigset_t set, oldset;
+
+ if (lockfd != -1)
+ return -1;
+
+ lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
+ if (lockfd == -1)
+ return -1;
+ if (set_close_on_exec(lockfd) == -1)
+ goto cleanup_fd;
+
+ memset(&act, 0, sizeof act);
+ act.sa_handler = alarm_catch;
+ act.sa_flags = 0;
+ sigfillset(&act.sa_mask);
+ if (sigaction(SIGALRM, &act, &oldact) == -1)
+ goto cleanup_fd;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGALRM);
+ if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1)
+ goto cleanup_sig;
+
+ alarm(TIMEOUT);
+ if (do_lock(lockfd) == -1)
+ goto cleanup_alarm;
+ alarm(0);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ sigaction(SIGALRM, &oldact, NULL);
+ return 0;
+
+cleanup_alarm:
+ alarm(0);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+cleanup_sig:
+ sigaction(SIGALRM, &oldact, NULL);
+cleanup_fd:
+ close(lockfd);
+ lockfd = -1;
+ return -1;
+}
+
+static int
+ulckpwdf(void)
+{
+ unlink(LOCKFILE);
+ if (lockfd == -1)
+ return -1;
+
+ if (close(lockfd) == -1) {
+ lockfd = -1;
+ return -1;
+ }
+ lockfd = -1;
+ return 0;
+}
+/* END_HACK */
+#endif
+
+#define PAM_FAIL_CHECK if(retval != PAM_SUCCESS) { return retval; }
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ char *usrname, *curpass, *newpass; /* pointers to the username,
+ current password, and new password */
+
+ struct pam_conv *appconv; /* conversation with the app */
+ struct pam_message msg, *pmsg; /* Misc for conversations */
+ struct pam_response *resp;
+
+ int retval=0; /* Gets the return values for all our function calls */
+ unsigned int pflags=0; /* Holds the flags from our getpass & setpass
+ functions */
+
+ const char *cmiscptr; /* Utility variables, used for different purposes at
+ different times */
+ char *miscptr; /* Utility variables, used for different purposes at
+ different times */
+ unsigned int miscint;
+ int fascist = 1; /* Be fascist by default. If compiled with cracklib,
+ call cracklib. Otherwise just check length... */
+
+ char argbuf[256],argval[256];
+ int i;
+
+
+ retval = pam_get_item(pamh,PAM_CONV,(const void **) &appconv);
+ PAM_FAIL_CHECK;
+
+ retval = pam_get_item(pamh,PAM_USER,(const void **) &usrname);
+ PAM_FAIL_CHECK;
+ if(flags & PAM_PRELIM_CHECK) {
+ pflags = _do_getpass(usrname,&miscptr);
+ if(pflags & PPW_NOSUCHUSER)
+ return PAM_USER_UNKNOWN;
+ else if(pflags & ~(PPW_SHADOW|PPW_EXPIRING|PPW_WILLEXPIRE))
+ return PAM_AUTHTOK_ERR;
+ else
+ return PAM_SUCCESS;
+ } /* else... */
+#ifdef DEBUG
+ fprintf(stderr,"Got username of %s\n",usrname);
+#endif
+ if((usrname == NULL) || (strlen(usrname) < 1)) {
+ /* The app is supposed to get us the username! */
+ retval = PAM_USER_UNKNOWN;
+ PAM_FAIL_CHECK;
+ }
+
+ for(i=0; i < argc; i++) {
+ {
+ char *tmp = x_strdup(argv[i]);
+ strncpy(argbuf,strtok(tmp ,"="),255);
+ strncpy(argval,strtok(NULL,"="),255);
+ free(tmp);
+ }
+
+ /* For PC functionality use "strict" -- historically "fascist" */
+ if(!strcmp(argbuf,"strict") || !strcmp(argbuf, "fascist"))
+
+ if(!strcmp(argval,"true"))
+ fascist = 1;
+ else if(!strcmp(argval,"false"))
+ fascist = 0;
+ else
+ return PAM_SERVICE_ERR;
+ else {
+ _pam_log(LOG_ERR,"Unknown option: %s",argbuf);
+ return PAM_SERVICE_ERR;
+ }
+ }
+
+
+ /* Now we have all the initial information we need from the app to
+ set things up (we assume that getting the username succeeded...) */
+ retval = pam_get_item(pamh,PAM_OLDAUTHTOK,(const void **) &curpass);
+ PAM_FAIL_CHECK;
+ if(getuid()) { /* If this is being run by root, we don't need to get their
+ old password.
+ note */
+ /* If we haven't been given a password yet, prompt for one... */
+ miscint=0;
+ while((curpass == NULL) && (miscint++ < MAX_PASSWD_TRIES)) {
+ pflags = _do_getpass(usrname,&miscptr);
+ if(pflags & PPW_NOSUCHUSER)
+ return PAM_USER_UNKNOWN; /* If the user that was passed in doesn't
+ exist, say so and exit (app passes in
+ username) */
+
+ /* Get the password from the user... */
+ pmsg = &msg;
+
+ msg.msg_style = PAM_PROMPT_ECHO_OFF;
+ msg.msg = OLD_PASSWORD_PROMPT;
+ resp = NULL;
+
+ retval = appconv->conv(1, (const struct pam_message **) &pmsg,
+ &resp, appconv->appdata_ptr);
+
+ PAM_FAIL_CHECK;
+ curpass = resp->resp;
+ free (resp);
+ if(_do_checkpass(curpass?curpass:"",miscptr)) {
+ int abortme = 0;
+
+ /* password is incorrect... */
+ if (curpass && curpass[0] == '\0') {
+ /* ...and it was zero-length; user wishes to abort change */
+ abortme = 1;
+ }
+ if (curpass) { free (curpass); }
+ curpass = NULL;
+ if (abortme) {
+ conv_sendmsg(appconv,"Password change aborted.",PAM_ERROR_MSG);
+ return PAM_AUTHTOK_ERR;
+ }
+ }
+ }
+
+ if(curpass == NULL)
+ return PAM_AUTH_ERR; /* They didn't seem to enter the right password
+ for three tries - error */
+ pam_set_item(pamh, PAM_OLDAUTHTOK, (void *)curpass);
+ } else {
+#ifdef DEBUG
+ fprintf(stderr,"I am ROOT!\n");
+#endif
+ pflags = _do_getpass(usrname,&curpass);
+ if(curpass == NULL)
+ curpass = x_strdup("");
+ }
+ if(pflags & PPW_TOOEARLY) {
+ conv_sendmsg(appconv,"You must wait longer to change your password",
+ PAM_ERROR_MSG);
+ return PAM_AUTHTOK_ERR;
+ }
+ if(pflags & PPW_WILLEXPIRE)
+ conv_sendmsg(appconv,"Your password is about to expire",PAM_TEXT_INFO);
+ else if(pflags & PPW_EXPIRED)
+ return PAM_ACCT_EXPIRED; /* If their account has expired, we can't auth
+ them to change their password */
+ if(!(pflags & PPW_EXPIRING) && (flags & PAM_CHANGE_EXPIRED_AUTHTOK))
+ return PAM_SUCCESS;
+ /* If we haven't been given a password yet, prompt for one... */
+ miscint=0;
+ pam_get_item(pamh,PAM_AUTHTOK,(const void **)&newpass);
+ cmiscptr = NULL;
+ while((newpass == NULL) && (miscint++ < MAX_PASSWD_TRIES)) {
+
+ /* Get the password from the user... */
+ pmsg = &msg;
+
+ msg.msg_style = PAM_PROMPT_ECHO_OFF;
+ msg.msg = NEW_PASSWORD_PROMPT;
+ resp = NULL;
+
+ retval = appconv->conv(1, (const struct pam_message **) &pmsg,
+ &resp, appconv->appdata_ptr);
+
+ PAM_FAIL_CHECK;
+ newpass = resp->resp;
+ free (resp);
+
+#ifdef DEBUG
+ if(newpass)
+ fprintf(stderr,"Got password of %s\n",newpass);
+ else
+ fprintf(stderr,"No new password...\n");
+#endif
+ if (newpass[0] == '\0') { free (newpass); newpass = (char *) 0; }
+ cmiscptr=NULL;
+ if(newpass) {
+#ifdef USE_CRACKLIB
+ if(fascist && getuid())
+ cmiscptr = FascistCheck(newpass,CRACKLIB_DICTS);
+#else
+ if(fascist && getuid() && strlen(newpass) < 6)
+ cmiscptr = "You must choose a longer password";
+#endif
+ if(curpass)
+ if(!strcmp(curpass,newpass)) {
+ cmiscptr="You must choose a new password.";
+ newpass=NULL;
+ }
+ } else {
+ /* We want to abort the password change */
+ conv_sendmsg(appconv,"Password change aborted",PAM_ERROR_MSG);
+ return PAM_AUTHTOK_ERR;
+ }
+ if(!cmiscptr) {
+ /* We ask them to enter their password again... */
+ /* Get the password from the user... */
+ pmsg = &msg;
+
+ msg.msg_style = PAM_PROMPT_ECHO_OFF;
+ msg.msg = AGAIN_PASSWORD_PROMPT;
+ resp = NULL;
+
+ retval = appconv->conv(1, (const struct pam_message **) &pmsg,
+ &resp, appconv->appdata_ptr);
+
+ PAM_FAIL_CHECK;
+ miscptr = resp->resp;
+ free (resp);
+ if (miscptr[0] == '\0') { free (miscptr); miscptr = (char *) 0; }
+ if(!miscptr) { /* Aborting password change... */
+ conv_sendmsg(appconv,"Password change aborted",PAM_ERROR_MSG);
+ return PAM_AUTHTOK_ERR;
+ }
+ if(!strcmp(newpass,miscptr)) {
+ miscptr=NULL;
+ break;
+ }
+ conv_sendmsg(appconv,"You must enter the same password twice.",
+ PAM_ERROR_MSG);
+ miscptr=NULL;
+ newpass=NULL;
+ }
+ else {
+ conv_sendmsg(appconv,cmiscptr,PAM_ERROR_MSG);
+ newpass = NULL;
+ }
+ }
+ if(cmiscptr) {
+ /* conv_sendmsg(appconv,cmiscptr,PAM_ERROR_MSG); */
+ return PAM_AUTHTOK_ERR;
+ } else if(newpass == NULL)
+ return PAM_AUTHTOK_ERR; /* They didn't seem to enter the right password
+ for three tries - error */
+#ifdef DEBUG
+ printf("Changing password for sure!\n");
+#endif
+ /* From now on, we are bound and determined to get their password
+ changed :-) */
+ pam_set_item(pamh, PAM_AUTHTOK, (void *)newpass);
+ retval = _do_setpass(usrname,newpass,pflags);
+#ifdef DEBUG
+ fprintf(stderr,"retval was %d\n",retval);
+#endif
+ if(retval & ~PPW_SHADOW) {
+ conv_sendmsg(appconv,"Error: Password NOT changed",PAM_ERROR_MSG);
+ return PAM_AUTHTOK_ERR;
+ } else {
+ conv_sendmsg(appconv,"Password changed",PAM_TEXT_INFO);
+ return PAM_SUCCESS;
+ }
+}
+
+/* _do_checkpass() returns 0 on success, non-0 on failure */
+STATIC int _do_checkpass(const char *entered, char *listed)
+{
+ char salt[3];
+ if ((strlen(listed) == 0) &&(strlen(entered) == 0)) {
+ /* no password in database; no password entered */
+ return (0);
+ }
+ salt[0]=listed[0]; salt[1]=listed[1]; salt[2]='\0';
+ return strcmp(crypt(entered,salt),listed);
+}
+
+STATIC char mksalt(int seed) {
+ int num = seed % 64;
+
+ if (num < 26)
+ return 'a' + num;
+ else if (num < 52)
+ return 'A' + (num - 26);
+ else if (num < 62)
+ return '0' + (num - 52);
+ else if (num == 63)
+ return '.';
+ else
+ return '/';
+}
+
+STATIC int _do_setpass(char *forwho, char *towhat,int flags)
+{
+ struct passwd *pwd=NULL, *tmpent=NULL;
+ FILE *pwfile,*opwfile;
+ char thesalt[3];
+ int retval=0;
+ struct timeval time1;
+ int err = 0;
+#ifdef HAVE_SHADOW_H
+ struct spwd *spwdent=NULL, *stmpent=NULL;
+#endif
+ if(flags & PPW_SHADOW) { retval |= PPW_SHADOW; }
+ gettimeofday(&time1, NULL);
+ srand(time1.tv_usec);
+ thesalt[0]=mksalt(rand());
+ thesalt[1]=mksalt(rand());
+ thesalt[2]='\0';
+
+ /* lock the entire password subsystem */
+#ifdef USE_LCKPWDF
+ lckpwdf();
+#endif
+ setpwent();
+ pwd = getpwnam(forwho);
+#ifdef DEBUG
+ printf("Got %p, for %s (salt %s)\n",pwd,
+ forwho,thesalt);
+#endif
+ if(pwd == NULL)
+ return PPW_NOSUCHUSER;
+ endpwent();
+
+#ifdef HAVE_SHADOW_H
+ if(flags & PPW_SHADOW) {
+ spwdent = getspnam(forwho);
+ if(spwdent == NULL)
+ return PPW_NOSUCHUSER;
+ spwdent->sp_pwdp = towhat;
+ spwdent->sp_lstchg = time(NULL)/(60*60*24);
+ pwfile = fopen(SH_TMPFILE,"w");
+ opwfile = fopen("/etc/shadow","r");
+ if(pwfile == NULL || opwfile == NULL)
+ return PPW_ERROR;
+ chown(SH_TMPFILE,0,0);
+ chmod(SH_TMPFILE,0600);
+ stmpent=fgetspent(opwfile);
+ while(stmpent) {
+ if(!strcmp(stmpent->sp_namp,forwho)) {
+ stmpent->sp_pwdp = crypt(towhat,thesalt);
+ stmpent->sp_lstchg = time(NULL)/(60*60*24);
+#ifdef DEBUG
+ fprintf(stderr,"Set password %s for %s\n",stmpent->sp_pwdp,
+ forwho);
+#endif
+ }
+ if (putspent(stmpent,pwfile)) {
+ fprintf(stderr, "error writing entry to shadow file: %s\n",
+ strerror(errno));
+ err = 1;
+ retval = PPW_ERROR;
+ break;
+ }
+ stmpent=fgetspent(opwfile);
+ }
+ fclose(opwfile);
+
+ if (fclose(pwfile)) {
+ fprintf(stderr, "error writing entries to shadow file: %s\n",
+ strerror(errno));
+ retval = PPW_ERROR;
+ err = 1;
+ }
+
+ if (!err)
+ rename(SH_TMPFILE,"/etc/shadow");
+ else
+ unlink(SH_TMPFILE);
+ } else {
+ pwd->pw_passwd = towhat;
+ pwfile = fopen(PW_TMPFILE,"w");
+ opwfile = fopen("/etc/passwd","r");
+ if(pwfile == NULL || opwfile == NULL)
+ return PPW_ERROR;
+ chown(PW_TMPFILE,0,0);
+ chmod(PW_TMPFILE,0644);
+ tmpent=fgetpwent(opwfile);
+ while(tmpent) {
+ if(!strcmp(tmpent->pw_name,forwho)) {
+ tmpent->pw_passwd = crypt(towhat,thesalt);
+ }
+ if (putpwent(tmpent,pwfile)) {
+ fprintf(stderr, "error writing entry to password file: %s\n",
+ strerror(errno));
+ err = 1;
+ retval = PPW_ERROR;
+ break;
+ }
+ tmpent=fgetpwent(opwfile);
+ }
+ fclose(opwfile);
+
+ if (fclose(pwfile)) {
+ fprintf(stderr, "error writing entries to password file: %s\n",
+ strerror(errno));
+ retval = PPW_ERROR;
+ err = 1;
+ }
+
+ if (!err)
+ rename(PW_TMPFILE,"/etc/passwd");
+ else
+ unlink(PW_TMPFILE);
+ }
+#else
+ pwd->pw_passwd = towhat;
+ pwfile = fopen(PW_TMPFILE,"w");
+ opwfile = fopen("/etc/passwd","r");
+ if(pwfile == NULL || opwfile == NULL)
+ return PPW_ERROR;
+ chown(PW_TMPFILE,0,0);
+ chmod(PW_TMPFILE,0644);
+ tmpent=fgetpwent(opwfile);
+ while(tmpent) {
+ if(!strcmp(tmpent->pw_name,forwho)) {
+ tmpent->pw_passwd = crypt(towhat,thesalt);
+ }
+ if (putpwent(tmpent,pwfile)) {
+ fprintf(stderr, "error writing entry to shadow file: %s\n",
+ strerror(errno));
+ err = 1;
+ retval = PPW_ERROR;
+ break;
+ }
+ tmpent=fgetpwent(opwfile);
+ }
+ fclose(opwfile);
+
+ if (fclose(pwfile)) {
+ fprintf(stderr, "error writing entries to password file: %s\n",
+ strerror(errno));
+ retval = PPW_ERROR;
+ err = 1;
+ }
+
+ if (!err)
+ rename(PW_TMPFILE,"/etc/passwd");
+ else
+ unlink(PW_TMPFILE);
+#endif
+ /* unlock the entire password subsystem */
+#ifdef USE_LCKPWDF
+ ulckpwdf();
+#endif
+ return retval;
+}
+
+STATIC int _do_getpass(char *forwho, char **theirpass)
+{
+ struct passwd *pwd=NULL; /* Password and shadow password */
+#ifdef HAVE_SHADOW_H
+ struct spwd *spwdent=NULL; /* file entries for the user */
+ time_t curdays;
+#endif
+ int retval=0;
+ /* UNIX passwords area */
+ setpwent();
+ pwd = getpwnam(forwho); /* Get password file entry... */
+ endpwent();
+ if(pwd == NULL)
+ return PPW_NOSUCHUSER; /* We don't need to do the rest... */
+#ifdef HAVE_SHADOW_H
+ if(!strcmp(pwd->pw_passwd,"x")) {
+ /* ...and shadow password file entry for this user, if shadowing
+ is enabled */
+ retval |= PPW_SHADOW;
+ setspent();
+ spwdent = getspnam(forwho);
+ endspent();
+ if(spwdent == NULL)
+ return PPW_NOSUCHUSER;
+ *theirpass = x_strdup(spwdent->sp_pwdp);
+
+ /* We have the user's information, now let's check if their account
+ has expired (60 * 60 * 24 = number of seconds in a day) */
+
+ /* Get the current number of days since 1970 */
+ curdays = time(NULL)/(60*60*24);
+ if((curdays < (spwdent->sp_lstchg + spwdent->sp_min))
+ && (spwdent->sp_min != -1))
+ retval |= PPW_TOOEARLY;
+ else if((curdays
+ > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact))
+ && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1))
+ /* Their password change has been put off too long,
+ OR their account has just plain expired */
+ retval |= PPW_EXPIRED;
+ else if((curdays > (spwdent->sp_lstchg + spwdent->sp_max))
+ && (spwdent->sp_max != -1))
+ /* Their passwd needs to be changed */
+ retval |= PPW_EXPIRING;
+ else if((curdays > (spwdent->sp_lstchg
+ + spwdent->sp_max - spwdent->sp_warn))
+ && (spwdent->sp_max != -1) && (spwdent->sp_warn != -1))
+ retval |= PPW_WILLEXPIRE;
+/* if(spwdent->sp_lstchg < 0)
+ retval &= ~(PPW_WILLEXPIRE | PPW_EXPIRING | PPW_EXPIRED);
+ if(spwdent->sp_max < 0)
+ retval &= ~(PPW_EXPIRING | PPW_EXPIRED); */
+ } else {
+ *theirpass = (char *)x_strdup(pwd->pw_passwd);
+ }
+
+#else
+ *theirpass = (char *) x_strdup(pwd->pw_passwd);
+#endif
+
+ return retval;
+}
+
+STATIC int conv_sendmsg(struct pam_conv *aconv, const char *message, int style)
+{
+ struct pam_message msg,*pmsg;
+ struct pam_response *resp;
+ int retval;
+
+ /* Get the password from the user... */
+ pmsg = &msg;
+
+ msg.msg_style = style;
+ msg.msg = message;
+ resp = NULL;
+
+ retval = aconv->conv(1, (const struct pam_message **) &pmsg,
+ &resp, aconv->appdata_ptr);
+ if (resp) {
+ _pam_drop_reply(resp, 1);
+ }
+ return retval;
+}
+
+
+STATIC int conv_getitem(struct pam_conv *aconv, char *message, int style,
+ char **result)
+{
+ struct pam_message msg,*pmsg;
+ struct pam_response *resp;
+ int retval;
+
+ D(("called."));
+
+ /* Get the password from the user... */
+ pmsg = &msg;
+ msg.msg_style = style;
+ msg.msg = message;
+ resp = NULL;
+
+ retval = aconv->conv(1, (const struct pam_message **) &pmsg,
+ &resp, aconv->appdata_ptr);
+ if(retval != PAM_SUCCESS)
+ return retval;
+ if(resp != NULL) {
+ *result = resp->resp; free(resp);
+ return PAM_SUCCESS;
+ }
+ else
+ return PAM_SERVICE_ERR;
+}
diff --git a/contrib/libpam/modules/pam_unix/pam_unix_sess.c b/contrib/libpam/modules/pam_unix/pam_unix_sess.c
new file mode 100644
index 000000000000..319b2ed6288e
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/pam_unix_sess.c
@@ -0,0 +1,181 @@
+/*
+ * $Header: /home/morgan/pam/Linux-PAM-0.53/modules/pam_unix/RCS/pam_unix_sess.c,v 1.1 1996/11/09 19:44:35 morgan Exp $
+ */
+
+/*
+ * Copyright Alexander O. Yuriev, 1996. All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+/*
+ * $Log: pam_unix_sess.c,v $
+ * Revision 1.1 1996/11/09 19:44:35 morgan
+ * Initial revision
+ *
+ * Revision 1.4 1996/05/21 03:55:17 morgan
+ * added "const" to definition of rcsid[]
+ *
+ * Revision 1.3 1996/04/23 16:32:28 alex
+ * nothing really got changed.
+ *
+ * Revision 1.2 1996/04/19 03:23:33 alex
+ * session code implemented. account management moved into pam_unix_acct.c
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+
+#ifndef LINUX /* AGM added this as of 0.2 */
+
+ #include <security/pam_appl.h>
+
+#endif /* ditto */
+
+#include <security/pam_modules.h>
+#include <syslog.h>
+#include <unistd.h>
+#ifndef LOG_AUTHPRIV
+#define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+static const char rcsid[] = "$Id: pam_unix_sess.c,v 1.1 1996/11/09 19:44:35 morgan Exp $ pam_unix session management. alex@bach.cis.temple.edu";
+
+/* Define internal functions */
+
+static int _get_log_level( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv );
+
+int _pam_unix_open_session( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv );
+
+int _pam_unix_close_session( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv );
+
+/* Implementation */
+
+static int _get_log_level( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+{
+ int i = argc;
+ int log_level = LOG_DEBUG;
+
+ while ( i-- )
+ {
+ if ( strcmp( *argv, "debug" ) == 0 )
+ log_level = LOG_DEBUG;
+ else if ( strcmp ( *argv, "trace" ) == 0 )
+ log_level = LOG_AUTHPRIV;
+ argv++;
+ }
+
+ return log_level;
+}
+
+int _pam_unix_open_session( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+{
+ int log_level;
+ char *user_name, *service;
+
+
+ log_level = _get_log_level( pamh, flags, argc, argv );
+
+ pam_get_item( pamh, PAM_USER, (void*) &user_name );
+ if ( !user_name )
+ return PAM_CONV_ERR; /* How did we get authenticated with
+ no username?! */
+
+ pam_get_item( pamh, PAM_SERVICE, (void*) &service );
+ if ( !service )
+ return PAM_CONV_ERR;
+
+ syslog ( log_level,
+ "pam_unix authentication session started, user %s, service %s\n",
+ user_name, service );
+
+ return PAM_SUCCESS;
+}
+
+int _pam_unix_close_session( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+{
+ int log_level;
+ char *user_name, *service;
+
+ log_level = _get_log_level( pamh, flags, argc, argv );
+
+ pam_get_item( pamh, PAM_USER, (void*) &user_name );
+ if ( !user_name )
+ return PAM_CONV_ERR; /* How did we get authenticated with
+ no username?! */
+
+ pam_get_item( pamh, PAM_SERVICE, (void*) &service );
+ if ( !service )
+ return PAM_CONV_ERR;
+
+ syslog ( log_level,
+ "pam_unix authentication session finished, user %s, service %s\n",
+ user_name, service );
+
+ return PAM_SUCCESS;
+}
+
+int pam_sm_open_session( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv )
+{
+ return _pam_unix_open_session( pamh, flags, argc, argv ) ;
+}
+
+int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ return _pam_unix_close_session( pamh, flags, argc, argv ) ;
+}
+
diff --git a/contrib/libpam/modules/pam_unix/support.c b/contrib/libpam/modules/pam_unix/support.c
new file mode 100644
index 000000000000..a2fafcd2c13e
--- /dev/null
+++ b/contrib/libpam/modules/pam_unix/support.c
@@ -0,0 +1,152 @@
+/*
+ * $Header: /home/morgan/pam/Linux-PAM-0.53/modules/pam_unix/RCS/support.c,v 1.1 1996/11/09 19:44:35 morgan Exp $
+ */
+
+/*
+ * Copyright Andrew Morgan, 1996. All rights reserved.
+ * Modified by Alexander O. Yuriev
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+
+/*
+ * $Log: support.c,v $
+ * Revision 1.1 1996/11/09 19:44:35 morgan
+ * Initial revision
+ *
+ * Revision 1.1 1996/04/17 01:11:08 alex
+ * Initial revision
+ *
+ */
+
+#include <stdlib.h> /* define NULL */
+
+#ifndef LINUX
+
+ #include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+
+#ifndef NDEBUG
+
+ #include <syslog.h>
+
+#endif /* NDEBUG */
+
+
+/* Phototype declarations */
+
+int converse( pam_handle_t *pamh,
+ int nargs,
+ struct pam_message **message,
+ struct pam_response **response );
+
+int _set_auth_tok( pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv );
+
+/* Implementation */
+
+int converse( pam_handle_t *pamh,
+ int nargs,
+ struct pam_message **message,
+ struct pam_response **response )
+
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
+ if ( retval == PAM_SUCCESS )
+ {
+ retval = conv->conv( nargs,
+ ( const struct pam_message ** ) message,
+ response,
+ conv->appdata_ptr );
+ }
+ return retval;
+}
+
+/***************************************************************************/
+/* prompt user for a using conversation calls */
+/***************************************************************************/
+
+int _set_auth_tok( pam_handle_t *pamh,
+ int flags, int argc,
+ const char **argv )
+{
+ int retval;
+ char *p;
+
+ struct pam_message msg[1],*pmsg[1];
+ struct pam_response *resp;
+
+ /* set up conversation call */
+
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[0].msg = "Password: ";
+ resp = NULL;
+
+ if ( ( retval = converse( pamh, 1 , pmsg, &resp ) ) != PAM_SUCCESS )
+ return retval;
+
+ if ( resp )
+ {
+ if ( ( flags & PAM_DISALLOW_NULL_AUTHTOK ) &&
+ resp[0].resp == NULL )
+ {
+ free( resp );
+ return PAM_AUTH_ERR;
+ }
+
+ p = resp[ 0 ].resp;
+
+ /* This could be a memory leak. If resp[0].resp
+ is malloc()ed, then it has to be free()ed!
+ -- alex
+ */
+
+ resp[ 0 ].resp = NULL;
+
+ }
+ else
+ return PAM_CONV_ERR;
+
+ free( resp );
+ pam_set_item( pamh, PAM_AUTHTOK, p );
+ return PAM_SUCCESS;
+}
diff --git a/contrib/libpam/modules/pam_warn/Makefile b/contrib/libpam/modules/pam_warn/Makefile
new file mode 100644
index 000000000000..167af5a370ac
--- /dev/null
+++ b/contrib/libpam/modules/pam_warn/Makefile
@@ -0,0 +1,96 @@
+#
+# $Id: Makefile,v 1.2 1997/04/05 06:20:16 morgan Exp $
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log: Makefile,v $
+# Revision 1.2 1997/04/05 06:20:16 morgan
+# fixed fakeroot
+#
+# Revision 1.1 1996/12/01 03:12:22 morgan
+# Initial revision
+#
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/11/14
+#
+
+TITLE=pam_warn
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/contrib/libpam/modules/pam_warn/README b/contrib/libpam/modules/pam_warn/README
new file mode 100644
index 000000000000..f45b271c0d77
--- /dev/null
+++ b/contrib/libpam/modules/pam_warn/README
@@ -0,0 +1,23 @@
+# $Id: README,v 1.1 1996/12/01 03:12:22 morgan Exp $
+#
+
+This module is an authentication module that does not authenticate.
+Instead it always returns PAM_IGNORE, indicating that it does not want
+to affect the authentication process.
+
+Its purpose is to log a message to the syslog indicating the
+pam_item's available at the time it was invoked. It is a diagnostic
+tool.
+
+Recognized arguments:
+
+ <none>
+
+module services provided:
+
+ auth _autheticate and _setcred (blank)
+ password _chauthtok [mapped to _authenticate]
+
+
+Andrew Morgan
+1996/11/14
diff --git a/contrib/libpam/modules/pam_warn/pam_warn.c b/contrib/libpam/modules/pam_warn/pam_warn.c
new file mode 100644
index 000000000000..2a0a23d6e989
--- /dev/null
+++ b/contrib/libpam/modules/pam_warn/pam_warn.c
@@ -0,0 +1,112 @@
+/* pam_warn module */
+
+/*
+ * $Id: pam_warn.c,v 1.2 1997/02/15 17:19:08 morgan Exp $
+ *
+ * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+ *
+ * $Log: pam_warn.c,v $
+ * Revision 1.2 1997/02/15 17:19:08 morgan
+ * corrected many bugs and removed fixed buffer logging
+ *
+ * Revision 1.1 1996/12/01 03:12:22 morgan
+ * Initial revision
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-warn", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc
+ , const char **argv)
+{
+ const char *service=NULL, *user=NULL, *terminal=NULL
+ , *rhost=NULL, *ruser=NULL;
+
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service);
+ (void) pam_get_item(pamh, PAM_TTY, (const void **)&terminal);
+ _pam_log(LOG_NOTICE, "service: %s [on terminal: %s]"
+ , service ? service : "<unknown>"
+ , terminal ? terminal : "<unknown>"
+ );
+ (void) pam_get_user(pamh, &user, "Who are you? ");
+ (void) pam_get_item(pamh, PAM_RUSER, (const void **)&ruser);
+ (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);
+ _pam_log(LOG_NOTICE, "user: (uid=%d) -> %s [remote: %s@%s]"
+ , getuid()
+ , user ? user : "<unknown>"
+ , ruser ? ruser : "?nobody"
+ , rhost ? rhost : "?nowhere"
+ );
+
+ /* we are just a fly on the wall */
+
+ return PAM_IGNORE;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ , const char **argv)
+{
+ return PAM_IGNORE;
+}
+
+/* password updating functions */
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc
+ , const char **argv)
+{
+ /* map to the authentication function... */
+
+ return pam_sm_authenticate(pamh, flags, argc, argv);
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_warn_modstruct = {
+ "pam_warn",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_chauthtok,
+};
+
+#endif
+
+/* end of module definition */
diff --git a/contrib/libpam/modules/pam_wheel/Makefile b/contrib/libpam/modules/pam_wheel/Makefile
new file mode 100644
index 000000000000..553e32199668
--- /dev/null
+++ b/contrib/libpam/modules/pam_wheel/Makefile
@@ -0,0 +1,94 @@
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# Created by Cristian Gafton <gafton@sorosis.ro> 1996/09/10
+#
+
+ifeq ($(HAVE_PWDBLIB),yes)
+
+TITLE=pam_wheel
+CFLAGS += -DHAVE_PWDBLIB
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+#LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+EXTRALS = -lpwdb
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+#static/%.o : %.c
+# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+#ifdef STATIC
+#LIBSTATIC = lib$(TITLE).o
+#endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+#ifdef STATIC
+# $(MKDIR) ./static
+#endif
+
+register:
+#ifdef STATIC
+# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+#endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD) $(EXTRALS)
+endif
+
+#ifdef STATIC
+#$(LIBOBJS): $(LIBSRC)
+#
+#$(LIBSTATIC): $(LIBOBJS)
+# $(LD) -r -o $@ $(LIBOBJS) $(EXTRALS)
+#endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~ *.so
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak dynamic/* static/*
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+else
+include ../dont_makefile
+endif
diff --git a/contrib/libpam/modules/pam_wheel/README b/contrib/libpam/modules/pam_wheel/README
new file mode 100644
index 000000000000..336bb31ef133
--- /dev/null
+++ b/contrib/libpam/modules/pam_wheel/README
@@ -0,0 +1,33 @@
+
+pam_wheel:
+ only permit root authentication too members of wheel group
+
+RECOGNIZED ARGUMENTS:
+ debug write a message to syslog indicating success or
+ failure.
+
+ use_uid the check for wheel membership will be done against
+ the current uid instead of the original one
+ (useful when jumping with su from one account to
+ another for example)
+
+ trust the pam_wheel module will return PAM_SUCCESS instead
+ of PAM_IGNORE if the user is a member of the wheel
+ group (thus with a little play stacking the modules
+ the wheel members may be able to su to root without
+ being prompted for a passwd).
+
+ deny Reverse the sense of the auth operation: if the user
+ is trying to get UID 0 access and is a member of the
+ wheel group, deny access (well, kind of nonsense, but
+ for use in conjunction with 'group' argument... :-)
+
+ group=xxxx Instead of checking the GID 0 group, use the xxxx
+ group to perform the authentification.
+
+MODULE SERVICES PROVIDED:
+ auth _authetication and _setcred (blank)
+
+AUTHOR:
+ Cristian Gafton <gafton@sorosis.ro>
+
diff --git a/contrib/libpam/modules/pam_wheel/pam_wheel.c b/contrib/libpam/modules/pam_wheel/pam_wheel.c
new file mode 100644
index 000000000000..db262d83d8c9
--- /dev/null
+++ b/contrib/libpam/modules/pam_wheel/pam_wheel.c
@@ -0,0 +1,277 @@
+/* pam_wheel module */
+
+/*
+ * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
+ * See the end of the file for Copyright Information
+ *
+ *
+ * 1.2 - added 'deny' and 'group=' options
+ * 1.1 - added 'trust' option
+ * 1.0 - the code is working for at least another person, so... :-)
+ * 0.1 - use vsyslog instead of vfprintf/syslog in _pam_log
+ * - return PAM_IGNORE on success (take care of sloppy sysadmins..)
+ * - use pam_get_user instead of pam_get_item(...,PAM_USER,...)
+ * - a new arg use_uid to auth the current uid instead of the
+ * initial (logged in) one.
+ * 0.0 - first release
+ *
+ * TODO:
+ * - try to use make_remark from pam_unix/support.c
+ * - consider returning on failure PAM_FAIL_NOW if the user is not
+ * a wheel member.
+ */
+
+#include <stdio.h>
+#define __USE_BSD
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef HAVE_PWDBLIB
+# include <pwdb/pwdb_public.h>
+#else
+# include <pwd.h>
+# include <grp.h>
+#endif
+
+
+/*
+ * here, we make a definition for the externally accessible function
+ * in this file (this definition is required for static a module
+ * but strongly encouraged generally) it is used to instruct the
+ * modules include file to define the function prototypes.
+ */
+
+#define PAM_SM_AUTH
+
+#include <security/pam_modules.h>
+
+/* variables */
+static char use_group[BUFSIZ];
+
+/* some syslogging */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-Wheel", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* checks if a user is on a list of members of the GID 0 group */
+
+static int is_on_list(char * const *list, const char *member)
+{
+ while (*list) {
+ if (strcmp(*list, member) == 0)
+ return 1;
+ list++;
+ }
+ return 0;
+}
+
+/* argument parsing */
+
+#define PAM_DEBUG_ARG 0x0001
+#define PAM_USE_UID_ARG 0x0002
+#define PAM_TRUST_ARG 0x0004
+#define PAM_DENY_ARG 0x0010
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strcmp(*argv,"use_uid"))
+ ctrl |= PAM_USE_UID_ARG;
+ else if (!strcmp(*argv,"trust"))
+ ctrl |= PAM_TRUST_ARG;
+ else if (!strcmp(*argv,"deny"))
+ ctrl |= PAM_DENY_ARG;
+ else if (!strncmp(*argv,"group=",6))
+ strcpy(use_group,*argv+6);
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ int ctrl;
+ const char *username;
+ char *fromsu;
+ struct passwd *pwd, *tpwd;
+ struct group *grp;
+ int retval = PAM_AUTH_ERR;
+
+ /* Init the optional group */
+ bzero(use_group,sizeof(use_group));
+
+ ctrl = _pam_parse(argc, argv);
+ retval = pam_get_user(pamh,&username,NULL);
+ if ((retval != PAM_SUCCESS) || (!username)) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"can not get the username");
+ return PAM_SERVICE_ERR;
+ }
+
+ /* su to a uid 0 account ? */
+ pwd = getpwnam(username);
+ if (!pwd) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"unknown user %s",username);
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* Now we know that the username exists, pass on to other modules...
+ * the call to pam_get_user made this obsolete, so is commented out
+ *
+ * pam_set_item(pamh,PAM_USER,(const void *)username);
+ */
+
+ /* is this user an UID 0 account ? */
+ if(pwd->pw_uid) {
+ /* no need to check for wheel */
+ return PAM_IGNORE;
+ }
+
+ if (ctrl & PAM_USE_UID_ARG) {
+ tpwd = getpwuid(getuid());
+ if (!tpwd) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"who is running me ?!");
+ return PAM_SERVICE_ERR;
+ }
+ fromsu = tpwd->pw_name;
+ } else {
+ fromsu = getlogin();
+ if (!fromsu) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"who is running me ?!");
+ return PAM_SERVICE_ERR;
+ }
+ }
+
+ if (!use_group[0])
+ grp = getgrgid(0);
+ else
+ grp = getgrnam(use_group);
+
+ if (!grp || !grp->gr_mem) {
+ if (ctrl & PAM_DEBUG_ARG) {
+ if (!use_group[0])
+ _pam_log(LOG_NOTICE,"no members in a GID 0 group");
+ else
+ _pam_log(LOG_NOTICE,"no members in '%s' group",use_group);
+ }
+ if (ctrl & PAM_DENY_ARG)
+ /* if this was meant to deny access to the members
+ * of this group and the group does not exist, allow
+ * access
+ */
+ return PAM_IGNORE;
+ else
+ return PAM_AUTH_ERR;
+ }
+
+ if (is_on_list(grp->gr_mem, fromsu)) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"Access %s to '%s' for '%s'",
+ (ctrl & PAM_DENY_ARG)?"denied":"granted",
+ fromsu,username);
+ if (ctrl & PAM_DENY_ARG)
+ return PAM_PERM_DENIED;
+ else
+ if (ctrl & PAM_TRUST_ARG)
+ return PAM_SUCCESS;
+ else
+ return PAM_IGNORE;
+ }
+
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE,"Access %s for '%s' to '%s'",
+ (ctrl & PAM_DENY_ARG)?"granted":"denied",fromsu,username);
+ if (ctrl & PAM_DENY_ARG)
+ return PAM_SUCCESS;
+ else
+ return PAM_PERM_DENIED;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_wheel_modstruct = {
+ "pam_wheel",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/*
+ * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997
+ * All rights reserved
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `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 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.
+ */
diff --git a/contrib/libpam/modules/register_static b/contrib/libpam/modules/register_static
new file mode 100755
index 000000000000..2067ac7e98d1
--- /dev/null
+++ b/contrib/libpam/modules/register_static
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+if [ `basename $PWD` != "modules" ]; then
+ echo "$0 must be run from the .../modules directory"
+ exit 1
+fi
+
+merge_line ()
+{
+ if [ $# != 3 ]; then
+ echo "usage: merge_line token filename 'new line'"
+ fi
+ if [ -f $2 ]; then
+# remove any existing entry...
+ grep -v "$1" $2 > tmp.$2
+ rm -f $2
+ mv {tmp.,}$2
+ fi
+ cat << EOT >> $2
+$3
+EOT
+
+}
+
+
+if [ $# -ne 2 ]; then
+
+ cat << EOT 2>&1
+$0: this script takes TWO arguments:
+ the 'alphanumeric label' of the module and the location of
+ its object file from the .../modules/ directory
+EOT
+ exit 1
+
+else
+ echo "
+ *> registering static module: $1 ($2) <*
+"
+ merge_line "$1" _static_module_list "\
+extern struct pam_module _$1_modstruct;"
+
+ merge_line "$1" _static_module_entry " &_$1_modstruct,"
+ if [ -n "$2" ]; then
+ merge_line "$2" _static_module_objects "../modules/$2"
+ fi
+
+fi
+
+exit 0