diff options
Diffstat (limited to 'contrib')
225 files changed, 41922 insertions, 0 deletions
diff --git a/contrib/libpam/CHANGELOG b/contrib/libpam/CHANGELOG new file mode 100644 index 0000000..99872a4 --- /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 0000000..2f27a2e --- /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 0000000..d25f58b --- /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 0000000..78a428e --- /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 0000000..5ed6acb --- /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 0000000..92ab525 --- /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 0000000..4fb9f7c --- /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 0000000..2eae367 --- /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 0000000..db650a0 --- /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 0000000..6328a4f --- /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 0000000..b0e04b0 --- /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 0000000..2e4f034 --- /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 0000000..7691dc3 --- /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 0000000..d3344bb --- /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 0000000..5843e58 --- /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 0000000..d5f618e --- /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 0000000..6ca566c --- /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 0000000..8ce5ab0 --- /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 0000000..d834198 --- /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 0000000..94e9968 --- /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 0000000..178de28 --- /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 0000000..8c7e1e1 --- /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 0000000..f9f2652 --- /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 0000000..158accc --- /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 0000000..95ca2ab --- /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 0000000..866b408 --- /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 0000000..b0f40d4 --- /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 0000000..a8b745a --- /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 0000000..91f990f --- /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 0000000..7538441 --- /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 0000000..ea2dd98 --- /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 0000000..ea2dd98 --- /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 0000000..f631c47 --- /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 0000000..b0997d5 --- /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 0000000..c809a0e --- /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 0000000..06fdabb --- /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 0000000..42bccd6 --- /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 0000000..1b2dcf9 --- /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 0000000..388a5d7 --- /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 0000000..0299533 --- /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 0000000..33b4fda --- /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 0000000..a635c8b --- /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 0000000..b97b2cd --- /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 0000000..53cd809 --- /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 0000000..7f8c4a3 --- /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 <brucec@humbug.org.au> + +<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 0000000..4700c2a0 --- /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 <gafton@redhat.com> + +<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 0000000..99f3671 --- /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 <morgan@parc.power.net> + +<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 0000000..a62f457 --- /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 <kinch@kinch.ark.com> + +<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>${string}</tt> syntax and (possibly +non-existent) <em/PAM_ITEM/s may be used in values using the +<tt>@{string}</tt> syntax. Both the <tt>$</tt> +and <tt>@</tt> characters can be backslash-escaped to be used +as literal values (as in <tt>\$</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 0000000..99f06ef --- /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 <morgan@parc.power.net> + +<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 0000000..ca2e065 --- /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 <morgan@parc.power.net> + +<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 0000000..360edee --- /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 <morgan@parc.power.net> + +<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 0000000..edb87d1 --- /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 <shadow@dementia.org> + +<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 0000000..8c0e662 --- /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 <morgan@parc.power.net> + +<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 0000000..6b98ea6 --- /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 <gafton@redhat.com> <newline> +Thanks are also due to Elliot Lee <sopwith@redhat.com> +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><domain></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><type></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><item></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 0000000..fe4a0d2 --- /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><sopwith@cuc.edu></tt> + +<tag><bf>Maintainer:</bf></tag> +Red Hat Software:<newline> +Michael K. Johnson <johnsonm@redhat.com> 1996/11/18<newline> +(if unavailable, contact Elliot Lee <sopwith@cuc.edu>). + +<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 0000000..9a99f20 --- /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 <morgan@parc.power.net> + +<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/˜/', 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 0000000..de4b32a --- /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 <johnsonm@redhat.com><newline> +(based on code taken from a module written by Andrew G. Morgan +<morgan@parc.power.net>). + +<tag><bf>Maintainer:</bf></tag> +Michael K. Johnson <johnsonm@redhat.com> + +<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 0000000..84df9fc --- /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, <morgan@parc.power.net> + +<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 0000000..c9f7bff --- /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 <gafton@redhat.com> <newline> +and Andrew G. Morgan <morgan@parc.power.net> + +<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 0000000..4d5f39a --- /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 <gafton@redhat.com> + +<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 0000000..9100102 --- /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 <longyear@netcom.com> + +<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 <netdb.h></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 0000000..ff6aa86 --- /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 <morgan@parc.power.net> + +<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 0000000..276ae90 --- /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 <sopwith@cuc.edu> + +<tag><bf>Maintainer:</bf></tag> +Red Hat Software:<newline> +<em/currently/ Michael K. Johnson <johnsonm@redhat.com><newline> +(if unavailable, contact Elliot Lee <sopwith@cuc.edu>). + +<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 0000000..0b3cddf --- /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><morgan@parc.power.net></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/&/ (logical AND) and <tt/|/ (logical OR). Two +examples are: <tt>!morgan&!root</tt>, indicating that this rule +does not apply to the user <tt>morgan</tt> nor to <tt>root</tt>; and +<tt>tty*&!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>\</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* & ; !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 0000000..6e81f18 --- /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 <morgan@parc.power.net> + +<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 0000000..9139695 --- /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 <gafton@redhat.com> + +<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 0000000..7c4170a --- /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><security/pam_appl.h></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/$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><NUL></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><security/pam_appl.h></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><security/pam_appl.h></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><security/pam_appl.h></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><security/pam_misc.h></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 +``..\a.Time is running out...\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 ``..\a.Sorry, your time is +up!\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><morgan@transmeta.com></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 0000000..418b09b --- /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,&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><security/pam_modules.h></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><security/pam_modules.h></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><security/pam_modules.h></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><security/pam_modules.h></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><security/pam_modules.h></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><morgan@transmeta.com></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 0000000..093998a --- /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/#/' and extend to the +next end-of-line; also, module specification lines may be extended +with a `<tt/\/' 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_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><morgan@parc.power.net></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 0000000..6234e14 --- /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 0000000..6e37b86 --- /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 0000000..d73258d --- /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 0000000..1d5c898 --- /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 0000000..6da47d1 --- /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 0000000..6dd5e6e --- /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 0000000..b62bc2d --- /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 0000000..063f24d --- /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 0000000..3808e55 --- /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 0000000..6a64c22 --- /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 0000000..0a1f5a6 --- /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 0000000..617a5f2 --- /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 0000000..ad134f6 --- /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 0000000..f3914a4 --- /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 0000000..acfc592 --- /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 0000000..b033aa6 --- /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 0000000..b68368b --- /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 0000000..d9c5edd --- /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 0000000..b5865cd --- /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 0000000..6ba9cc6 --- /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 0000000..ffc01ac --- /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 0000000..ac461f5 --- /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 0000000..397fb9d --- /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 0000000..e6950e2 --- /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 0000000..d0bbc38 --- /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 0000000..34f98f5 --- /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 0000000..2632b81 --- /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 0000000..53d7715 --- /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 0000000..0e8142b --- /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 0000000..9eddf29 --- /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 0000000..cc66f1a --- /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 0000000..6e186b7 --- /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 0000000..6fed9ba --- /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 0000000..303425a --- /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 0000000..f8a0da5 --- /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 0000000..b720774 --- /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 0000000..38b93fe --- /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 0000000..53700a0 --- /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 0000000..d840a2d --- /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 0000000..607c6d5 --- /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 0000000..9380f88 --- /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 0000000..1cfc865 --- /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 0000000..d35b66b --- /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 0000000..53cf51b --- /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 0000000..4823973 --- /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 0000000..e54a87d --- /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 0000000..0066fb4 --- /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 0000000..8641594 --- /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 0000000..f256ce1 --- /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 0000000..a3d684b --- /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 0000000..df10c26 --- /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 0000000..abfefa5 --- /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 0000000..0667b5e --- /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 0000000..1213339 --- /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 0000000..668f2f8 --- /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 0000000..e4b0273 --- /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 0000000..3400dfb --- /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 0000000..02506cb --- /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 0000000..4f7f6de --- /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 0000000..76ba24d --- /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 0000000..df363bc --- /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 0000000..d6e959c --- /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 0000000..4c60840 --- /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 0000000..bd0879c --- /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 "e 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 = "e; /* 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 && ("e != var->defval) && + ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) { + return retval; + } + if (var->override && ("e != var->override) && + ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) { + return retval; + } + + /* Now its easy */ + + if (var->override && *(var->override) && "e != 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 ("e == 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 && ("e != var->defval)) { + free(var->defval); + } + if (var->override && ("e != 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 0000000..388e8b6 --- /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 0000000..dbd6452 --- /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 0000000..9d46a56 --- /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 0000000..3eb2730 --- /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 0000000..fc3d1f2 --- /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 0000000..09b693b --- /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 0000000..b375c07 --- /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 0000000..b5355c6 --- /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 0000000..597f912 --- /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 0000000..ca2d415 --- /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 0000000..5db53cc --- /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 0000000..bdd76adb --- /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 0000000..03bb7ed --- /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 0000000..9e2cf88 --- /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 0000000..e51a72d --- /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 0000000..96714f6 --- /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 0000000..f6a0e07 --- /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 0000000..06a6857 --- /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 0000000..d92c1f9 --- /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 0000000..ea57e42 --- /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 0000000..179c430 --- /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 0000000..0294039 --- /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 0000000..b65e7db --- /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 0000000..e54b12a --- /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 0000000..5a402ea --- /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 0000000..15160f3 --- /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 0000000..0769bb9 --- /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 0000000..ab7ccd7 --- /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 0000000..2788dcf --- /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 0000000..823b624 --- /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 0000000..da179a3 --- /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 0000000..1bdd564 --- /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 0000000..397f367 --- /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 0000000..0cb2187 --- /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 0000000..7428bb4 --- /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 0000000..351a706 --- /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 0000000..23eb4c1 --- /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 0000000..321f249 --- /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 0000000..fdfbdd8 --- /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 0000000..4949ade --- /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 0000000..88be13b --- /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 0000000..a612f74 --- /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 0000000..dbd1385 --- /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 0000000..4a1eed0 --- /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 0000000..cd90b0f --- /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 0000000..402f7f3 --- /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 0000000..d50031d --- /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 0000000..49ce96c --- /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 0000000..6332eaa --- /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 0000000..71e212d --- /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 0000000..a74b911 --- /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 0000000..253308f --- /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 0000000..b412edf --- /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 0000000..72b1da8 --- /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 0000000..93addbb --- /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 0000000..527dfd3 --- /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 0000000..10dfcf7 --- /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 **)¤t); + 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 **)¤t); + 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 0000000..b378708 --- /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 0000000..d7010dd --- /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 0000000..21327d4 --- /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 0000000..d8a09ea --- /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 0000000..1df095c --- /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 0000000..369fb03 --- /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 0000000..121b19a --- /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 0000000..cbd5bfb --- /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 0000000..edc9134 --- /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 0000000..52e8e21 --- /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 0000000..1cb7c14 --- /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 0000000..5015418 --- /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 0000000..ec17ff3 --- /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 0000000..aaa8512 --- /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 0000000..a1b65c0 --- /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 0000000..bc297d4 --- /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 0000000..0c3f976 --- /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 0000000..051d8b7 --- /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 0000000..489c1d7 --- /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 0000000..d2062fd --- /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 0000000..37e4c85 --- /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 0000000..ad1f47f --- /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 0000000..082e996 --- /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 0000000..5c0546a --- /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 0000000..95f13d0 --- /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 0000000..de1345e --- /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 0000000..319b2ed --- /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 0000000..a2fafcd --- /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 0000000..167af5a --- /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 0000000..f45b271 --- /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 0000000..2a0a23d --- /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 0000000..553e321 --- /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 0000000..336bb31 --- /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 0000000..db262d8 --- /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 0000000..2067ac7 --- /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 |