This commit was generated by cvs2svn to compensate for changes in r76238,
which included commits to RCS files with non-trunk default branches.
This commit is contained in:
commit
9f524a8aad
@ -1,24 +1,329 @@
|
||||
|
||||
$Id$
|
||||
$Id: CHANGELOG,v 1.61 2001/04/08 06:17:04 agmorgan Exp $
|
||||
|
||||
-----------------------------
|
||||
|
||||
0.66: whenever
|
||||
TODO:
|
||||
|
||||
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.
|
||||
- sanitize use of md5 throughout distribution.. Make a static
|
||||
library for helping to develop modules that contains it and other
|
||||
stuff. Also add sha-1 and ripemd-160 digest algorithms.
|
||||
- once above is done. remove hacks from the secret@here module etc..
|
||||
- remove prototype for gethostname in pam_access.c (Derrick)
|
||||
- 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
|
||||
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
|
||||
- verify that the PAM_INCOMPLETE interface works (auth seems ok..)
|
||||
- add PAM_INCOMPLETE support to modules (partially added to pam_pwdb)
|
||||
- work on RFC.
|
||||
- do we still need to remove openlog/closelog from modules..?
|
||||
- auth and acct support in pam_cracklib, "yes, I know the password
|
||||
you just typed was valid, I just don't think it was very strong..."
|
||||
- add in the pam_cap and pam_netid modules
|
||||
|
||||
====================================================================
|
||||
Note, as of release 0.73, all checkins should be accompanied with a
|
||||
Bug ID. The bug IDs relate to sourceforge IDs.. You can query the
|
||||
related bug description with the following URL:
|
||||
|
||||
http://sourceforge.net/tracker/index.php?func=detail&aid=XXXXXX&group_id=6663&atid=106663
|
||||
|
||||
Where you should replace XXXXXX with a bug-id.
|
||||
|
||||
If you have found a bug in Linux-PAM, please consider filing such a
|
||||
bug report - outstanding bugs are listed here:
|
||||
|
||||
http://sourceforge.net/tracker/?atid=106663&group_id=6663&func=browse
|
||||
|
||||
(to file another bug see the 'submit bug' button on this page).
|
||||
|
||||
====================================================================
|
||||
|
||||
0.76: please submit patches for this section with actual code/doc
|
||||
patches!
|
||||
|
||||
*
|
||||
|
||||
0.75: Sat Apr 7 23:10:50 PDT 2001
|
||||
|
||||
** WARNING **
|
||||
|
||||
This release contains backwardly incompatible changes to
|
||||
libpam. Prior versions were buggy - see bugfix for Bug 129775.
|
||||
|
||||
** WARNING **
|
||||
|
||||
* made 0.75 release (Bug 414665 - agmorgan)
|
||||
* pam_pwdb has been removed from the suggested pam.conf template. I've
|
||||
replaced it with pam_unix. (Bug 227565 - agmorgan)
|
||||
* pam_limits - Richard M. Yumul reported that "<domain> -" didn't
|
||||
work, first fix suggested by Werner Puschitz (Bug 404953 - agmorgan)
|
||||
* Nicolay Pelov suggested a simple fix for freebsd support (Bug 407282
|
||||
- agmorgan)
|
||||
* Michel D'HOOGE submitted documentation fixes (Bug 408961 - agmorgan)
|
||||
* fix for module linking directions (Bug 133545 - agmorgan)
|
||||
* fix for glibc-2.2.2 compilation of pam_issue (Bug 133542 - agmorgan)
|
||||
* fix pam_userdb to make and link both .o files it needs - converse()
|
||||
wasn't being linked! (Bug 132880 - agmorgan)
|
||||
* added some sys-admin documentation for the pam_tally module (Bug
|
||||
126210 - agmorgan).
|
||||
* added a link to module examples from the module writers doc (Bug
|
||||
131192 - agmorgan).
|
||||
* fixed a small security hole (more of a user confusion issue) with
|
||||
the unix and pwdb password helper binaries. The beef is described in
|
||||
the bug report, but no uid change was possible so no-one should
|
||||
think they need to issue a security bulletin over this one! (Bug
|
||||
112540 - agmorgan)
|
||||
* pam_lastlog needs to be linked with -lutil, also removed ambiguity
|
||||
from sysadmin guide regarding this module being a 'session' module
|
||||
(Bug 131549 - agmorgan).
|
||||
* pam_cracklib needs to be linked with -lcrypt (old password checking)
|
||||
(Bug 131601 - agmorgan).
|
||||
* fixes for static library builds and also the examples when linked
|
||||
with the debugging build of the libraries. (Bug 131783 - agmorgan)
|
||||
* fixed URL for original RFC to a cached kernel.org file. (Bug 131503
|
||||
- agmorgan)
|
||||
* quoted the $CRACKLIB_DICTPATH test in configure.in (Bug 130130 -
|
||||
agmorgan).
|
||||
* improved handling of the setcred/close_session and update chauthtok
|
||||
stack. *Warning* This is a backwardly incompatable change, but 'more
|
||||
sane' than before. (Bug 129775 - agmorgan)
|
||||
* bumped the version number, and added some code to assist in making
|
||||
documentation releases (Bug 129644 - agmorgan).
|
||||
|
||||
0.74: Sun Jan 21 22:36:08 PST 2001
|
||||
|
||||
* made 0.74 release (Bug 129642 - agmorgan)
|
||||
* libpam - cleaned up a few non-static functions to be static and added
|
||||
support for libpam to enforce things like pam_[gs]et_data() and
|
||||
AUTHTOK rules for using the API. Also documented pam_[gs]et_item()
|
||||
a little better including return codes (Bugs 129027, 128576 -
|
||||
agmorgan).
|
||||
* pam_access - fixed the non-default config file option (Bug 127561 -
|
||||
agmorgan)
|
||||
* pam.8 manual page clarified with respect to the default location for
|
||||
finding modules, also added some text describing the [...] control
|
||||
syntax. (Bug 127625 - agmorgan)
|
||||
* md5.h ia64 fixes for pam_unix and pam_pwdb (Bug 127700 - agmorgan)
|
||||
* removed requirement for c++ from the configure{.in,} files (Bug
|
||||
128298 - agmorgan)
|
||||
* removed subdirectories from man page redirections (124396 - baggins)
|
||||
* per David Lee, fixed non-POSIX shell command in modules/pam_filter/Makefile
|
||||
(Bug 126440 - vorlon)
|
||||
* modify format of pam_unix log messages to include service name
|
||||
(Bug 126423 - vorlon)
|
||||
* prevent pam_unix from logging unknown usernames (Bug 126431 - vorlon)
|
||||
* changed format of pam_unix 'authentication failure' log messages to make
|
||||
them clearer and more consistent (Bug 126036 - vorlon)
|
||||
* improved portability of pam_unix by eliminating Linux-specific utmp
|
||||
defines in PAM_getlogin() (Bug 125704 - vorlon)
|
||||
* removed static variables from pam_tally (Bug 117434 - agmorgan)
|
||||
* added copyright message to pam_access module from original logdaemon
|
||||
sources (Bug 125022 - agmorgan)
|
||||
* configure.in - removed the GCC -Wtraditional flag (Bug 124923 - agmorgan)
|
||||
* pam_mail - use PAM_PATH_MAILDIR as the location of mail spool
|
||||
(Bug 124397 - baggins)
|
||||
* _pam_aconf.h.in, configure.in - added PAM_PATH_MAILDIR set via
|
||||
--with-mailspool=dir option (default is _PAM_MAILDIR if defined
|
||||
in paths.h otherwise /var/spool/mail (Bug 124397 - baggins)
|
||||
* removed unnecessary CVS Log tags from all over the source
|
||||
(Bug 124391 - baggins)
|
||||
* pam_tally - check for PAM_TTY if PAM_RHOST is not set when writing
|
||||
to faillog (Bug 124394 - baggins)
|
||||
* use O_NOFOLLOW if available when opening debug log (Bug 124385 - baggins)
|
||||
* pam_cracklib - removed comments about pam_unix not working with
|
||||
pam_cracklib, added information about use_authtok parameter
|
||||
(Bug 124388 - baggins)
|
||||
* pam_userdb - fixed wrong definition of struct pam_module (was pam_wheel)
|
||||
(Bug 124386 - baggins)
|
||||
* fixed example/Makefile include path (Bug 124187, 127563(?) - agmorgan)
|
||||
* pam_userdb compiles on RH5x. Also removed circular dependency on
|
||||
configure.in. Also bumped revision number to 0.74. (Bug 124136 -
|
||||
agmorgan)
|
||||
|
||||
0.73: Sat Dec 2 00:04:04 PST 2000
|
||||
|
||||
* updated documentaion revisions and added 'make release' support
|
||||
to the top level Makefile (Bug 124132 - agmorgan).
|
||||
* documented Qmail support in pam_mail (Bug 109219 - baggins)
|
||||
* add change_uid option to pam_limits, and set real uid only if
|
||||
this option is present (Bug 124062 - baggins)
|
||||
* pam_limits - set real uid to the user for who we set limits.
|
||||
(Bug 123972 - baggins)
|
||||
* removed static variables from pam_limits (thread safe now). (Bug
|
||||
117450 - agmorgan).
|
||||
* removed static variable from pam_wheel (module should be thread safe
|
||||
now). (Bug 112906 - agmorgan)
|
||||
* added support for '/' symbols in pam_time and pam_group config files
|
||||
(support for modern terminal devices). Fixed infinite loop problem
|
||||
with '\\[^\n]' in these files. (Bug 116076 - agmorgan)
|
||||
* avoid potential SIGPIPE when writing to helper binaries with (Bug
|
||||
123399 - agmorgan)
|
||||
* replaced bogus logic in the pam_cracklib module for determining if
|
||||
the replacement is too similar to the old password (Bug 115055 -
|
||||
agmorgan)
|
||||
* added accessconf=<filename> feature to pam_access - request from
|
||||
Aldrin Martoq and Meelis Roos (Bugs 111927,117240 - agmorgan)
|
||||
* fix for pam_limit module not dealing with all limits Adam J. Richter
|
||||
(Bug 119554 - agmorgan)
|
||||
* comment fix describing fail_delay callback in _pam_types.h (Bug
|
||||
112646 - agmorgan)
|
||||
* "likeauth" fix for pam_unix and pam_pwdb which (Bug 113596 - agmorgan)
|
||||
* fix for pam_unix (support.c) to avoid segfault with NULL password
|
||||
(Bug 113238 - vorlon)
|
||||
* fix to pam_unix_passwd: try repeatedly to get a lock on the password
|
||||
file, instead of failing immediately (Bug 108845 - fix vorlon)
|
||||
* fix to pam_shells: logged information was not formatted correctly
|
||||
(extra comma) (Bug 111491 - fix vorlon)
|
||||
* fix for C++ application support (Bug 111645 - fix agmorgan)
|
||||
* fix for typo in pam_client.h (Bug 111648 - fix agmorgan)
|
||||
* removal of -lpam from pam_mkhomedir Makefile (Bug 116380 - fix agmorgan)
|
||||
* autoconf support [Task ID 15788, Bug ID 108297 - agmorgan with help!]
|
||||
- bugfix for libpamc.h include file [Bug ID 117476 - agmorgan]
|
||||
- bugfix for pam_filter.h inclusion [Bug ID 117474 - agmorgan]
|
||||
|
||||
0.72: Mon Dec 13 22:41:11 PST 1999
|
||||
|
||||
* patches from Debian (Ben Collins): pam_ftp supports event driven
|
||||
conversations now; pwdb_chkpwd cleanup; pam_warn static compile fix;
|
||||
user_db compiler warnings removed; debian defs file; pam_mail can
|
||||
now be used as a session module
|
||||
* ndbm compilation option for user_db module (fix explained by Richard Khoo)
|
||||
* pam_cracklib bug fix
|
||||
* packaging fixes & build from scratch stuff (Konst Bulatnikov & Frodo
|
||||
Looijaard)
|
||||
* -ldl appended to the libpam.so compilation make rule. (Charles Seeger)
|
||||
* Red Hat security patch for pam_pwdb forwarded by Debian! (Ben
|
||||
Collins. Fix provided by Andrey as it caught the problem earlier in the
|
||||
code.)
|
||||
* heuristic to prevent leaking filedescriptors to an agent. [This needs
|
||||
to be better supported perhaps by an additional libpamc API function?]
|
||||
* pam_userdb segfault fix from (Ben Collins)
|
||||
* PAM draft spec extras added at request of 'sen_ml'
|
||||
|
||||
0.71: Sun Nov 7 20:21:19 PST 1999
|
||||
|
||||
* added -lc to linker pass for pam_nologin module (glibc is weird).
|
||||
* various header changes to lower the number of warnings on glibc
|
||||
systems (Dan Yefimov)
|
||||
* merged a bunch of Debian fixes/patches/documentation (Ben Collins)
|
||||
things touched: libpam (minor); doc/modules/pam_unix.sgml; pam_env
|
||||
(plus docs); pam_mkhomedir (new module for new home directories on
|
||||
the fly...); pam_motd (new module); pam_limits (adjust to match
|
||||
docs); pam_issue (new module + doc) [Some of these were also
|
||||
submitted by Thorsten Kukuk]
|
||||
* small hack to lower the number of warnings that pam_client.h was
|
||||
generating.
|
||||
* debian and SuSE apparently can use the pam_ftp module, so
|
||||
removed the obsolete comment about this from the docs. (Thorsten
|
||||
Kukuk)
|
||||
|
||||
0.70: Fri Oct 8 22:05:30 PDT 1999
|
||||
|
||||
* bug fix for parsing of value=action tokens in libpam/pam_misc.c was
|
||||
segfaulting (Jan Rekorajski and independently Matthew Melvin)
|
||||
* numerous fixes from Thorsten Kukuk (icluding much needed fixes for
|
||||
bitrot in modules and some documentation) that got included in SuSE 6.2.
|
||||
* reentrancy issues in pam_unix and pam_cracklib resolved (Jan Rekorajski)
|
||||
* added hosts_equiv_rootok module option to pam_rhosts module (Tim Berger)
|
||||
* added comment about 'expose_account' module argument to admin and
|
||||
module writers' docs (request from Michael K Johnson).
|
||||
* myriad of bug fixes for libpamc - library now built by default and
|
||||
works with the biomouse fingerprint scanner agent/module
|
||||
(distributed separately).
|
||||
|
||||
0.69: Sun Aug 1 20:25:37 PDT 1999
|
||||
|
||||
* c++ header #ifdef'ing for pam_appl.h (Tuomo Pyhala)
|
||||
* added pam_userdb module (Cristian Gafton)
|
||||
* minor documentation changes
|
||||
* added in revised pam_client library (libpamc). Not installed by
|
||||
default yet, since the example agent/module combo is not very secure.
|
||||
* glibc fixes (Thorsten Kukuk, Adam J. Richter)
|
||||
|
||||
0.68: Sun Jul 4 23:04:13 PDT 1999
|
||||
|
||||
* completely new pam_unix module from Jan Rekorajski and Stephen Langasek
|
||||
* Jan Rekorajski pam_mail - support for Maildir format mailboxes
|
||||
* Jan Rekorajski pam_cracklib - support for old password comparison
|
||||
* Jan Rekorajski bug fix for pam_pwdb setcred reusing auth retval
|
||||
* Andrey's pam_tally patch (lstat -> fstat)
|
||||
* Robert Milkowski's additional pam_tally patches to **change format of
|
||||
/var/log/faillog** to one from shadow-utils, add new option "per_user"
|
||||
for pam_tally module, failure time logging, support for fail_line
|
||||
field, and support for fail_locktime field with new option
|
||||
no_lock_time.
|
||||
* pam_tally: clean up the tally application too.
|
||||
* Marcin Korzonek added process priority settings to pam_limits (bonus
|
||||
points for adding to documentation!)
|
||||
* Andrey's pam_pwdb patch (cleanup + md5 endian fubar fix)
|
||||
* more binary prompt preparations (make misc conv more compatible with spec)
|
||||
* modified callback hook for fail delay to be more useful with event
|
||||
driven applications (changed function prototype - suspect no one
|
||||
will notice). Documented this in app developer guide.
|
||||
* documentation for pam_access from Tim Berger
|
||||
* syntax fixes for the documentation - a long time since I've built it :*(
|
||||
added some more names to the CREDITS file.
|
||||
|
||||
0.67: Sat Jun 19 14:01:24 PDT 1999
|
||||
|
||||
* [dropped libpam_client - libpamc will be in the next release and
|
||||
conforms to the developing spec in doc/specs/draft-morgan-pam.raw.
|
||||
Sorry if you are keeping a PAM tree in CVS. CVS is a pain for
|
||||
directories, but this directory was actually not referenced by
|
||||
anything so the disruption should be light.]
|
||||
* updates to pam_tally from Tim
|
||||
* multiple updates from Stephen Langasek to pam_unix
|
||||
* pam_filter had some trouble compiling (bug report from Sridhar)
|
||||
* pam_wheel now attempts to identify the wheel group for the local
|
||||
system instead of blindly assuming it is gid=0. In the case that
|
||||
there is no "wheel" group, we default to assuming gid=0 is what was
|
||||
meant - former behavior. (courtesy of Sridhar)
|
||||
* NIS+ changes to pam_unix module from Dmitry O Panov
|
||||
* hopefully, a fix for redefinition of LOG_AUTHPRIV (bug report Luke
|
||||
Kenneth Casson Leighton)
|
||||
* fix for minor typo in pam_wheel documentation (Jacek Kopecky)
|
||||
* slightly more explanation of the [x=y] pam.conf syntax in the sys
|
||||
admin guide.
|
||||
|
||||
0.66: Mon Dec 28 20:22:23 PST 1998 <morgan@linux.kernel.org>
|
||||
|
||||
* Started using cvs to keep track of changes to Linux-PAM. This will
|
||||
likely break some of the automated building stuff (RPMs etc..).
|
||||
* security bug fix to pam_unix and pam_tally from Andrey.
|
||||
* modules make file is now more automatic. It should be possible to
|
||||
unpack an external module in the modules directory and have it automatically
|
||||
added to the build process. Also added a modules/download-all script
|
||||
that will make such downloading easier. I'm happy to receive patches to
|
||||
this file, informing the distribution of places from which to enrich itself.
|
||||
* removed pam_system_log stuff. Thought about it long and hard: a
|
||||
bad idea. If libc cannot guarantee a thread safe syslog, it needs
|
||||
to be fixed and compatibility with other PAM libraries was
|
||||
unnecessarily strained.
|
||||
* SAG documentation changes: Seth Chaiklin
|
||||
* rhosts: problems with NIS lookup failures with the root-uid check.
|
||||
As a work-around, I've partially eliminated the need for the lookup
|
||||
by supplying two new arguments: no_uid_check, superuser=<username>.
|
||||
As a general rule this is more pluggable, since this module might be
|
||||
used as an authentication scheme for a network service that does not
|
||||
need root privilege...
|
||||
* authenticate retval -> setcred for pam_pwdb (likeauth arg).
|
||||
* pam_pwdb event driven support
|
||||
* non openlog pam_listfile logging
|
||||
* BUGFIX: close filedescriptor in pam_group and pam_time (Emmanuel Galanos)
|
||||
* Chris Adams' mailhash change for pam_mail module
|
||||
* fixed malloc failure check in pam_handlers.c (follow up to comment
|
||||
by Brad M. Garcia).
|
||||
* update to _pam_compat.h (Brad M. Garcia)
|
||||
* support static modules in libpam again (Brad M. Garcia)
|
||||
* libpam/pam_misc.c for egcs to grok the code (Brad M. Garcia)
|
||||
* added a solaris-2.5.1 defs file (revived by Derrick J Brashear)
|
||||
* pam_listfile logs failed attempts
|
||||
* added a comment (Michael K Johnson pointed it out) about sgml2latex
|
||||
having a new syntax. I'll make it the change real when I upgrade...
|
||||
* a little more text to the RFC, spelling fix from William J Buffam.
|
||||
* minor changes to pam_securetty to accommodate event driven support.
|
||||
|
||||
0.65: Sun Apr 5 22:29:09 PDT 1998 <morgan@linux.kernel.org>
|
||||
|
||||
|
94
contrib/libpam/Make.Rules.in
Normal file
94
contrib/libpam/Make.Rules.in
Normal file
@ -0,0 +1,94 @@
|
||||
##
|
||||
## $Id: Make.Rules.in,v 1.6 2001/02/10 22:33:09 agmorgan Exp $
|
||||
##
|
||||
## @configure_input@
|
||||
##
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
bindir = @bindir@
|
||||
sbindir = @sbindir@
|
||||
libexecdir = @libexecdir@
|
||||
datadir = @datadir@
|
||||
sysconfdir = @sysconfdir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
localstatedir = @localstatedir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
mandir = @mandir@
|
||||
includedir = @includedir@
|
||||
|
||||
absolute_srcdir = @LOCALSRCDIR@
|
||||
|
||||
# major and minor numbers of this release
|
||||
MAJOR_REL=@LIBPAM_VERSION_MAJOR@
|
||||
MINOR_REL=@LIBPAM_VERSION_MINOR@
|
||||
|
||||
# The following is the generic set of compiler options for compiling
|
||||
# Linux-PAM. True, they are a little anal. Pay attention to the comments
|
||||
# they generate.
|
||||
|
||||
HEADER_DIRS=-I./include -I$(absolute_srcdir)/libpam/include \
|
||||
-I$(absolute_srcdir) -I$(absolute_srcdir)/libpamc/include
|
||||
WARNINGS=@WARNINGS@
|
||||
OS_CFLAGS=@OS_CFLAGS@
|
||||
PIC=@PIC@
|
||||
|
||||
# Mode to install shared libraries with
|
||||
SHLIBMODE=@SHLIBMODE@
|
||||
|
||||
NEED_LINK_LIB_C=@PAM_NEEDS_LIBC@
|
||||
HAVE_LCKPWDF=@HAVE_LCKPWDF@
|
||||
HAVE_LIBCRACK=@HAVE_LIBCRACK@
|
||||
HAVE_LIBCRYPT=@HAVE_LIBCRYPT@
|
||||
HAVE_LIBUTIL=@HAVE_LIBUTIL@
|
||||
HAVE_NDBM_H=@HAVE_NDBM_H@
|
||||
HAVE_LIBNDBM=@HAVE_LIBNDBM@
|
||||
HAVE_LIBDB=@HAVE_LIBDB@
|
||||
HAVE_LIBFL=@HAVE_LIBFL@
|
||||
HAVE_LIBNSL=@HAVE_LIBNSL@
|
||||
HAVE_LIBPWDB=@HAVE_LIBPWDB@
|
||||
|
||||
# documentation support
|
||||
HAVE_SGML2TXT=@HAVE_SGML2TXT@
|
||||
HAVE_SGML2HTML=@HAVE_SGML2HTML@
|
||||
PSER=@PSER@
|
||||
|
||||
# configuration settings
|
||||
WITH_DEBUG=@WITH_DEBUG@
|
||||
WITH_LIBDEBUG=@WITH_LIBDEBUG@
|
||||
WITH_PAMLOCKING=@WITH_PAMLOCKING@
|
||||
WITH_LCKPWDF=@WITH_LCKPWDF@
|
||||
STATIC_LIBPAM=@STATIC_LIBPAM@
|
||||
DYNAMIC_LIBPAM=@DYNAMIC_LIBPAM@
|
||||
STATIC=@STATIC@
|
||||
DYNAMIC=@DYNAMIC@
|
||||
|
||||
# Location of libraries when installed on the system
|
||||
FAKEROOT=@FAKEROOT@
|
||||
SECUREDIR=@SECUREDIR@
|
||||
SCONFIGD=@SCONFIGDIR@
|
||||
SUPLEMENTED=@SUPLEMENTED@
|
||||
INCLUDED=@INCLUDEDIR@/security
|
||||
CRACKLIB_DICTPATH=@CRACKLIB_DICTPATH@
|
||||
|
||||
# generic build setup
|
||||
OS=@OS@
|
||||
CC=@CC@
|
||||
CFLAGS=$(WARNINGS) -D$(OS) $(OS_CFLAGS) $(HEADER_DIRS) @CONF_CFLAGS@
|
||||
LD=@LD@
|
||||
LD_D=@LD_D@
|
||||
LD_L=@LD_L@
|
||||
DYNTYPE=@DYNTYPE@
|
||||
LIBDL=@LIBDL@
|
||||
MKDIR=@MKDIR@
|
||||
INSTALL=@INSTALL@
|
||||
RANLIB=@RANLIB@
|
||||
STRIP=@STRIP@
|
||||
CC_STATIC=@CC_STATIC@
|
||||
|
||||
LINKLIBS = $(NEED_LINK_LIB_C) $(LIBDL)
|
@ -1,282 +1,78 @@
|
||||
##
|
||||
## $Id: Makefile,v 1.31 1997/04/05 07:04:25 morgan Exp morgan $
|
||||
##
|
||||
## $Log: Makefile,v $
|
||||
##
|
||||
## $Id: Makefile,v 1.5 2001/01/20 22:29:47 agmorgan Exp $
|
||||
##
|
||||
|
||||
# major and minor numbers of this release
|
||||
MAJOR_REL=0
|
||||
MINOR_REL=65
|
||||
DEBUG_REL=no
|
||||
#DEBUG_REL=yes
|
||||
## Note, ideally I would prefer it if this top level makefile did
|
||||
## not get created by autoconf. As I find typing 'make' and relying
|
||||
## on it to take care of all dependencies much more friendly than
|
||||
## the multi-stage autoconf+make and also worry about updates to
|
||||
## configure.in not getting propagated down the tree. (AGM) [I realise
|
||||
## that this may not prove possible, but at least I tried.. Sigh.]
|
||||
|
||||
# this should be the name of this directory
|
||||
RELNAME = Linux-PAM-$(MAJOR_REL).$(MINOR_REL)
|
||||
DISTNAME=Linux-PAM
|
||||
|
||||
# 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
|
||||
ifeq ($(shell test \! -f Make.Rules || echo yes),yes)
|
||||
include Make.Rules
|
||||
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.
|
||||
THINGSTOMAKE = modules libpam libpamc libpam_misc doc examples
|
||||
|
||||
include default.defs
|
||||
all: $(THINGSTOMAKE)
|
||||
|
||||
# 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
|
||||
prep:
|
||||
rm -f security
|
||||
ln -sf . security
|
||||
|
||||
clean:
|
||||
@rm -f *~ core
|
||||
@for i in $(DIRS) ; do \
|
||||
$(MAKE) -C $$i clean ; \
|
||||
done
|
||||
if [ ! -f Make.Rules ]; then touch Make.Rules ; fi
|
||||
for i in $(THINGSTOMAKE) ; do $(MAKE) -C $$i clean ; done
|
||||
rm -f security *~ *.orig *.rej Make.Rules #*#
|
||||
|
||||
extraclean:
|
||||
@for i in $(DIRS) doc; do \
|
||||
$(MAKE) -C $$i extraclean ; \
|
||||
done
|
||||
distclean: clean
|
||||
rm -f Make.Rules _pam_aconf.h
|
||||
rm -f config.status config.cache config.log core
|
||||
|
||||
check:
|
||||
@$(MAKE) -C conf check
|
||||
maintainer-clean: distclean
|
||||
@echo files should be ok for packaging now.
|
||||
|
||||
RCScheck:
|
||||
@$(MAKE) -C conf RCScheck
|
||||
# NB _pam_aconf.h.in changes will remake this too
|
||||
Make.Rules: configure Make.Rules.in _pam_aconf.h.in
|
||||
@echo XXX - not sure how to preserve past configure options..
|
||||
@echo XXX - so not attempting to. Feel free to run ./configure
|
||||
@echo XXX - by hand, with the options you want.
|
||||
./configure
|
||||
|
||||
# this can be used to see what hasn't been check'd into RCS
|
||||
_pam_aconf.h: Make.Rules
|
||||
|
||||
open:
|
||||
@find . \( -type f -a -perm 644 \) -print
|
||||
configure: configure.in
|
||||
@echo
|
||||
@echo You do not appear to have an up-to-date ./configure file.
|
||||
@echo Please run autoconf, and then ./configure [..options..]
|
||||
@echo
|
||||
@rm -f configure
|
||||
@exit 1
|
||||
|
||||
$(THINGSTOMAKE): _pam_aconf.h prep
|
||||
$(MAKE) -C $@ all
|
||||
|
||||
install: _pam_aconf.h prep
|
||||
$(MKDIR) $(FAKEROOT)$(INCLUDED)
|
||||
$(INSTALL) -m 444 security/_pam_aconf.h $(FAKEROOT)$(INCLUDED)
|
||||
for x in $(THINGSTOMAKE) ; do make -C $$x install ; done
|
||||
|
||||
remove:
|
||||
rm -f $(FAKEROOT)$(INCLUDED)/_pam_aconf.h
|
||||
for x in $(THINGSTOMAKE) ; do make -C $$x remove ; done
|
||||
|
||||
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-)
|
||||
@if [ ! -f Make.Rules ]; then echo make Make.Rules first ; exit 1; fi
|
||||
@if [ ! -L ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) ]; then \
|
||||
echo generating ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) link ; \
|
||||
ln -sf $(DISTNAME) ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) ; \
|
||||
echo to ../$(DISTNAME) . ; fi
|
||||
@diff ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/Make.Rules Make.Rules
|
||||
make distclean
|
||||
cd .. ; tar zvfc $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL).tar.gz \
|
||||
--exclude CVS --exclude .cvsignore --exclude '.#*' \
|
||||
$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/*
|
||||
|
||||
|
@ -1,167 +1,28 @@
|
||||
#
|
||||
# $Id: README,v 1.14 1997/04/05 07:04:46 morgan Exp $
|
||||
# $Id: README,v 1.3 2000/11/20 00:01:49 agmorgan 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.]
|
||||
Thanks for downloading Linux-PAM.
|
||||
|
||||
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!
|
||||
How to use it is as follows:
|
||||
|
||||
* 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.
|
||||
./configure --help | less
|
||||
./configure <your-options>
|
||||
make
|
||||
|
||||
* Currently, you have to 'make' binaries from this directory. 'make
|
||||
clean', however, works in any directory that has a Makefile.
|
||||
Note, if you are worried - don't even think about doing the next line
|
||||
(most Linux distributions already support PAM out of the box, so if
|
||||
something goes wrong with installing the code from this version your
|
||||
box may stop working..)
|
||||
|
||||
* 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 install
|
||||
|
||||
* '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
|
||||
That said, please report problems to me.
|
||||
|
||||
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/
|
||||
<morgan@kernel.org>
|
||||
<agmorgan@users.sourceforge.net>
|
||||
|
64
contrib/libpam/_pam_aconf.h.in
Normal file
64
contrib/libpam/_pam_aconf.h.in
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* $Id: _pam_aconf.h.in,v 1.4 2000/12/04 20:56:10 baggins Exp $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PAM_ACONF_H
|
||||
#define PAM_ACONF_H
|
||||
|
||||
/* lots of stuff gets written to /tmp/pam-debug.log */
|
||||
#undef DEBUG
|
||||
|
||||
/* build libraries with different names (suffixed with 'd') */
|
||||
#undef WITH_LIBDEBUG
|
||||
|
||||
/* provide a global locking facility within libpam */
|
||||
#undef PAM_LOCKING
|
||||
|
||||
/* GNU systems as a class, all have the feature.h file */
|
||||
#undef HAVE_FEATURES_H
|
||||
#ifdef HAVE_FEATURES_H
|
||||
# define _SVID_SOURCE
|
||||
# define _BSD_SOURCE
|
||||
# define __USE_BSD
|
||||
# define __USE_SVID
|
||||
# define __USE_MISC
|
||||
# define _GNU_SOURCE
|
||||
# include <features.h>
|
||||
#endif /* HAVE_FEATURES_H */
|
||||
|
||||
/* we have libcrack available */
|
||||
#undef HAVE_LIBCRACK
|
||||
|
||||
/* we have libcrypt - its not part of libc (do we need both definitions?) */
|
||||
#undef HAVE_LIBCRYPT
|
||||
#undef HAVE_CRYPT_H
|
||||
|
||||
/* we have libndbm and/or libdb */
|
||||
#undef HAVE_DB_H
|
||||
#undef HAVE_NDBM_H
|
||||
|
||||
/* have libfl (Flex) */
|
||||
#undef HAVE_LIBFL
|
||||
|
||||
/* have libnsl - instead of libc support */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* have libpwdb - don't expect this to be important for much longer */
|
||||
#undef HAVE_LIBPWDB
|
||||
|
||||
/* ugly hack to partially support old pam_strerror syntax */
|
||||
#undef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT
|
||||
|
||||
/* read both confs - read /etc/pam.d and /etc/pam.conf in serial */
|
||||
#undef PAM_READ_BOTH_CONFS
|
||||
|
||||
#undef HAVE_PATHS_H
|
||||
#ifdef HAVE_PATHS_H
|
||||
#include <paths.h>
|
||||
#endif
|
||||
/* location of the mail spool directory */
|
||||
#undef PAM_PATH_MAILDIR
|
||||
|
||||
#endif /* PAM_ACONF_H */
|
3548
contrib/libpam/configure
vendored
Executable file
3548
contrib/libpam/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
339
contrib/libpam/configure.in
Normal file
339
contrib/libpam/configure.in
Normal file
@ -0,0 +1,339 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(conf/pam_conv1/pam_conv.y)
|
||||
|
||||
dnl The configuration header file
|
||||
AC_CONFIG_HEADER(_pam_aconf.h)
|
||||
|
||||
dnl
|
||||
dnl Release specific
|
||||
dnl
|
||||
|
||||
LIBPAM_VERSION_MAJOR=0
|
||||
LIBPAM_VERSION_MINOR=75
|
||||
|
||||
AC_SUBST(LIBPAM_VERSION_MAJOR)
|
||||
AC_SUBST(LIBPAM_VERSION_MINOR)
|
||||
AC_DEFINE(LIBPAM_VERSION_MAJOR)
|
||||
AC_DEFINE(LIBPAM_VERSION_MINOR)
|
||||
|
||||
dnl
|
||||
dnl By default, everything under PAM is installed under the root fs.
|
||||
dnl
|
||||
|
||||
AC_PREFIX_DEFAULT()
|
||||
|
||||
dnl
|
||||
dnl Rules needed for the following (hardcoded Linux defaults for now)
|
||||
dnl
|
||||
|
||||
CC=gcc ; AC_SUBST(CC)
|
||||
CONF_CFLAGS= ; AC_SUBST(CONF_CFLAGS)
|
||||
MKDIR="mkdir -p" ; AC_SUBST(MKDIR)
|
||||
LOCALSRCDIR=`/bin/pwd` ; AC_SUBST(LOCALSRCDIR)
|
||||
OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
|
||||
AC_SUBST(OS)
|
||||
|
||||
dnl These are most likely platform specific - I think HPUX differs
|
||||
DYNTYPE=so ; AC_SUBST(DYNTYPE)
|
||||
USESONAME=yes ; AC_SUBST(USESONAME)
|
||||
NEEDSONAME=yes ; AC_SUBST(NEEDSONAME)
|
||||
SHLIBMODE=755 ; AC_SUBST(SHLIBMODE)
|
||||
|
||||
dnl ### Should enable this INSTALL detection.
|
||||
dnl ### Would need to distribute GNU's config.guess and config.sub
|
||||
dnl AC_PROG_INSTALL
|
||||
INSTALL=/usr/bin/install ; AC_SUBST(INSTALL)
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
dnl ### AC_PROG_CXX
|
||||
AC_PROG_YACC
|
||||
AC_PROG_LEX
|
||||
dnl AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
dnl
|
||||
dnl options and defaults
|
||||
dnl
|
||||
|
||||
dnl lots of debugging information goes to /tmp/pam-debug.log
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug qspecify you are building with debugging on],
|
||||
WITH_DEBUG=yes ; AC_DEFINE(DEBUG) , WITH_DEBUG=no)
|
||||
AC_SUBST(WITH_DEBUG)
|
||||
|
||||
dnl build specially named libraries (for debugging purposes)
|
||||
AC_ARG_ENABLE(libdebug,
|
||||
[ --enable-libdebug specify you are building debugging libraries],
|
||||
WITH_LIBDEBUG=yes ; AC_DEFINE(WITH_LIBDEBUG) , WITH_LIBDEBUG=no)
|
||||
AC_SUBST(WITH_LIBDEBUG)
|
||||
|
||||
dnl packaging convenience
|
||||
AC_ARG_ENABLE(fakeroot,
|
||||
[ --enable-fakeroot=<path to packaging directory>], FAKEROOT=$enableval)
|
||||
AC_SUBST(FAKEROOT)
|
||||
|
||||
AC_ARG_ENABLE(securedir,
|
||||
[ --enable-securedir=<path to location of PAMs> [default \$libdir/security]],
|
||||
SECUREDIR=$enableval, SECUREDIR=$libdir/security)
|
||||
AC_SUBST(SECUREDIR)
|
||||
|
||||
AC_ARG_ENABLE(sconfigdir,
|
||||
[ --enable-sconfigdir=<path to module conf files> [default \$sysconfdir/security]],
|
||||
SCONFIGDIR=$enableval, SCONFIGDIR=$sysconfdir/security)
|
||||
AC_SUBST(SCONFIGDIR)
|
||||
|
||||
AC_ARG_ENABLE(suplementedir,
|
||||
[ --enable-suplementedir=<path to module helper binaries> [default \$sbindir]],
|
||||
SUPLEMENTED=$enableval, SUPLEMENTED=$sbindir)
|
||||
AC_SUBST(SUPLEMENTED)
|
||||
|
||||
AC_ARG_ENABLE(includedir,
|
||||
[ --enable-includedir=<path to include location> - where to put <security>],
|
||||
INCLUDEDIR=$enableval, INCLUDEDIR=/usr/include)
|
||||
AC_SUBST(INCLUDEDIR)
|
||||
|
||||
AC_ARG_ENABLE(pamlocking,
|
||||
[ --enable-pamlocking configure libpam to observe a global authentication lock],
|
||||
WITH_PAMLOCKING=yes ; AC_DEFINE(PAM_LOCKING) , WITH_PAMLOCKING=no)
|
||||
AC_SUBST(WITH_PAMLOCKING)
|
||||
|
||||
AC_ARG_ENABLE(uglyhack,
|
||||
[ --enable-uglyhack configure libpam to try to honor old pam_strerror syntax],
|
||||
AC_DEFINE(UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT))
|
||||
|
||||
AC_ARG_ENABLE(read-both-confs,
|
||||
[ --enable-read-both-confs read both /etc/pam.d and /etc/pam.conf files],
|
||||
AC_DEFINE(PAM_READ_BOTH_CONFS))
|
||||
AC_SUBST(PAM_READ_BOTH_CONFS)
|
||||
|
||||
AC_ARG_ENABLE(static-libpam, [ --enable-static-libpam build a libpam.a library],
|
||||
STATIC_LIBPAM=yes , STATIC_LIBPAM=no)
|
||||
AC_SUBST(STATIC_LIBPAM)
|
||||
|
||||
AC_ARG_ENABLE(dynamic-libpam,
|
||||
[ --disable-dynamic-libpam do not build a shared libpam library],
|
||||
DYNAMIC_LIBPAM=no, DYNAMIC_LIBPAM=yes)
|
||||
AC_SUBST(DYNAMIC_LIBPAM)
|
||||
|
||||
DYNAMIC=-DPAM_DYNAMIC
|
||||
AC_SUBST(DYNAMIC)
|
||||
|
||||
AC_ARG_ENABLE(static-modules,
|
||||
[ --enable-static-modules do not make the modules dynamically loadable],
|
||||
STATIC=-DPAM_STATIC)
|
||||
AC_SUBST(STATIC)
|
||||
|
||||
AC_ARG_ENABLE(lckpwdf,
|
||||
[ --disable-lckpwdf do not use the lckpwdf function],
|
||||
WITH_LCKPWDF=no, WITH_LCKPWDF=yes)
|
||||
AC_SUBST(WITH_LCKPWDF)
|
||||
|
||||
AC_CHECK_HEADERS(paths.h)
|
||||
AC_ARG_WITH(mailspool,
|
||||
[ --with-mailspool path to mail spool directory
|
||||
[default _PATH_MAILDIR if defined in paths.h, otherwise /var/spool/mail]],
|
||||
with_mailspool=${withval})
|
||||
if test x$with_mailspool != x ; then
|
||||
pam_mail_spool="\"$with_mailspool\""
|
||||
else
|
||||
AC_TRY_RUN([
|
||||
#include <paths.h>
|
||||
int main() {
|
||||
#ifdef _PATH_MAILDIR
|
||||
exit(0);
|
||||
#else
|
||||
exit(1);
|
||||
#endif
|
||||
}], pam_mail_spool="_PATH_MAILDIR",
|
||||
pam_mail_spool="\"/var/spool/mail\"",
|
||||
pam_mail_spool="\"/var/spool/mail\"")
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(PAM_PATH_MAILDIR, $pam_mail_spool)
|
||||
|
||||
dnl Checks for libraries.
|
||||
AC_CHECK_LIB(c, __libc_sched_setscheduler, PAM_NEEDS_LIBC=, PAM_NEEDS_LIBC=-lc)
|
||||
AC_SUBST(PAM_NEEDS_LIBC)
|
||||
|
||||
dnl Checks for the existence of lckpwdf in libc
|
||||
AC_CHECK_LIB(c, lckpwdf, HAVE_LCKPWDF=yes, HAVE_LCKPWDF=no)
|
||||
AC_SUBST(HAVE_LCKPWDF)
|
||||
|
||||
dnl Checks for the existence of libdl - on BSD its part of libc
|
||||
AC_CHECK_LIB(dl, dlopen, LIBDL=-ldl)
|
||||
AC_SUBST(LIBDL)
|
||||
|
||||
dnl
|
||||
dnl At least on Solaris, the existing libcrack must be dynamic.
|
||||
dnl Ought to introduce a check for this.
|
||||
dnl
|
||||
AC_CHECK_LIB(crack, FascistCheck, HAVE_LIBCRACK=yes ; AC_DEFINE(HAVE_LIBCRACK),
|
||||
HAVE_LIBCRACK=no)
|
||||
AC_SUBST(HAVE_LIBCRACK)
|
||||
|
||||
AC_CHECK_LIB(crypt, fcrypt, HAVE_LIBCRYPT=yes ; AC_DEFINE(HAVE_LIBCRYPT),
|
||||
HAVE_LIBCRYPT=no)
|
||||
AC_SUBST(HAVE_LIBCRYPT)
|
||||
AC_CHECK_LIB(util, logwtmp, HAVE_LIBUTIL=yes ; AC_DEFINE(HAVE_LIBUTIL),
|
||||
HAVE_LIBUTIL=no)
|
||||
AC_SUBST(HAVE_LIBUTIL)
|
||||
AC_CHECK_LIB(ndbm, dbm_store, HAVE_LIBNDBM=yes ; AC_DEFINE(HAVE_LIBNDBM),
|
||||
HAVE_LIBNDBM=no)
|
||||
AC_SUBST(HAVE_LIBNDBM)
|
||||
AC_CHECK_LIB(db, dbm_store, HAVE_LIBDB=yes ; AC_DEFINE(HAVE_LIBDB),
|
||||
HAVE_LIBDB=no)
|
||||
AC_SUBST(HAVE_LIBDB)
|
||||
AC_CHECK_LIB(fl, yylex, yyterminate, HAVE_LIBFL=yes ; AC_DEFINE(HAVE_LIBFL),
|
||||
HAVE_LIBFL=no)
|
||||
AC_SUBST(HAVE_LIBFL)
|
||||
AC_CHECK_LIB(nsl, yp_maplist, HAVE_LIBNSL=yes ; AC_DEFINE(HAVE_LIBNSL),
|
||||
HAVE_LIBNSL=no)
|
||||
AC_SUBST(HAVE_LIBNSL)
|
||||
AC_CHECK_LIB(pwdb, pwdb_db_name, HAVE_LIBPWDB=yes ; AC_DEFINE(HAVE_LIBPWDB),
|
||||
HAVE_LIBPWDB=no)
|
||||
AC_SUBST(HAVE_LIBPWDB)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h)
|
||||
|
||||
dnl Linux wants features.h in some of the source files.
|
||||
AC_CHECK_HEADERS(features.h)
|
||||
|
||||
dnl For module/pam_cracklib
|
||||
AC_CHECK_HEADERS(crypt.h)
|
||||
|
||||
dnl For module/pam_userdb
|
||||
AC_CHECK_HEADERS(ndbm.h db.h)
|
||||
dnl I suspect the following two lines are a hack.
|
||||
HAVE_NDBM_H=$ac_cv_header_ndbm_h
|
||||
AC_SUBST(HAVE_NDBM_H)
|
||||
|
||||
dnl For module/pam_lastlog
|
||||
AC_CHECK_HEADERS(lastlog.h utmp.h utmpx.h)
|
||||
|
||||
dnl This following rule should be made conditional upon HAVE_LIBCRYPT
|
||||
dnl being found.
|
||||
|
||||
dnl Look for cracklib dictionary
|
||||
AC_MSG_CHECKING(path to cracklib dictionary)
|
||||
DICT_DIR_CANDIDATES="/usr/lib /usr/share/dict /usr/share/lib \
|
||||
/usr/local/lib /usr/local/share/lib"
|
||||
DICT_FILE_CANDIDATES="pw_dict cracklib_dict"
|
||||
CRACKLIB_DICTPATH=""
|
||||
for d in $DICT_DIR_CANDIDATES ; do
|
||||
for f in $DICT_FILE_CANDIDATES ; do
|
||||
if test -r $d/$f.hwm ; then
|
||||
CRACKLIB_DICTPATH=$d/$f
|
||||
break 2
|
||||
elif test -r $d/dict/$f.hwm ; then
|
||||
CRACKLIB_DICTPATH=$d/dict/$f
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
if test -z "$CRACKLIB_DICTPATH" ; then
|
||||
AC_MSG_RESULT(none found)
|
||||
else
|
||||
AC_MSG_RESULT($CRACKLIB_DICTPATH)
|
||||
fi
|
||||
AC_SUBST(CRACKLIB_DICTPATH)
|
||||
|
||||
dnl Set FLAGS, linker options etc. depending on C compiler.
|
||||
dnl gcc is tested and much preferred; others less so, if at all
|
||||
dnl
|
||||
dnl If compiling with gcc, linking is also supposed to be done with gcc;
|
||||
dnl since we use linker-specific arguments, we may not gain anything by
|
||||
dnl switching LD_L over, but I think we can use LD_D as-is.
|
||||
dnl
|
||||
dnl For the moment, gcc is enforced above at "CC=gcc".
|
||||
dnl
|
||||
dnl There is an issue over _POSIX_SOURCE _BSD_SOURCE and _GNU_SOURCE .
|
||||
dnl The original "Linux-PAM" had blanket inclusion. But portability
|
||||
dnl requires their default absence: if particular OSes require them,
|
||||
dnl this should be done selectively.
|
||||
|
||||
GCC_WARNINGS="-Wall -Wwrite-strings \
|
||||
-Wpointer-arith -Wcast-qual -Wcast-align \
|
||||
-Wstrict-prototypes -Wmissing-prototypes \
|
||||
-Wnested-externs -Winline -Wshadow"
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
###
|
||||
### Non-Linux needs attention on per-OS basis
|
||||
OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic"
|
||||
WARNINGS="$GCC_WARNINGS"
|
||||
PIC="-fPIC"
|
||||
#can/should we use LD=gcc ???
|
||||
LD=ld
|
||||
LD_D="gcc -shared -Xlinker -x"
|
||||
LD_L="$LD -x -shared"
|
||||
RANLIB=ranlib
|
||||
STRIP=strip
|
||||
CC_STATIC="-Xlinker -export-dynamic"
|
||||
else
|
||||
###
|
||||
### Non-gcc needs attention on per-OS basis
|
||||
###
|
||||
### [These are Solaris-C specific...]
|
||||
OS_CFLAGS=""
|
||||
WARNINGS=""
|
||||
PIC="-K pic"
|
||||
LD=ld
|
||||
LD_D="cc -z text -G -R."
|
||||
LD_L="$LD_D"
|
||||
RANLIB=ranlib
|
||||
STRIP=strip
|
||||
CC_STATIC=
|
||||
fi
|
||||
|
||||
AC_SUBST(OS_CFLAGS)
|
||||
AC_SUBST(WARNINGS)
|
||||
AC_SUBST(PIC)
|
||||
AC_SUBST(LD)
|
||||
AC_SUBST(LD_D)
|
||||
AC_SUBST(LD_L)
|
||||
AC_SUBST(RANLIB)
|
||||
AC_SUBST(STRIP)
|
||||
AC_SUBST(CC_STATIC)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_BIGENDIAN
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_TYPE_GETGROUPS
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS(gethostname gettimeofday mkdir select strcspn strdup strerror strspn strstr strtol uname)
|
||||
|
||||
dnl Checks for programs/utilities
|
||||
AC_CHECK_PROG(HAVE_SGML2TXT, sgml2txt, yes, no)
|
||||
AC_CHECK_PROG(HAVE_SGML2HTML, sgml2html, yes, no)
|
||||
AC_CHECK_PROG(HAVE_SGML2LATEX, sgml2latex, yes, no)
|
||||
if test $HAVE_SGML2LATEX = "yes" ; then
|
||||
if sgml2latex -h | grep -e --paper | grep ' -p ' > /dev/null ; then
|
||||
PSER="sgml2latex -o ps"
|
||||
else
|
||||
PSER="sgml2latex -p"
|
||||
fi
|
||||
else
|
||||
AC_CHECK_PROG(HAVE_SGML2PS, sgml2ps, yes, no)
|
||||
if test $HAVE_SGML2PS = yes ; then
|
||||
PSER="sgml2ps"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(PSER)
|
||||
|
||||
dnl Files to be created from when we run configure
|
||||
AC_OUTPUT(Make.Rules)
|
40
contrib/libpam/defs/debian.defs
Normal file
40
contrib/libpam/defs/debian.defs
Normal file
@ -0,0 +1,40 @@
|
||||
##
|
||||
# defs for Debian
|
||||
# Ben Collins <bcollins@debian.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.
|
||||
##
|
||||
|
||||
CFLAGS := -O2 -I${shell pwd}/include # -D__NO_STRING_INLINES
|
||||
ifneq (,$(findstring $(DEB_BUILD_OPTIONS),debug DEBUG Debug))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
|
||||
OS := $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM)
|
||||
ARCH := $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU)
|
||||
CC := gcc
|
||||
INSTALL := install
|
||||
MKDIR := mkdir -p
|
||||
ULIBS :=
|
||||
LD := ld
|
||||
LD_D := gcc -shared -Xlinker -x
|
||||
LD_L := $(LD) -x -shared
|
||||
AR := ar -cr
|
||||
RANLIB := ranlib
|
||||
PREFIX :=
|
||||
LIBDIR := $(PREFIX)/lib
|
||||
USESONAME := yes
|
||||
SOSWITCH := -soname
|
||||
LINKLIBS := -lc -L${shell pwd}/libpam -L${shell pwd}/libpam_misc
|
||||
NEEDSONAME := no
|
||||
LDCONFIG := /sbin/ldconfig
|
||||
FAKEROOT :=
|
||||
SUPLEMENTED := $(PREFIX)/sbin
|
||||
SECUREDIR := $(LIBDIR)/security
|
||||
INCLUDED := /usr/include/security
|
||||
CONFIGED := /etc
|
||||
SCONFIGED := /etc/security
|
||||
EXTRALS := -lnsl -lcrypt
|
||||
WARNINGS := -Wall
|
35
contrib/libpam/defs/redhat4.defs
Normal file
35
contrib/libpam/defs/redhat4.defs
Normal file
@ -0,0 +1,35 @@
|
||||
##
|
||||
# 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
|
||||
LINKLIBS=-lc
|
||||
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
|
45
contrib/libpam/defs/solaris-2.1.5.defs
Normal file
45
contrib/libpam/defs/solaris-2.1.5.defs
Normal file
@ -0,0 +1,45 @@
|
||||
##
|
||||
# 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=gcc
|
||||
INSTALL=install
|
||||
MKDIR=mkdir -p
|
||||
CFLAGS=-O7 -pipe -g -D__EXTENSIONS__ -Dsolaris
|
||||
ULIBS=
|
||||
LD_D=gcc -shared -Xlinker -x
|
||||
LD=ld
|
||||
LD_L=$(LD) -G
|
||||
USESONAME=yes
|
||||
SOSWITCH=-h
|
||||
NEEDSONAME=no
|
||||
LDCONFIG=/sbin/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
|
36
contrib/libpam/defs/suse.defs
Normal file
36
contrib/libpam/defs/suse.defs
Normal file
@ -0,0 +1,36 @@
|
||||
##
|
||||
# defs for SuSE Linux
|
||||
# Thorsten Kukuk <kukuk@suse.de>
|
||||
##
|
||||
# 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 SuSE Linux.
|
||||
|
||||
OS=linux
|
||||
ARCH=$(shell rpm --showrc | grep 'build arch' | grep -v "compatible" | sed 's/^.*: //g')
|
||||
CC=gcc
|
||||
INSTALL=install
|
||||
MKDIR=mkdir -p
|
||||
CFLAGS=$(RPM_OPT_FLAGS) -pipe -D_REENTRANT
|
||||
ULIBS=#-lefence
|
||||
LD=ld
|
||||
LD_D=gcc -shared -Xlinker -x
|
||||
LD_L=$(LD) -x -shared
|
||||
USESONAME=yes
|
||||
SOSWITCH=-soname
|
||||
LINKLIBS=-lc
|
||||
NEEDSONAME=yes
|
||||
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
|
||||
EXTRALS=-lcrypt
|
@ -1,29 +1,41 @@
|
||||
<!--
|
||||
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 $
|
||||
$Id: CREDITS,v 1.2 2001/03/19 01:46:41 agmorgan Exp $
|
||||
-->
|
||||
Chris Adams,
|
||||
Peter Allgeyer,
|
||||
Tim Baverstock,
|
||||
Tim Berger,
|
||||
Craig S. Bell,
|
||||
Derrick J. Brashear,
|
||||
Ben Buxton,
|
||||
Seth Chaiklin,
|
||||
Oliver Crow,
|
||||
Chris Dent,
|
||||
Marc Ewing,
|
||||
Cristian Gafton,
|
||||
Emmanuel Galanos,
|
||||
Brad M. Garcia,
|
||||
Eric Hester,
|
||||
Michel D'Hooge,
|
||||
Roger Hu,
|
||||
Eric Jacksch,
|
||||
Michael K. Johnson,
|
||||
David Kinchlea,
|
||||
Olaf Kirch,
|
||||
Marcin Korzonek,
|
||||
Stephen Langasek,
|
||||
Nicolai Langfeldt,
|
||||
Elliot Lee,
|
||||
Luke Kenneth Casson Leighton,
|
||||
Al Longyear,
|
||||
Ingo Luetkebohle,
|
||||
Marek Michalkiewicz,
|
||||
Robert Milkowski,
|
||||
Aleph One,
|
||||
Martin Pool,
|
||||
Sean Reifschneider,
|
||||
Jan Rekorajski,
|
||||
Erik Troan,
|
||||
Theodore Ts'o,
|
||||
Jeff Uphoff,
|
||||
|
@ -1,10 +1,13 @@
|
||||
|
||||
### $Id: Makefile,v 1.9 1997/01/04 21:55:52 morgan Exp $
|
||||
### $Id: Makefile,v 1.3 2001/01/22 08:03:01 agmorgan Exp $
|
||||
|
||||
TXTER=sgml2txt
|
||||
HTMLER=sgml2html
|
||||
# older distributions use, sgml2ps
|
||||
PSER=sgml2latex -p
|
||||
include ../Make.Rules
|
||||
|
||||
# These two should probably be moved into autoconf...
|
||||
DOCDIR=/usr/doc/Linux-PAM
|
||||
MANDIR=/usr/man
|
||||
|
||||
#######################################################
|
||||
|
||||
FILES=pam pam_appl pam_modules
|
||||
FSRCS=pam.sgml pam_appl.sgml pam_modules.sgml
|
||||
@ -26,36 +29,48 @@ all: htmls texts postscript
|
||||
htmls: $(HTMLS)
|
||||
|
||||
$(HTMLS) : $(FSRCS)
|
||||
ifeq ($(HAVE_SGML2HTML),yes)
|
||||
@for i in $(FILES) ; do \
|
||||
if [ ! -f "html/$$i.html" ] || [ "$$i.sgml" -nt "html/$$i.html" ]; \
|
||||
then \
|
||||
cd html ; $(HTMLER) ../$$i ; \
|
||||
cd html ; sgml2html ../$$i ; \
|
||||
if [ $$? -ne 0 ]; then exit 1 ; fi ; \
|
||||
cd .. ; \
|
||||
fi ; \
|
||||
done
|
||||
else
|
||||
@echo XXX - you do not have the sgml2html binary installed
|
||||
endif
|
||||
|
||||
texts: $(TEXTS)
|
||||
|
||||
$(TEXTS) : $(FSRCS)
|
||||
ifeq ($(HAVE_SGML2TXT),yes)
|
||||
@for i in $(FILES) ; do \
|
||||
if [ ! -f "txts/$$i.txt" ] \
|
||||
|| [ "$$i.sgml" -nt "txts/$$i.txt" ]; then \
|
||||
cd txts ; $(TXTER) ../$$i ; cd .. ; \
|
||||
cd txts ; sgml2txt ../$$i ; cd .. ; \
|
||||
fi ; \
|
||||
done
|
||||
else
|
||||
@echo XXX - you do not have the sgml2txt binary installed
|
||||
endif
|
||||
|
||||
postscript: $(PSFILES)
|
||||
|
||||
$(PSFILES): $(FSRCS)
|
||||
ifneq ($(PSER),)
|
||||
@for i in $(FILES) ; do \
|
||||
if [ ! -f "ps/$$i.ps" ] || [ "$$i.sgml" -nt "ps/$$i.ps" ]; then \
|
||||
cd ps ; $(PSER) ../$$i ; cd .. ; \
|
||||
fi ; \
|
||||
done
|
||||
else
|
||||
@echo XXX - neither sgml2ps nor sgml2latex binaries are installed
|
||||
endif
|
||||
|
||||
pam.sgml: pam_source.sgml MODULES-SGML
|
||||
@sed -e '/^<!\-\- insert\-file MODULES\-SGML \-\->/r MODULES-SGML' pam_source.sgml > pam.sgml
|
||||
pam.sgml: pam_source.sgml MODULES-SGML CREDITS
|
||||
@sed -e '/^<!\-\- insert\-file MODULES\-SGML \-\->/r MODULES-SGML' pam_source.sgml | sed -e '/^<!\-\- insert\-file CREDITS \-\->/r CREDITS' > pam.sgml
|
||||
|
||||
MODULES-SGML: $(MODULES)
|
||||
@echo 'Building module text from files in modules/*.sgml'
|
||||
@ -67,11 +82,64 @@ MODULES-SGML: $(MODULES)
|
||||
|
||||
extraclean: clean
|
||||
|
||||
remove:
|
||||
cd man && for file in *.3 ; do \
|
||||
rm -f $(FAKEROOT)$(MANDIR)/man3/$$file ; \
|
||||
done
|
||||
cd man && for file in *.8 ; do \
|
||||
rm -f $(FAKEROOT)$(MANDIR)/man8/$$file ; \
|
||||
done
|
||||
cd txts && for file in *.txt; do \
|
||||
rm -f $(FAKEROOT)$(DOCDIR)/text/$$file ; \
|
||||
done
|
||||
cd ps && for file in *.ps; do \
|
||||
rm -f $(FAKEROOT)$(DOCDIR)/ps/$$file ; \
|
||||
done
|
||||
cd html && for file in *.html; do \
|
||||
rm -f $(FAKEROOT)$(DOCDIR)/html/$$file ; \
|
||||
done
|
||||
|
||||
install: all
|
||||
ifeq ($(HAVE_SGML2TXT),yes)
|
||||
mkdir -p $(FAKEROOT)$(DOCDIR)/text
|
||||
for file in txts/*.txt; do \
|
||||
install -m 644 $$file $(FAKEROOT)$(DOCDIR)/text ; \
|
||||
done
|
||||
endif
|
||||
ifneq ($(PSER),)
|
||||
mkdir -p $(FAKEROOT)$(DOCDIR)/ps
|
||||
for file in ps/*.ps; do \
|
||||
install -m 644 $$file $(FAKEROOT)$(DOCDIR)/ps ; \
|
||||
done
|
||||
endif
|
||||
ifeq ($(HAVE_SGML2HTML),yes)
|
||||
mkdir -p $(FAKEROOT)$(DOCDIR)/html
|
||||
for file in html/*.html; do \
|
||||
install -m 644 $$file $(FAKEROOT)$(DOCDIR)/html ; \
|
||||
done
|
||||
endif
|
||||
mkdir -p $(FAKEROOT)$(MANDIR)/man{3,8}
|
||||
for file in man/*.3 ; do \
|
||||
install -m 644 $$file $(FAKEROOT)$(MANDIR)/man3 ; \
|
||||
done
|
||||
for file in man/*.8 ; do \
|
||||
install -m 644 $$file $(FAKEROOT)$(MANDIR)/man8 ; \
|
||||
done
|
||||
|
||||
spec:
|
||||
cd specs/formatter && make
|
||||
specs/formatter/padout < specs/draft-morgan-pam.raw > specs/draft-morgan-pam-current.txt
|
||||
|
||||
releasedocs: all spec
|
||||
tar zvfc Linux-PAM-$(MAJOR_REL).$(MINOR_REL)-docs.tar.gz --exclude CVS html ps txts specs/draft-morgan-pam-current.txt
|
||||
|
||||
clean:
|
||||
rm -f *~ *.bak
|
||||
rm -f html/pam*.html
|
||||
rm -f man/*~
|
||||
rm -f $(TEXTS)
|
||||
rm -f $(PSFILES)
|
||||
rm -f $(PSFILES) ps/missfont.log
|
||||
rm -f MODULES-SGML pam.sgml
|
||||
rm -f specs/draft-morgan-pam-current.txt
|
||||
make -C specs/formatter clean
|
||||
|
||||
|
@ -17,5 +17,5 @@ currently not complete. However, in order of decreasing length:
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
REVISION: <tt>$Id: index.html,v 1.4 1996/11/21 06:51:01 morgan Exp $</tt>
|
||||
REVISION: <tt>$Id: index.html,v 1.1.1.1 2000/06/20 22:10:56 agmorgan Exp $</tt>
|
||||
</BODY>
|
||||
|
@ -1 +1 @@
|
||||
.so man8/pam.8
|
||||
.so pam.8
|
||||
|
@ -1 +1 @@
|
||||
.so man8/pam.8
|
||||
.so pam.8
|
||||
|
@ -1 +1 @@
|
||||
.so man3/pam_open_session.3
|
||||
.so pam_open_session.3
|
||||
|
@ -1 +1 @@
|
||||
.so man3/pam_start.3
|
||||
.so pam_start.3
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\" Hey Emacs! This file is -*- nroff -*- source.
|
||||
.\" $Id: template-man,v 1.1 1997/01/04 18:25:13 morgan Exp $
|
||||
.\" $Id: template-man,v 1.1.1.1 2000/06/20 22:10:58 agmorgan 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
|
||||
|
108
contrib/libpam/doc/modules/pam_access.sgml
Normal file
108
contrib/libpam/doc/modules/pam_access.sgml
Normal file
@ -0,0 +1,108 @@
|
||||
<!--
|
||||
|
||||
pam_access module docs added by Tim Berger <timb@transmeta.com>
|
||||
|
||||
-->
|
||||
|
||||
<sect1> The access module
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
|
||||
<tt>pam_access</tt>
|
||||
|
||||
|
||||
<tag><bf>Author[s]:</bf></tag>
|
||||
|
||||
Alexei Nogin <alexei@nogin.dnttm.ru>
|
||||
|
||||
<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. By default
|
||||
<tt>/etc/security/access.conf</tt> is used but this can be overridden.
|
||||
|
||||
<tag><bf>Network aware:</bf></tag>
|
||||
|
||||
Through <tt/PAM_TTY/ if set, otherwise attempts getting tty name of
|
||||
the stdin file descriptor with <tt/ttyname()/. Standard
|
||||
gethostname(), <tt/yp_get_default_domain()/, <tt/gethostbyname()/
|
||||
calls. <bf/NIS/ is used for netgroup support.
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
Provides logdaemon style login access control.
|
||||
|
||||
<sect2> Account component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
|
||||
<tt>accessfile=<it>/path/to/file.conf</it></tt>
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
|
||||
This module provides logdaemon style 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 <tt/syslog(3)/. Wietse
|
||||
Venema's <tt/login_access.c/ from <em/logdaemon-5.6/ is used with
|
||||
several changes by A. Nogin.
|
||||
|
||||
<p>
|
||||
The behavior of this module can be modified with the following
|
||||
arguments:
|
||||
<itemize>
|
||||
|
||||
<item><tt>accessfile=/path/to/file.conf</tt> -
|
||||
indicate an alternative <em/access/ configuration file to override
|
||||
the default. This can be useful when different services need different
|
||||
access lists.
|
||||
|
||||
</itemize>
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
Use of module is recommended, for example, on administrative machines
|
||||
such as <bf/NIS/ servers and mail servers where you need several accounts
|
||||
active but don't want them all to have login capability.
|
||||
|
||||
For <tt>/etc/pam.d</tt> style configurations where your modules live
|
||||
in <tt>/lib/security</tt>, start by adding the following line to
|
||||
<tt>/etc/pam.d/login</tt>, <tt>/etc/pam.d/rlogin</tt>,
|
||||
<tt>/etc/pam.d/rsh</tt> and <tt>/etc/pam.d/ftp</tt>:
|
||||
|
||||
<tscreen>
|
||||
<verb>
|
||||
account required /lib/security/pam_access.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
Note that use of this module is not effective unless your system ignores
|
||||
<tt>.rhosts</tt> files. See the the pam_rhosts_auth documentation.
|
||||
|
||||
A sample <tt>access.conf</tt> configuration file is included with the
|
||||
distribution.
|
||||
|
||||
</descrip>
|
120
contrib/libpam/doc/modules/pam_issue.sgml
Normal file
120
contrib/libpam/doc/modules/pam_issue.sgml
Normal file
@ -0,0 +1,120 @@
|
||||
<!--
|
||||
|
||||
Ben Collins <bcollins@debian.org>
|
||||
|
||||
-->
|
||||
|
||||
<sect1>Add issue file to user prompt
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
<tt/pam_issue/
|
||||
|
||||
<tag><bf>Author:</bf></tag>
|
||||
Ben Collins <bcollins@debian.org>
|
||||
|
||||
<tag><bf>Maintainer:</bf></tag>
|
||||
Author
|
||||
|
||||
<tag><bf>Management groups provided:</bf></tag>
|
||||
Authentication (pam_sm_authenticate)
|
||||
|
||||
<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>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
This module prepends the issue file (<em>/etc/issue</em> by default) when
|
||||
prompting for a username.
|
||||
|
||||
<sect2>Authentication component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/issue=issue-file-name/; <tt/noesc/;
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
This module allows you to prepend an issue file to the username prompt. It
|
||||
also by default parses escape codes in the issue file similar to some
|
||||
common getty's (using \x format).
|
||||
<p>
|
||||
Recognized escapes:
|
||||
<itemize>
|
||||
|
||||
<item><tt/d/
|
||||
- current date
|
||||
|
||||
<item><tt/s/
|
||||
- operating system name
|
||||
|
||||
<item><tt/l/
|
||||
- name of this tty
|
||||
|
||||
<item><tt/m/
|
||||
- architecture of this system (i686, sparc, powerpc, ...)
|
||||
|
||||
<item><tt/n/
|
||||
- hostname of this system
|
||||
|
||||
<item><tt/o/
|
||||
- domainname of this system
|
||||
|
||||
<item><tt/r/
|
||||
- release number of the operation system (eg. 2.2.12)
|
||||
|
||||
<item><tt/t/
|
||||
- current time
|
||||
|
||||
<item><tt/u/
|
||||
- number of users currently logged in
|
||||
|
||||
<item><tt/U/
|
||||
- same as <tt/u/, except it is suffixed with "user" or "users" (eg. "1
|
||||
user" or "10 users"
|
||||
|
||||
<item><tt/v/
|
||||
- version/build-date of the operating system (eg. "#3 Mon Aug 23 14:38:16
|
||||
EDT 1999" on Linux).
|
||||
|
||||
</itemize>
|
||||
|
||||
<p>
|
||||
The behavior of this module can be modified with one of the following
|
||||
flags:
|
||||
|
||||
<p>
|
||||
<itemize>
|
||||
|
||||
<item><tt/issue/
|
||||
- the file to output if not using the default
|
||||
|
||||
<item><tt/noesc/
|
||||
- turns off escape code parsing
|
||||
|
||||
</itemize>
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
login auth pam_issue.so issue=/etc/issue
|
||||
|
||||
</descrip>
|
||||
|
||||
<!--
|
||||
End of sgml insert for this module.
|
||||
-->
|
83
contrib/libpam/doc/modules/pam_mkhomedir.sgml
Normal file
83
contrib/libpam/doc/modules/pam_mkhomedir.sgml
Normal file
@ -0,0 +1,83 @@
|
||||
<!--
|
||||
|
||||
Ben Collins <bcollins@debian.org>
|
||||
|
||||
-->
|
||||
|
||||
<sect1>Create home directories on initial login
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
<tt/pam_mkhomedir/
|
||||
|
||||
<tag><bf>Author:</bf></tag>
|
||||
Jason Gunthorpe <jgg@ualberta.ca>
|
||||
|
||||
<tag><bf>Maintainer:</bf></tag>
|
||||
Ben Collins <bcollins@debian.org>
|
||||
|
||||
<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>
|
||||
|
||||
<tag><bf>Network aware:</bf></tag>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
Creates home directories on the fly for authenticated users.
|
||||
|
||||
<sect2>Session component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/debug/; <tt/skel=skeleton-dir/; <tt/umask=octal-umask/;
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
This module is useful for distributed systems where the user account is
|
||||
managed in a central database (such as NIS, NIS+, or LDAP) and accessed
|
||||
through miltiple systems. It frees the administrator from having to create
|
||||
a default home directory on each of the systems by creating it upon the
|
||||
first succesfully authenticated login of that user. The skeleton directory
|
||||
(usually /etc/skel/) is used to copy default files and also set's a umask
|
||||
for the creation.
|
||||
|
||||
<p>
|
||||
The behavior of this module can be modified with one of the following
|
||||
flags:
|
||||
|
||||
<p>
|
||||
<itemize>
|
||||
|
||||
<item><tt/skel/
|
||||
- The skeleton directory for default files to copy to the new home directory.
|
||||
|
||||
<item><tt/umask/
|
||||
- An octal for of the same format as you would pass to the shells umask command.
|
||||
|
||||
</itemize>
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
|
||||
|
||||
</descrip>
|
||||
|
||||
<!--
|
||||
End of sgml insert for this module.
|
||||
-->
|
77
contrib/libpam/doc/modules/pam_motd.sgml
Normal file
77
contrib/libpam/doc/modules/pam_motd.sgml
Normal file
@ -0,0 +1,77 @@
|
||||
<!--
|
||||
|
||||
Ben Collins <bcollins@debian.org>
|
||||
|
||||
-->
|
||||
|
||||
<sect1>Output the motd file
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
<tt/pam_motd/
|
||||
|
||||
<tag><bf>Author:</bf></tag>
|
||||
Ben Collins <bcollins@debian.org>
|
||||
|
||||
<tag><bf>Maintainer:</bf></tag>
|
||||
Author
|
||||
|
||||
<tag><bf>Management groups provided:</bf></tag>
|
||||
Session (open)
|
||||
|
||||
<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>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
This module outputs the motd file (<em>/etc/motd</em> by default) upon
|
||||
successful login.
|
||||
|
||||
<sect2>Session component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/debug/; <tt/motd=motd-file-name/;
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
This module allows you to have arbitrary motd's (message of the day)
|
||||
output after a succesful login. By default this file is <em>/etc/motd</em>,
|
||||
but is configurable to any file.
|
||||
|
||||
<p>
|
||||
The behavior of this module can be modified with one of the following
|
||||
flags:
|
||||
|
||||
<p>
|
||||
<itemize>
|
||||
|
||||
<item><tt/motd/
|
||||
- the file to output if not using the default.
|
||||
|
||||
</itemize>
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
login session pam_motd.so motd=/etc/motd
|
||||
|
||||
</descrip>
|
||||
|
||||
<!--
|
||||
End of sgml insert for this module.
|
||||
-->
|
191
contrib/libpam/doc/modules/pam_tally.sgml
Normal file
191
contrib/libpam/doc/modules/pam_tally.sgml
Normal file
@ -0,0 +1,191 @@
|
||||
<!--
|
||||
|
||||
$Id: pam_tally.sgml,v 1.1 2001/02/11 07:52:56 agmorgan Exp $
|
||||
|
||||
This template file was written by Andrew G. Morgan <morgan@kernel.org>
|
||||
adapted from text provided by Tim Baverstock.
|
||||
-->
|
||||
|
||||
<sect1>The login counter (tallying) module
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
pam_tally
|
||||
|
||||
<tag><bf>Author[s]:</bf></tag>
|
||||
Tim Baverstock
|
||||
|
||||
<tag><bf>Maintainer:</bf></tag>
|
||||
|
||||
<tag><bf>Management groups provided:</bf></tag>
|
||||
auth; 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>
|
||||
A faillog file (default location /var/log/faillog)
|
||||
|
||||
<tag><bf>Network aware:</bf></tag>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
This module maintains a count of attempted accesses, can reset count
|
||||
on success, can deny access if too many attempts fail.
|
||||
|
||||
<p>
|
||||
pam_tally comes in two parts: <tt>pam_tally.so</tt> and
|
||||
<tt>pam_tally</tt>. The former is the PAM module and the latter, a
|
||||
stand-alone program. <tt>pam_tally</tt> is an (optional) application
|
||||
which can be used to interrogate and manipulate the counter file. It
|
||||
can display users' counts, set individual counts, or clear all
|
||||
counts. Setting artificially high counts may be useful for blocking
|
||||
users without changing their passwords. For example, one might find it
|
||||
useful to clear all counts every midnight from a cron job.
|
||||
|
||||
<p>
|
||||
The counts file is organized as a binary-word array, indexed by
|
||||
uid. You can probably make sense of it with <tt>od</tt>, if you don't
|
||||
want to use the supplied appliction.
|
||||
|
||||
<p>
|
||||
Note, there are some outstanding issues with this module:
|
||||
<tt>pam_tally</tt> is very dependant on <tt>getpw*()</tt> - a database
|
||||
of usernames would be much more flexible; the `keep a count of current
|
||||
logins' bit has been <tt>#ifdef</tt>'d out and you can only reset the
|
||||
counter on successful authentication, for now.
|
||||
|
||||
<sect3>Generic options accepted by both components
|
||||
<p>
|
||||
<itemize>
|
||||
<item> <tt>onerr=</tt>(<tt>succeed</tt>|<tt>fail</tt>):
|
||||
if something weird happens, such as unable to open the file, how
|
||||
should the module react?
|
||||
<item> <tt>file=</tt><em>/where/to/keep/counts</em>:
|
||||
specify the file location for the counts.
|
||||
The default location is <tt>/var/log/faillog</tt>.
|
||||
</itemize>
|
||||
|
||||
<sect2>Authentication component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt>onerr=</tt>(<tt>succeed</tt>|<tt>fail</tt>);
|
||||
<tt>file=</tt>/where/to/keep/counts;
|
||||
<tt>no_magic_root</tt>
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
|
||||
<p>
|
||||
The authentication component of this module increments the attempted
|
||||
login counter.
|
||||
|
||||
<p>
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
<p>
|
||||
The module argument <tt>no_magic_root</tt> is used to indicate that if
|
||||
the module is invoked by a user with uid=0, then the counter is
|
||||
incremented. The sys-admin should use this for daemon-launched
|
||||
services, like <tt>telnet</tt>/<tt>rsh</tt>/<tt>login</tt>. For user
|
||||
launched services, like <tt>su</tt>, this argument should be omitted.
|
||||
|
||||
<p>
|
||||
By way of more explanation, when a process already running as root
|
||||
tries to access some service, the access is <em>magic</em>, and
|
||||
bypasses <tt>pam_tally</tt>'s checks: this is handy for <tt>su</tt>ing
|
||||
from root into an account otherwise blocked. However, for services
|
||||
like <tt>telnet</tt> or <tt>login</tt>, which always effectively run
|
||||
from the root account, root (ie everyone) shouldn't be granted this
|
||||
magic status, and the flag `no_magic_root' should be set in this
|
||||
situation, as noted in the summary above.
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Account component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt>onerr=</tt>(<tt>succeed</tt>|<tt>fail</tt>);
|
||||
<tt>file=</tt>/where/to/keep/counts;
|
||||
<tt>deny=</tt><em>n</em>;
|
||||
<tt>no_magic_root</tt>;
|
||||
<tt>even_deny_root_account</tt>;
|
||||
<tt>reset</tt>;
|
||||
<tt>no_reset</tt>;
|
||||
<tt>per_user</tt>;
|
||||
<tt>no_lock_time</tt>
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
|
||||
<p>
|
||||
The account component can deny access and/or reset the attempts
|
||||
counter. It also checks to make sure that the counts file is a plain
|
||||
file and not world writable.
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
<p>
|
||||
The <tt>deny=</tt><em>n</em> option is used to deny access if tally
|
||||
for this user exceeds <em>n</em>. The presence of
|
||||
<tt>deny=</tt><em>n</em> changes the default for
|
||||
<tt>reset</tt>/<tt>no_reset</tt> to <tt>reset</tt>, unless the user
|
||||
trying to gain access is root and the <tt>no_magic_root</tt> option
|
||||
has NOT been specified.
|
||||
|
||||
<p>
|
||||
The <tt>no_magic_root</tt> option ensures that access attempts by root
|
||||
DON'T ignore deny. Use this for daemon-based stuff, like
|
||||
<tt>telnet</tt>/<tt>rsh</tt>/<tt>login</tt>.
|
||||
|
||||
<p>
|
||||
The <tt>even_deny_root_account</tt> option is used to ensure that the
|
||||
root account can become unavailable. <bf>Note</bf> that magic root
|
||||
trying to gain root bypasses this, but normal users can be locked out.
|
||||
|
||||
<p>
|
||||
The <tt>reset</tt> option instructs the module to reset count to 0 on
|
||||
successful entry, even for magic root. The <tt>no_reset</tt> option is
|
||||
used to instruct the module to not reset the count on successful
|
||||
entry. This is the default unless <tt>deny</tt> exists and the user
|
||||
attempting access is NOT magic root.
|
||||
|
||||
<p>
|
||||
If <tt>/var/log/faillog</tt> contains a non-zero <tt>.fail_max</tt>
|
||||
field for this user then the <tt>per_user</tt> module argument will
|
||||
ensure that the module uses this value and not the global
|
||||
<tt>deny=</tt><em>n</em> parameter.
|
||||
|
||||
<p>
|
||||
The <tt>no_lock_time</tt> option is for ensuring that the module does
|
||||
not use the <tt>.fail_locktime</tt> field in /var/log/faillog for this
|
||||
user.
|
||||
|
||||
<p>
|
||||
Normally, failed attempts to access root will <bf>NOT</bf> cause the
|
||||
root account to become blocked, to prevent denial-of-service: if your
|
||||
users aren't given shell accounts and root may only login via
|
||||
<tt>su</tt> or at the machine console (not
|
||||
<tt>telnet</tt>/<tt>rsh</tt>, etc), this is safe. If you really want
|
||||
root to be blocked for some given service, use
|
||||
<tt>even_deny_root_account</tt>.
|
||||
|
||||
</descrip>
|
||||
|
||||
<!--
|
||||
End of sgml insert for this module.
|
||||
-->
|
288
contrib/libpam/doc/modules/pam_unix.sgml
Normal file
288
contrib/libpam/doc/modules/pam_unix.sgml
Normal file
@ -0,0 +1,288 @@
|
||||
<!--
|
||||
This file was written by Andrew G. Morgan <morgan@linux.kernel.org>
|
||||
|
||||
Converted from the pam_pwdb.sgml file for pam_unix by Ben Collins <bcollins@debian.org>
|
||||
-->
|
||||
|
||||
<sect1>The Unix Password module
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
pam_unix
|
||||
|
||||
<tag><bf>Author:</bf></tag>
|
||||
|
||||
<tag><bf>Maintainer:</bf></tag>
|
||||
|
||||
<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>
|
||||
|
||||
<tag><bf>Network aware:</bf></tag>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
This is the standard Unix authentication module. It uses standard calls
|
||||
from the system's libraries to retrieve and set account information as
|
||||
well as authentication. Usually this is obtained from the /etc/passwd
|
||||
and the /etc/shadow file as well if shadow is enabled.
|
||||
|
||||
<sect2>Account component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/debug/; <tt/audit/
|
||||
|
||||
<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)/). The <tt/audit/
|
||||
argument causes even more logging.
|
||||
|
||||
Based on the following <tt/shadow/ elements:
|
||||
<tt/expire/;
|
||||
<tt/last_change/;
|
||||
<tt/max_change/;
|
||||
<tt/min_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/GNU Libc/ info documents. 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_unix.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Authentication component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/debug/;
|
||||
<tt/audit/;
|
||||
<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. The <tt/audit/
|
||||
causes even more information to be logged.
|
||||
|
||||
<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>unix_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/nsswitch.conf</tt> file, the user
|
||||
databases specified there dictate the source of the authenticated
|
||||
user's record.
|
||||
<p>
|
||||
In its authentication mode, this module can be inserted as follows:
|
||||
<tscreen>
|
||||
<verb>
|
||||
#
|
||||
# Authenticate the user
|
||||
#
|
||||
login auth required pam_unix.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Password component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/debug/;
|
||||
<tt/audit/;
|
||||
<tt/nullok/;
|
||||
<tt/not_set_pass/;
|
||||
<tt/use_authtok/;
|
||||
<tt/try_first_pass/;
|
||||
<tt/use_first_pass/;
|
||||
<tt/md5/;
|
||||
<tt/bigcrypt/;
|
||||
<tt/shadow/;
|
||||
<tt/nis/;
|
||||
<tt/remember/
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
|
||||
This part of the <tt/pam_unix/ module performs the task of updating
|
||||
the user's password.
|
||||
|
||||
<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/ argument 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_unix/ 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)/. The <tt/audit/ argument causes
|
||||
even more information to be logged.
|
||||
|
||||
<p>
|
||||
With the <tt/nis/ argument, <tt/pam_unix/ will attempt to use NIS RPC
|
||||
for setting new passwords.
|
||||
|
||||
<p>
|
||||
The <tt/remember/ argument takes one value. This is the number of most
|
||||
recent passwords to save for each user. These are saved in
|
||||
<tt>/etc/security/opasswd</tt> in order to force password change history
|
||||
and keep the user from alternating between the same password too frequently.
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
Standard usage:
|
||||
<tscreen>
|
||||
<verb>
|
||||
#
|
||||
# Change the users password
|
||||
#
|
||||
passwd password required pam_unix.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
<p>
|
||||
An example of the stacking of this module with respect to the
|
||||
pluggable password checking module, <tt/pam_cracklib/:
|
||||
<tscreen>
|
||||
<verb>
|
||||
#
|
||||
# Change the users password
|
||||
#
|
||||
passwd password required pam_cracklib.so retry=3 minlen=6 difok=3
|
||||
passwd password required pam_unix.so use_authtok nullok md5
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
</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>
|
||||
#
|
||||
# session opening and closing
|
||||
#
|
||||
login session required pam_unix.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
</descrip>
|
||||
|
||||
<!--
|
||||
End of sgml insert for this module.
|
||||
-->
|
112
contrib/libpam/doc/modules/pam_userdb.sgml
Normal file
112
contrib/libpam/doc/modules/pam_userdb.sgml
Normal file
@ -0,0 +1,112 @@
|
||||
<!--
|
||||
This file was written by Cristian Gafton <gafton@redhat.com>
|
||||
-->
|
||||
|
||||
<sect1>The userdb module
|
||||
|
||||
<sect2>Synopsis
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Module Name:</bf></tag>
|
||||
<tt/pam_userdb/
|
||||
|
||||
<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 Berkeley DB.
|
||||
|
||||
<tag><bf>Network aware:</bf></tag>
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect2>Overview of module
|
||||
|
||||
<p>
|
||||
Look up users in a .db database and verify their password against
|
||||
what is contained in that database.
|
||||
|
||||
<sect2>Authentication component
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
|
||||
<tag><bf>Recognized arguments:</bf></tag>
|
||||
<tt/debug/;
|
||||
<tt/icase/;
|
||||
<tt/dump/;
|
||||
<tt/db=XXXX/;
|
||||
|
||||
<tag><bf>Description:</bf></tag>
|
||||
|
||||
This module is used to verify a username/password pair against values stored in
|
||||
a Berkeley DB database. The database is indexed by the username, and the data
|
||||
fields corresponding to the username keys are the passwords, in unencrypted form,
|
||||
so caution must be exercised over the access rights to the DB database itself..
|
||||
|
||||
The module will read the password from the user using the conversation mechanism. If
|
||||
you are using this module on top of another authetication module (like <tt/pam_pwdb/;)
|
||||
then you should tell that module to read the entered password from the PAM_AUTHTOK field, which is set by this module.
|
||||
|
||||
<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.d/<service></tt> file.
|
||||
<itemize>
|
||||
<item>
|
||||
<tt/debug/ -
|
||||
Supply more debugging information to <tt/syslog(3)/.
|
||||
|
||||
<item>
|
||||
<tt/icase/ -
|
||||
Perform the password comparisons case insensitive.
|
||||
|
||||
<item>
|
||||
<tt/dump/ -
|
||||
dump all the entries in the database to the log (eek,
|
||||
don't do this by default!)
|
||||
|
||||
<item>
|
||||
<tt/db=XXXX/ -
|
||||
use the database found on pathname XXXX. Note that Berkeley DB usually adds the
|
||||
needed filename extension for you, so you should use something like <tt>/etc/foodata</tt>
|
||||
instead of <tt>/etc/foodata.db</tt>.
|
||||
|
||||
</itemize>
|
||||
|
||||
<tag><bf>Examples/suggested usage:</bf></tag>
|
||||
|
||||
This is a normal ftp configuration file (usually placed as <tt>/etc/pam.d/ftp</tt>
|
||||
on most systems) that will accept for login users whose username/password pairs are
|
||||
provided in the <tt>/tmp/dbtest.db</tt> file:
|
||||
|
||||
<tscreen>
|
||||
<verb>
|
||||
#%PAM-1.0
|
||||
auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
|
||||
auth sufficient pam_userdb.so icase db=/tmp/dbtest
|
||||
auth required pam_pwdb.so shadow nullok try_first_pass
|
||||
auth required pam_shells.so
|
||||
account required pam_pwdb.so
|
||||
session required pam_pwdb.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
</descrip>
|
||||
|
||||
<!--
|
||||
End of sgml insert for this module.
|
||||
-->
|
@ -2,9 +2,9 @@
|
||||
|
||||
<!--
|
||||
|
||||
$Id: pam_appl.sgml,v 1.16 1997/04/05 06:49:14 morgan Exp morgan $
|
||||
$Id: pam_appl.sgml,v 1.5 2001/03/19 01:46:41 agmorgan Exp $
|
||||
|
||||
Copyright (C) Andrew G. Morgan 1996, 1997. All rights reserved.
|
||||
Copyright (C) Andrew G. Morgan 1996-2001. All rights reserved.
|
||||
|
||||
Redistribution and use in source (sgml) and binary (derived) forms,
|
||||
with or without modification, are permitted provided that the
|
||||
@ -45,8 +45,8 @@ 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
|
||||
<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt>
|
||||
<date>DRAFT v0.75 2001/03/18
|
||||
<abstract>
|
||||
This manual documents what an application developer needs to know
|
||||
about the <bf>Linux-PAM</bf> library. It describes how an application
|
||||
@ -71,7 +71,7 @@ information:
|
||||
<verb>
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
cc -o application .... -lpam
|
||||
cc -o application .... -lpam -ldl
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -85,7 +85,7 @@ specific to the Linux-PAM distribution):
|
||||
...
|
||||
#include <security/pam_misc.h>
|
||||
|
||||
cc -o application .... -lpam -lpam_misc
|
||||
cc -o application .... -lpam -lpam_misc -ldl
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -130,7 +130,7 @@ 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
|
||||
services are provided in a manner that is <bf>transparent</bf> to
|
||||
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.
|
||||
@ -179,7 +179,7 @@ provided in a later section.
|
||||
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
|
||||
understand. In the case of <tt>ftpd</tt>, this might 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
|
||||
@ -218,9 +218,9 @@ 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.
|
||||
library before the PAM session is opened. 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>
|
||||
|
||||
@ -233,7 +233,7 @@ 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
|
||||
Below we document those functions in the <bf/Linux-PAM/ library that
|
||||
may be called from an application.
|
||||
|
||||
<sect2>Initialization of Linux-PAM
|
||||
@ -288,12 +288,16 @@ 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">).
|
||||
PAM_SUCCESS, but in the event of an unsuccessful application for
|
||||
service the appropriate <bf/Linux-PAM/ error-return value should be
|
||||
used here. Note, <tt/pam_end()/ unconditionally shuts down the
|
||||
authentication stack associated with the <tt/pamh/ handle. The value
|
||||
taken by <tt/pam_status/ is used as an argument to the module specific
|
||||
callback functions, <tt/cleanup()/ (see the <bf/Linux-PAM/ <htmlurl
|
||||
url="pam_modules.html" name="Module Developers' Guide">). In this way,
|
||||
the module can be given notification of the pass/fail nature of the
|
||||
tear-down process, and perform any last minute tasks that are
|
||||
appropriate to the module before it is unlinked.
|
||||
|
||||
<sect2>Setting PAM items
|
||||
<label id="pam-set-item-section">
|
||||
@ -316,33 +320,41 @@ extern int pam_set_item(pam_handle_t *pamh, int item_type,
|
||||
<tag><tt/PAM_USER/</tag>
|
||||
The 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: ''.
|
||||
|
||||
<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_RUSER/</tag>
|
||||
The requesting user's username
|
||||
|
||||
<tag><tt/PAM_RHOST/</tag>
|
||||
The remote host name
|
||||
The requesting hostname (the hostname of the machine from which
|
||||
the <tt/PAM_RUSER/ is requesting service)
|
||||
|
||||
<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: ''.
|
||||
<tag><tt/PAM_FAIL_DELAY/</tag> A function pointer to redirect
|
||||
centrally managed failure delays (see section <ref
|
||||
id="the-failure-delay-function" name="below">).
|
||||
|
||||
</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">).
|
||||
For all <tt/item_type/s, other than <tt/PAM_CONV/ and
|
||||
<tt/PAM_FAIL_DELAY/, <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">). In the case of
|
||||
<tt/PAM_FAIL_DELAY/, <tt/item/ is a function pointer: <tt/void
|
||||
(*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr)/ (see
|
||||
section <ref id="the-failure-delay-function" name="below">).
|
||||
|
||||
<p>
|
||||
A successful call to this function returns <tt/PAM_SUCCESS/. However,
|
||||
@ -350,13 +362,17 @@ the application should expect one of the following errors:
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
<tag><tt/PAM_SYSTEM_ERR/</tag>
|
||||
The <tt/pam_handle_t/ passed as a first argument to this
|
||||
function was invalid.
|
||||
<tag><tt/PAM_PERM_DENIED/</tag>
|
||||
An attempt was made to replace the conversation structure with
|
||||
a <tt/NULL/ value.
|
||||
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.
|
||||
The application attempted to set an undefined or inaccessible
|
||||
item.
|
||||
</descrip>
|
||||
|
||||
<sect2>Getting PAM items
|
||||
@ -375,9 +391,31 @@ 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.
|
||||
over-written!
|
||||
|
||||
<p>
|
||||
A successful call is signaled by a return value of <tt/PAM_SUCCESS/.
|
||||
However, the application should expect one of the following errors:
|
||||
|
||||
<p>
|
||||
<descrip>
|
||||
<tag><tt/PAM_SYSTEM_ERR/</tag>
|
||||
The <tt/pam_handle_t/ passed as a first argument to this
|
||||
function was invalid.
|
||||
<tag><tt/PAM_PERM_DENIED/</tag>
|
||||
The value of <tt/item/ was <tt/NULL/.
|
||||
<tag><tt/PAM_BAD_ITEM/</tag>
|
||||
The application attempted to set an undefined or inaccessible
|
||||
item.
|
||||
</descrip>
|
||||
|
||||
<p>
|
||||
Note, in the case of an error, the contents of <tt/item/ is not
|
||||
modified - that is, it retains its pre-call value. One should take
|
||||
care to initialize this value prior to calling
|
||||
<tt/pam_get_item()/. Since, if its value - despite the
|
||||
<tt/pam_get_item()/ function failing - is to be used the consequences
|
||||
are undefined.
|
||||
|
||||
<sect2>Understanding errors
|
||||
<label id="pam-strerror-section">
|
||||
@ -395,6 +433,7 @@ error associated with the argument <tt/errnum/. If the error is not
|
||||
recognized ``<tt/Unknown Linux-PAM error/'' is returned.
|
||||
|
||||
<sect2>Planning for delays
|
||||
<label id="the-failure-delay-function">
|
||||
|
||||
<p>
|
||||
<tscreen>
|
||||
@ -410,9 +449,9 @@ 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
|
||||
#ifdef PAM_FAIL_DELAY
|
||||
....
|
||||
#endif /* HAVE_PAM_FAIL_DELAY */
|
||||
#endif /* PAM_FAIL_DELAY */
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -420,14 +459,14 @@ application programmer should check if it is available with,
|
||||
<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.
|
||||
<tt/pam_chauthtok()/. These functions call each of the <em/stacked/
|
||||
authentication modules listed in the relevant <bf/Linux-PAM/
|
||||
configuration 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
|
||||
@ -441,6 +480,34 @@ randomly distributed (by up to 25%) about this longest value.
|
||||
Independent of success, the delay time is reset to its zero default
|
||||
value when <bf/Linux-PAM/ returns control to the application.
|
||||
|
||||
<p>
|
||||
For applications written with a single thread that are event driven in
|
||||
nature, <tt/libpam/ generating this delay may be undesirable. Instead,
|
||||
the application may want to register the delay in some other way. For
|
||||
example, in a single threaded server that serves multiple
|
||||
authentication requests from a single event loop, the application
|
||||
might want to simply mark a given connection as blocked until an
|
||||
application timer expires. For this reason, <bf/Linux-PAM/ supplies
|
||||
the <tt/PAM_FAIL_DELAY/ item. It can be queried and set with
|
||||
<tt/pam_get_item()/ and <tt/pam_set_item()/ respectively. The value
|
||||
used to set it should be a function pointer of the following
|
||||
prototype:
|
||||
|
||||
<tscreen>
|
||||
<verb>
|
||||
void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr);
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
The arguments being the <tt/retval/ return code of the module stack,
|
||||
the <tt/usec_delay/ micro-second delay that libpam is requesting and
|
||||
the <tt/appdata_ptr/ that the application has associated with the
|
||||
current <tt/pamh/ (<tt/pam_handle_t/). This last value was set by the
|
||||
application when it called <tt/pam_start/ or explicitly with
|
||||
<tt/pam_set_item(... , PAM_CONV, ...)/. Note, if <tt/PAM_FAIL_DELAY/
|
||||
is unset (or set to <tt/NULL/), then <tt/libpam/ will perform any
|
||||
delay.
|
||||
|
||||
<sect2>Authenticating the user
|
||||
|
||||
<p>
|
||||
@ -502,7 +569,7 @@ extern int pam_setcred(pam_handle_t *pamh, int flags);
|
||||
<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
|
||||
after the account management function has been called but before a
|
||||
session has been opened for the user.
|
||||
|
||||
<p>
|
||||
@ -583,7 +650,7 @@ 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.
|
||||
The user is no longer permitted to access the system.
|
||||
<tag><tt/PAM_AUTH_ERR/</tag>
|
||||
There was an authentication error.
|
||||
|
||||
@ -667,7 +734,7 @@ extern int pam_open_session(pam_handle_t *pamh, int flags);
|
||||
|
||||
<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
|
||||
begun. It is used to inform the modules 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
|
||||
@ -694,14 +761,15 @@ extern int pam_close_session(pam_handle_t *pamh, int flags);
|
||||
|
||||
<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
|
||||
ended. It is used to inform the modules 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/.
|
||||
This function simply calls each of the corresponding functions of the
|
||||
loaded modules in the same order that they were invoked with
|
||||
<tt/pam_open_session()/. 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
|
||||
@ -717,14 +785,6 @@ 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
|
||||
@ -746,7 +806,7 @@ setting.
|
||||
<tag>``<tt/NAME/''</tag>
|
||||
|
||||
Without an `<tt/=/' the <tt/pam_putenv()/ function will delete the
|
||||
correspoding variable from the <bf/Linux-PAM/ environment.
|
||||
corresponding variable from the <bf/Linux-PAM/ environment.
|
||||
|
||||
</descrip>
|
||||
|
||||
@ -927,7 +987,7 @@ 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/
|
||||
Sunsoft). The number of responses 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
|
||||
@ -968,6 +1028,13 @@ generated.
|
||||
|
||||
<sect>Security issues of <bf>Linux-PAM</bf>
|
||||
|
||||
<p>
|
||||
PAM, from the perspective of an application, is a convenient API for
|
||||
authenticating users. PAM modules generally have no increased
|
||||
privilege over that possessed by the application that is making use of
|
||||
it. For this reason, the application must take ultimate responsibility
|
||||
for protecting the environment in which PAM operates.
|
||||
|
||||
<p>
|
||||
A poorly (or maliciously) written application can defeat any
|
||||
<bf/Linux-PAM/ module's authentication mechanisms by simply ignoring
|
||||
@ -994,17 +1061,17 @@ 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
|
||||
Two important 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
|
||||
in the <bf/Linux-PAM/ configuration 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
|
||||
application on a system under a different name and this should not be
|
||||
permitted to cause a security breach.
|
||||
|
||||
<p>
|
||||
@ -1019,14 +1086,14 @@ ln -s /target/application ./preferred_name
|
||||
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.
|
||||
By studying the <bf/Linux-PAM/ configuration file(s), 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
|
||||
@ -1051,16 +1118,40 @@ 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)/.
|
||||
security. One convention that is actively used by some modules is
|
||||
that 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(3)/.
|
||||
|
||||
<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.
|
||||
For network-serving databases and other applications that provide
|
||||
their own security model (independent of the OS kernel) the above
|
||||
scheme is insufficient to identify the requesting user.
|
||||
|
||||
<p>
|
||||
A more portable solution to storing the identity of the requesting
|
||||
user is to use the <tt/PAM_RUSER/ <tt/pam_get_item(3)/. The
|
||||
application should supply this value before attempting to authenticate
|
||||
the user with <tt/pam_authenticate()/. How well this name can be
|
||||
trusted will ultimately be at the discretion of the local
|
||||
administrator (who configures PAM for your application) and a selected
|
||||
module may attempt to override the value where it can obtain more
|
||||
reliable data. If an application is unable to determine the identity
|
||||
of the requesting entity/user, it should not call <tt/pam_set_item(3)/
|
||||
to set <tt/PAM_RUSER/.
|
||||
|
||||
<p>
|
||||
In addition to the <tt/PAM_RUSER/ item, the application should supply
|
||||
the <tt/PAM_RHOST/ (<em/requesting host/) item. As a general rule, the
|
||||
following convention for its value can be assumed: <tt/<unset>/
|
||||
= unknown; <tt/localhost/ = invoked directly from the local system;
|
||||
<em/other.place.xyz/ = some component of the user's connection
|
||||
originates from this remote/requesting host. At present, PAM has no
|
||||
established convention for indicating whether the application supports
|
||||
a trusted path to communication from this host.
|
||||
|
||||
<sect1>Sufficient resources
|
||||
|
||||
@ -1072,6 +1163,13 @@ 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.
|
||||
|
||||
<p>
|
||||
This is also true of conversation prompts. The application should not
|
||||
accept prompts of arbitrary length with out checking for resource
|
||||
allocation failure and dealing with such extreme conditions gracefully
|
||||
and in a mannor that preserves the PAM API. Such tolerance may be
|
||||
especially important when attempting to track a malicious adversary.
|
||||
|
||||
<sect>A library of miscellaneous helper functions
|
||||
<label id="libpam-misc-section">
|
||||
|
||||
@ -1242,7 +1340,7 @@ 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
|
||||
idea how the attached 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.
|
||||
@ -1256,10 +1354,10 @@ 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
|
||||
protocol in mind and no-one ever considered attaching 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"
|
||||
being be attached 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
|
||||
@ -1280,7 +1378,7 @@ 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
|
||||
authentication "procedure", the conversation function should only
|
||||
deal with reformatting user prompts and extracting responses from raw
|
||||
input.
|
||||
|
||||
@ -1459,30 +1557,41 @@ This document was written by Andrew G. Morgan
|
||||
<!-- 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 $
|
||||
$Id: pam_appl.sgml,v 1.5 2001/03/19 01:46:41 agmorgan Exp $
|
||||
-->
|
||||
Chris Adams,
|
||||
Peter Allgeyer,
|
||||
Tim Baverstock,
|
||||
Tim Berger,
|
||||
Craig S. Bell,
|
||||
Derrick J. Brashear,
|
||||
Ben Buxton,
|
||||
Seth Chaiklin,
|
||||
Oliver Crow,
|
||||
Chris Dent,
|
||||
Marc Ewing,
|
||||
Cristian Gafton,
|
||||
Emmanuel Galanos,
|
||||
Brad M. Garcia,
|
||||
Eric Hester,
|
||||
Roger Hu,
|
||||
Eric Jacksch,
|
||||
Michael K. Johnson,
|
||||
David Kinchlea,
|
||||
Olaf Kirch,
|
||||
Marcin Korzonek,
|
||||
Stephen Langasek,
|
||||
Nicolai Langfeldt,
|
||||
Elliot Lee,
|
||||
Luke Kenneth Casson Leighton,
|
||||
Al Longyear,
|
||||
Ingo Luetkebohle,
|
||||
Marek Michalkiewicz,
|
||||
Robert Milkowski,
|
||||
Aleph One,
|
||||
Martin Pool,
|
||||
Sean Reifschneider,
|
||||
Jan Rekorajski,
|
||||
Erik Troan,
|
||||
Theodore Ts'o,
|
||||
Jeff Uphoff,
|
||||
@ -1495,7 +1604,6 @@ 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
|
||||
@ -1512,7 +1620,7 @@ 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.
|
||||
Copyright (c) Andrew G. Morgan 1996-9. All rights reserved.
|
||||
<newline>
|
||||
Email: <tt><morgan@transmeta.com></tt>
|
||||
|
||||
@ -1562,6 +1670,6 @@ 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>
|
||||
<tt>$Id: pam_appl.sgml,v 1.5 2001/03/19 01:46:41 agmorgan Exp $</tt>
|
||||
|
||||
</article>
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
<!--
|
||||
|
||||
$Id: pam_modules.sgml,v 1.19 1997/04/05 06:49:14 morgan Exp morgan $
|
||||
$Id: pam_modules.sgml,v 1.6 2001/02/22 04:58:51 agmorgan Exp $
|
||||
|
||||
Copyright (c) Andrew G. Morgan 1996, 1997. All rights reserved.
|
||||
Copyright (c) Andrew G. Morgan 1996-2001. All rights reserved.
|
||||
|
||||
** some sections, in this document, were contributed by other
|
||||
** authors. They carry individual copyrights.
|
||||
@ -48,8 +48,8 @@ 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
|
||||
<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt>
|
||||
<date>DRAFT v0.75 2001/02/21
|
||||
<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
|
||||
@ -68,7 +68,7 @@ programmer.
|
||||
#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
|
||||
ld -x --shared -o pam_module-name.so pam_module-name.o
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -122,13 +122,11 @@ Setting data
|
||||
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)
|
||||
);
|
||||
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>
|
||||
|
||||
@ -159,16 +157,15 @@ 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
|
||||
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()/.
|
||||
<tt/pam_set_data()/) this mask 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
|
||||
@ -185,10 +182,9 @@ Getting data
|
||||
Synopsis:
|
||||
<tscreen>
|
||||
<verb>
|
||||
extern int pam_get_data(const pam_handle_t *pamh
|
||||
, const char *module_data_name
|
||||
, const void **data
|
||||
);
|
||||
extern int pam_get_data(const pam_handle_t *pamh,
|
||||
const char *module_data_name,
|
||||
const void **data);
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -211,10 +207,9 @@ Setting items
|
||||
Synopsis:
|
||||
<tscreen>
|
||||
<verb>
|
||||
extern int pam_set_item(pam_handle_t *pamh
|
||||
, int item_type
|
||||
, const void *item
|
||||
);
|
||||
extern int pam_set_item(pam_handle_t *pamh,
|
||||
int item_type,
|
||||
const void *item);
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -231,8 +226,8 @@ following two <tt/item_type/s:
|
||||
<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
|
||||
The authentication token (often a 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
|
||||
@ -262,10 +257,9 @@ Getting items
|
||||
Synopsis:
|
||||
<tscreen>
|
||||
<verb>
|
||||
extern int pam_get_item(const 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);
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -346,10 +340,9 @@ The return values for this function are listed in the
|
||||
Synopsis:
|
||||
<tscreen>
|
||||
<verb>
|
||||
extern int pam_get_user(pam_handle_t *pamh
|
||||
, const char **user
|
||||
, const char *prompt
|
||||
);
|
||||
extern int pam_get_user(pam_handle_t *pamh,
|
||||
const char **user,
|
||||
const char *prompt);
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
@ -386,6 +379,27 @@ 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.
|
||||
|
||||
<p>
|
||||
The return value of this function is one of the following:
|
||||
<itemize>
|
||||
|
||||
<item> <tt/PAM_SUCCESS/ - username obtained.
|
||||
|
||||
<item> <tt/PAM_CONV_AGAIN/ - converstation did not complete and the
|
||||
caller is required to return control to the application, until such
|
||||
time as the application has completed the conversation process. A
|
||||
module calling <tt/pam_get_user()/ that obtains this return code,
|
||||
should return <tt/PAM_INCOMPLETE/ and be prepared (when invoked the
|
||||
next time) to recall <tt/pam_get_user()/ to fill in the user's name,
|
||||
and then pick up where it left off as if nothing had happened. This
|
||||
procedure is needed to support an event-driven application programming
|
||||
model.
|
||||
|
||||
<item> <tt/PAM_CONV_ERR/ - the conversation method supplied by the
|
||||
application failed to obtain the username.
|
||||
|
||||
</itemize>
|
||||
|
||||
<sect2>Setting a Linux-PAM environment variable
|
||||
|
||||
<p>
|
||||
@ -397,7 +411,7 @@ extern int pam_putenv(pam_handle_t *pamh, const char *name_value);
|
||||
</tscreen>
|
||||
|
||||
<p>
|
||||
<bf/Linux-PAM/ (0.54+) comes equipped with a series of functions for
|
||||
<bf/Linux-PAM/ 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
|
||||
@ -515,23 +529,23 @@ 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
|
||||
#ifdef PAM_FAIL_DELAY
|
||||
....
|
||||
#endif /* HAVE_PAM_FAIL_DELAY */
|
||||
#endif /* 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.
|
||||
<tt/pam_chauthtok()/. These functions call each of the <em/stacked/
|
||||
authentication modules listed in the <bf/Linux-PAM/ configuration
|
||||
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/ (cf. covert channel) attacks.
|
||||
|
||||
<p>
|
||||
The <tt/pam_fail_delay()/ function provides the mechanism by which an
|
||||
@ -677,8 +691,9 @@ 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.
|
||||
function is used to make such information available to the
|
||||
application. It should only be called <em/after/ the user has been
|
||||
authenticated but before a session has been established.
|
||||
|
||||
<p>
|
||||
Permitted flags, one of which, may be logically OR'd with
|
||||
@ -695,6 +710,28 @@ Permitted flags, one of which, may be logically OR'd with
|
||||
Extend the lifetime of the user credentials.
|
||||
</descrip>
|
||||
|
||||
<p>
|
||||
Prior to <bf/Linux-PAM-0.75/, and due to a deficiency with the way the
|
||||
<tt/auth/ stack was handled in the case of the setcred stack being
|
||||
processed, the module was required to attempt to return the same error
|
||||
code as <tt/pam_sm_authenticate/ did. This was necessary to preserve
|
||||
the logic followed by libpam as it executes the stack of
|
||||
<em/authentication/ modules, when the application called either
|
||||
<tt/pam_authenticate()/ or <tt/pam_setcred()/. Failing to do this,
|
||||
led to confusion on the part of the System Administrator.
|
||||
|
||||
<p>
|
||||
For <bf/Linux-PAM-0.75/ and later, libpam handles the credential stack
|
||||
much more sanely. The way the <tt/auth/ stack is navigated in order to
|
||||
evaluate the <tt/pam_setcred()/ function call, independent of the
|
||||
<tt/pam_sm_setcred()/ return codes, is exactly the same way that it
|
||||
was navigated when evaluating the <tt/pam_authenticate()/ library
|
||||
call. Typically, if a stack entry was ignored in evaluating
|
||||
<tt/pam_authenticate()/, it will be ignored when libpam evaluates the
|
||||
<tt/pam_setcred()/ function call. Otherwise, the return codes from
|
||||
each module specific <tt/pam_sm_setcred()/ call are treated as
|
||||
<tt/required/.
|
||||
|
||||
<p>
|
||||
Besides <tt/PAM_SUCCESS/, the module may return one of the following
|
||||
errors:
|
||||
@ -710,6 +747,11 @@ errors:
|
||||
This module was unable to set the credentials of the user.
|
||||
</descrip>
|
||||
|
||||
<p>
|
||||
these, non-<tt/PAM_SUCCESS/, return values will typically lead to the
|
||||
credential stack <em/failing/. The first such error will dominate in
|
||||
the return value of <tt/pam_setcred()/.
|
||||
|
||||
</itemize>
|
||||
|
||||
<sect1> Account management
|
||||
@ -953,6 +995,20 @@ 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/. .
|
||||
|
||||
<tag><tt/expose_account/</tag>
|
||||
|
||||
<p>
|
||||
In general the leakage of some information about user accounts is not
|
||||
a secure policy for modules to adopt. Sometimes information such as
|
||||
users names or home directories, or preferred shell, can be used to
|
||||
attack a user's account. In some circumstances, however, this sort of
|
||||
information is not deemed a threat: displaying a user's full name when
|
||||
asking them for a password in a secured environment could also be
|
||||
called being 'friendly'. The <tt/expose_account/ argument is a
|
||||
standard module argument to encourage a module to be less discrete
|
||||
about account information as it is deemed appropriate by the local
|
||||
administrator.
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect>Programming notes
|
||||
@ -1238,13 +1294,22 @@ endif
|
||||
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>
|
||||
At some point, we may include a fully commented example of a module in
|
||||
this document. For now, we point the reader to these two locations in
|
||||
the public CVS repository:
|
||||
<itemize>
|
||||
<item> A module that always succeeds: <tt><htmlurl
|
||||
url="http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/Linux-PAM/modules/pam_permit/?cvsroot=pam"
|
||||
name="http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/Linux-PAM/modules/pam_permit/?cvsroot=pam"
|
||||
></tt>
|
||||
<item> A module that always fails: <tt><htmlurl
|
||||
url="http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/Linux-PAM/modules/pam_deny/?cvsroot=pam"
|
||||
name="http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/Linux-PAM/modules/pam_deny/?cvsroot=pam"
|
||||
></tt>
|
||||
</itemize>
|
||||
|
||||
<sect>Files
|
||||
|
||||
@ -1314,33 +1379,41 @@ This document was written by Andrew G. Morgan
|
||||
<!-- insert credits here -->
|
||||
<!--
|
||||
an sgml list of people to credit for their contributions to Linux-PAM
|
||||
$Id: pam_modules.sgml,v 1.6 2001/02/22 04:58:51 agmorgan Exp $
|
||||
-->
|
||||
<!--
|
||||
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 $
|
||||
-->
|
||||
Chris Adams,
|
||||
Peter Allgeyer,
|
||||
Tim Baverstock,
|
||||
Tim Berger,
|
||||
Craig S. Bell,
|
||||
Derrick J. Brashear,
|
||||
Ben Buxton,
|
||||
Seth Chaiklin,
|
||||
Oliver Crow,
|
||||
Chris Dent,
|
||||
Marc Ewing,
|
||||
Cristian Gafton,
|
||||
Emmanuel Galanos,
|
||||
Brad M. Garcia,
|
||||
Eric Hester,
|
||||
Roger Hu,
|
||||
Eric Jacksch,
|
||||
Michael K. Johnson,
|
||||
David Kinchlea,
|
||||
Olaf Kirch,
|
||||
Marcin Korzonek,
|
||||
Stephen Langasek,
|
||||
Nicolai Langfeldt,
|
||||
Elliot Lee,
|
||||
Luke Kenneth Casson Leighton,
|
||||
Al Longyear,
|
||||
Ingo Luetkebohle,
|
||||
Marek Michalkiewicz,
|
||||
Robert Milkowski,
|
||||
Aleph One,
|
||||
Martin Pool,
|
||||
Sean Reifschneider,
|
||||
Jan Rekorajski,
|
||||
Erik Troan,
|
||||
Theodore Ts'o,
|
||||
Jeff Uphoff,
|
||||
@ -1420,6 +1493,6 @@ 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>
|
||||
<tt>$Id: pam_modules.sgml,v 1.6 2001/02/22 04:58:51 agmorgan Exp $</tt>
|
||||
|
||||
</article>
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
<!--
|
||||
|
||||
$Id: pam_source.sgml,v 1.5 1997/04/05 06:49:14 morgan Exp morgan $
|
||||
$Id: pam_source.sgml,v 1.5 2001/03/19 01:46:41 agmorgan Exp $
|
||||
|
||||
Copyright (c) Andrew G. Morgan 1996,1997. All rights reserved.
|
||||
Copyright (c) Andrew G. Morgan 1996-2001. All rights reserved.
|
||||
|
||||
Redistribution and use in source (sgml) and binary (derived) forms,
|
||||
with or without modification, are permitted provided that the
|
||||
@ -45,8 +45,8 @@ 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
|
||||
<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt>
|
||||
<date>DRAFT v0.75 2001/03/18
|
||||
<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
|
||||
@ -140,10 +140,10 @@ 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/
|
||||
Traditionally, 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.
|
||||
it agrees with that located on the system; hence verifying that
|
||||
as 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>
|
||||
@ -215,12 +215,122 @@ 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
|
||||
the order they appear in the configuration 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.
|
||||
|
||||
<sect1>Getting started
|
||||
|
||||
<p>
|
||||
The following text was contributed by Seth Chaiklin:
|
||||
<tscreen>
|
||||
<verb>
|
||||
To this point, we have described how PAM should work in an
|
||||
ideal world, in which all applications are coded properly.
|
||||
However, at the present time (October 1998), this is far
|
||||
from the case. Therefore, here are some practical considerations
|
||||
in trying to use PAM in your system.
|
||||
|
||||
Why bother, is it really worth all the trouble?
|
||||
|
||||
If you running Linux as a single user system, or in an
|
||||
environment where all the users are trusted, then there
|
||||
is no real advantage for using PAM.
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
<p>
|
||||
<BF>Ed:</BF> there is actually an advantage since you can <em/dummy
|
||||
down/ the authentication to the point where you don't have
|
||||
any... Almost like Win95.
|
||||
<p>
|
||||
In a networked environment, it is clear that you need to think a
|
||||
little more about how users etc., are authenticated:]
|
||||
|
||||
<p>
|
||||
<tscreen>
|
||||
<verb>
|
||||
If you are running Linux as a server, where several different
|
||||
services are being provided (e.g., WWW with areas restricted by
|
||||
password control, PPP), then there can be some real and interesting
|
||||
value for PAM. In particular, through the use of modules, PAM can
|
||||
enable a program to search through several different password
|
||||
databases, even if that program is not explicitly coded for
|
||||
that particular database. Here are some examples of the possibilities
|
||||
that this enables.
|
||||
|
||||
o Apache has a module that provides PAM services. Now
|
||||
authentication
|
||||
to use particular directories can be conducted by PAM, which
|
||||
means that the range of modules that are available to PAM can
|
||||
be used, including RADIUS, NIS, NCP (which means that Novell
|
||||
password databases can be used).
|
||||
|
||||
o pppd has a PAMified version (available from RedHat) Now it is
|
||||
possible to use a series of databases to authenticate ppp users.
|
||||
In addition to the normal Linux-based password databases (such
|
||||
as /etc/passwd and /etc/shadow), you can use PAM modules to
|
||||
authenticate against Novell password databases or NT-based
|
||||
password databases.
|
||||
|
||||
o The preceding two examples can be combined. Imagaine that the
|
||||
persons in your office/department are already registered with a
|
||||
username and password in a Novell or NT LAN. If you wanted to
|
||||
use this database on your Linux server (for PPP access, for
|
||||
web access, or even for normal shell access), you can use PAM
|
||||
to authenticate against this existing database, rather than
|
||||
maintain a separate database on both Linux and the LAN server.
|
||||
|
||||
|
||||
Can I use PAM for any program that requires authentication?
|
||||
|
||||
Yes and no. Yes, if you have access to the source code, and can
|
||||
add the appropriate PAM functions. No, if you do not have access
|
||||
to the source code, and the binary does not have the PAM functions
|
||||
included.
|
||||
|
||||
In other words, if a program is going to use PAM, then it has to
|
||||
have PAM functions explicitly coded into the program. If they
|
||||
are not, then it is not possible to use PAM.
|
||||
|
||||
How can I tell whether a program has PAM coded into it or not?
|
||||
|
||||
A quick-and-dirty (but not always reliable) method is to ldd
|
||||
<programname>
|
||||
If libpam and libpam_misc are not among the libraries that the program
|
||||
uses, then it is not going to work with PAM. However, it is possible
|
||||
that the libraries are included, but there are still problems, because
|
||||
the PAM coding in the program does not work as it should. So a
|
||||
more reliable method is to make the follow tests.
|
||||
|
||||
In the /etc/pam.d directory, one needs to make a configuration file
|
||||
for the program that one wants to run. The exact name of the
|
||||
configuration
|
||||
file is hard-coded into the program. Usually, it is the same name as
|
||||
the
|
||||
program, but not always. For sake of illustration, let's assume that
|
||||
the program is named "pamprog" and the name of the configuration file
|
||||
is /etc/pam.d/pamprog.
|
||||
|
||||
In the /etc/pam.d/pamprog but the following two lines:
|
||||
|
||||
auth required pam_permit.so
|
||||
auth required pam_warn.so
|
||||
|
||||
|
||||
Now try to use pamprog. The first line in the configuration file
|
||||
says that all users are permitted. The second line will write a
|
||||
warning to your syslog file (or whether you syslog is writing
|
||||
|
||||
messages). If this test succeeds, then you know that you have
|
||||
a program that can understand pam, and you can start the more
|
||||
interesting work of deciding how to stack modules in your
|
||||
/etc/pam.d/pamprog file.
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
<sect>The Linux-PAM configuration file
|
||||
<label id="configuration">
|
||||
|
||||
@ -363,9 +473,13 @@ is not deemed as fatal to satisfying the application that this
|
||||
|
||||
<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.
|
||||
the user's application for service. In general, <bf/Linux-PAM/
|
||||
ignores such a module when determining if the module stack will
|
||||
succeed or fail. However, in the absence of any definite successes or
|
||||
failures of previous or subsequent stacked modules this module will
|
||||
determine the nature of the response to the application. One example
|
||||
of this latter case, is when the other modules return something like
|
||||
<tt/PAM_IGNORE/.
|
||||
|
||||
</itemize>
|
||||
|
||||
@ -392,12 +506,12 @@ Here, <tt/valueI/ is one of the following <em/return values/:
|
||||
<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.
|
||||
action for those return values that are not explicitly defined.
|
||||
|
||||
<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
|
||||
<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
|
||||
@ -405,9 +519,41 @@ 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>
|
||||
<itemize>
|
||||
<item><tt/ignore/ - when used with a stack of modules, the module's
|
||||
return status will not contribute to the return code the application
|
||||
obtains.
|
||||
<item><tt/bad/ - this action indicates that the return code should be
|
||||
thought of as indicative of the module failing. If this module is
|
||||
the first in the stack to fail, its status value will be used for
|
||||
that of the whole stack.
|
||||
<item><tt/die/ - equivalent to <tt/bad/ with the side effect of
|
||||
terminating the module stack and PAM immediately returning to the
|
||||
application.
|
||||
<item><tt/ok/ - this tells <bf/PAM/ that the administrator thinks this
|
||||
return code should contribute directly to the return code of the full
|
||||
stack of modules. In other words, if the former state of the stack
|
||||
would lead to a return of <tt/PAM_SUCCESS/, the module's return code
|
||||
will override this value. Note, if the former state of the stack
|
||||
holds some value that is indicative of a modules failure, this 'ok'
|
||||
value will not be used to override that value.
|
||||
<item><tt/done/ - equivalent to <tt/ok/ with the side effect of
|
||||
terminating the module stack and PAM immediately returning to the
|
||||
application.
|
||||
<item><tt/reset/ - clear all memory of the state of the module stack and
|
||||
start again with the next stacked module.
|
||||
</itemize>
|
||||
|
||||
<p>
|
||||
Just to get a feel for the power of this new syntax, here is a taste
|
||||
of what you can do with it. With <bf/Linux-PAM-0.63/, the notion of
|
||||
client plug-in agents was introduced. This is something that makes it
|
||||
possible for PAM to support machine-machine authentication using the
|
||||
transport protocol inherent to the client/server application. With
|
||||
the ``<tt/[ ... value=action ... ]/'' control syntax, it is possible
|
||||
for an application to be configured to support binary prompts with
|
||||
compliant clients, but to gracefully fall over into an alternative
|
||||
authentication mode for older, legacy, applications. Flexible eh?
|
||||
|
||||
<tag> <tt/module-path/</tag>
|
||||
|
||||
@ -431,7 +577,7 @@ next section.
|
||||
</descrip>
|
||||
|
||||
<p>
|
||||
Any line in (one of) the confiuration file(s), that is not formatted
|
||||
Any line in (one of) the configuration 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)/.
|
||||
@ -453,10 +599,10 @@ 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>.
|
||||
used. The other mode (and the one currently supported by Red Hat 4.2
|
||||
and higher) 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
|
||||
@ -560,6 +706,20 @@ requires some reliably strong encryption to make it secure.
|
||||
This argument is intended for the <tt/auth/ and <tt/password/ module
|
||||
types only.
|
||||
|
||||
<tag><tt/expose_account/</tag>
|
||||
|
||||
<p>
|
||||
In general the leakage of some information about user accounts is not
|
||||
a secure policy for modules to adopt. Sometimes information such as
|
||||
users names or home directories, or preferred shell, can be used to
|
||||
attack a user's account. In some circumstances, however, this sort of
|
||||
information is not deemed a threat: displaying a user's full name when
|
||||
asking them for a password in a secured environment could also be
|
||||
called being 'friendly'. The <tt/expose_account/ argument is a
|
||||
standard module argument to encourage a module to be less discrete
|
||||
about account information as it is deemed appropriate by the local
|
||||
administrator.
|
||||
|
||||
</descrip>
|
||||
|
||||
<sect1>Example configuration file entries
|
||||
@ -681,17 +841,6 @@ 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>
|
||||
@ -801,6 +950,28 @@ 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.
|
||||
|
||||
<p>
|
||||
Here is a sample "other" configuration file. The <em/pam_deny/ module will
|
||||
deny access and the <em/pam_warn/ module will send a syslog message to
|
||||
<tt/auth.notice/:
|
||||
|
||||
<p>
|
||||
<tscreen>
|
||||
<verb>
|
||||
#
|
||||
# The PAM configuration file for the `other' service
|
||||
#
|
||||
auth required pam_deny.so
|
||||
auth required pam_warn.so
|
||||
account required pam_deny.so
|
||||
account required pam_warn.so
|
||||
password required pam_deny.so
|
||||
password required pam_warn.so
|
||||
session required pam_deny.so
|
||||
session required pam_warn.so
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
<sect>A reference guide for available modules
|
||||
|
||||
<p>
|
||||
@ -847,8 +1018,8 @@ files; the modules.
|
||||
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>
|
||||
url="http://www.kernel.org/pub/linux/libs/pam/pre/doc/rfc86.0.txt.gz"
|
||||
name="http://www.kernel.org/pub/linux/libs/pam/pre/doc/rfc86.0.txt.gz"></tt>
|
||||
|
||||
</itemize>
|
||||
|
||||
@ -875,37 +1046,9 @@ and in such a way that they need not be distributed with Linux-PAM.
|
||||
<sect>Author/acknowledgments
|
||||
|
||||
<p>
|
||||
This document was written by Andrew G. Morgan (morgan@parc.power.net)
|
||||
This document was written by Andrew G. Morgan (morgan@kernel.org)
|
||||
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.
|
||||
|
||||
<!-- insert-file CREDITS -->
|
||||
|
||||
<p>
|
||||
Thanks are also due to Sun Microsystems, especially to Vipin Samar and
|
||||
@ -920,9 +1063,6 @@ development of <bf/Linux-PAM/.
|
||||
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.
|
||||
@ -930,9 +1070,9 @@ for all the good work they have done.
|
||||
<sect>Copyright information for this document
|
||||
|
||||
<p>
|
||||
Copyright (c) Andrew G. Morgan 1996. All rights reserved.
|
||||
Copyright (c) Andrew G. Morgan 1996-9. All rights reserved.
|
||||
<newline>
|
||||
Email: <tt><morgan@parc.power.net></tt>
|
||||
Email: <tt><morgan@linux.kernel.org></tt>
|
||||
|
||||
<p>
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -980,6 +1120,6 @@ 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>
|
||||
<tt>$Id: pam_source.sgml,v 1.5 2001/03/19 01:46:41 agmorgan Exp $</tt>
|
||||
|
||||
</article>
|
||||
|
702
contrib/libpam/doc/specs/draft-morgan-pam.raw
Normal file
702
contrib/libpam/doc/specs/draft-morgan-pam.raw
Normal file
@ -0,0 +1,702 @@
|
||||
PAM working group ## A.G. Morgan
|
||||
Internet Draft: ## October 6, 1999
|
||||
Document: draft-morgan-pam-07.txt ##
|
||||
Expires: June 13, 2000 ##
|
||||
Obsoletes: draft-morgan-pam-06.txt##
|
||||
|
||||
## Pluggable Authentication Modules ##
|
||||
|
||||
#$ Status of this memo
|
||||
|
||||
This document is an draft specification. The latest version of this
|
||||
draft may be obtained from here:
|
||||
|
||||
http://linux.kernel.org/pub/linux/libs/pam/pre/doc/
|
||||
|
||||
As
|
||||
|
||||
Linux-PAM-'version'-docs.tar.gz
|
||||
|
||||
It is also contained in the Linux-PAM tar ball.
|
||||
|
||||
#$ 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 referring 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 inventing new 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 deem 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) and orthogonal to the process of authentication.
|
||||
|
||||
#$ 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 the PAM_RUSER _item_ with this requesting user].
|
||||
|
||||
arbitrator
|
||||
the entity (user) under whose identity the service application
|
||||
is negotiated and with whose authority service is granted.
|
||||
|
||||
user
|
||||
the entity (user) whose identity is being authenticated
|
||||
[PAM associates the PAM_USER _item_ 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 server end of
|
||||
the transport layer connecting the server to the client.
|
||||
PAM makes no assumptions about how data is encapsulated for
|
||||
exchanges between the server and the client, only that full
|
||||
octet sequences can be freely exchanged without corruption.
|
||||
|
||||
client
|
||||
application providing the direct/primary interface to
|
||||
applicant. This application is completely responsible
|
||||
for the client end of the transport layer connecting the
|
||||
server to the client. PAM makes no assumptions about how data
|
||||
is encapsulated for exchanges between the server and the
|
||||
client, only that full octet sequences can be freely
|
||||
exchanged without corruption.
|
||||
|
||||
module
|
||||
authentication binary that provides server-side support for
|
||||
some (arbitrary) authentication method.
|
||||
|
||||
agent
|
||||
authentication binary that provides client-side support for
|
||||
some (arbitrary) authentication method.
|
||||
|
||||
Here is a diagram to help orient the reader:
|
||||
|
||||
## +-------+ +--------+ ##
|
||||
## . . . . .| agent | .| module | ##
|
||||
## . +-------+ .+--------+ ##
|
||||
## V | . | ##
|
||||
## . | V | ##
|
||||
## +---------+ +-------+ . +------+ ##
|
||||
## | | |libpamc| . |libpam| ##
|
||||
## | | +-------+ . +------+ ##
|
||||
## |applicant| | . | ##
|
||||
## | | +--------+ +----------+ ##
|
||||
## | |---| client |-----------| server | ##
|
||||
## +---------+ +--------+ +----------+ ##
|
||||
|
||||
Solid lines connecting the boxes represent two-way interaction. The
|
||||
dotted-directed lines indicate an optional connection beteween the
|
||||
plugin module (agent) and the server (applicant). In the case of the
|
||||
module, this represents the module invoking the 'conversation'
|
||||
callback function provided to libpam by the server application when it
|
||||
inititializes the libpam library. In the case of the agent, this may
|
||||
be some out-of-PAM API interaction (for example directly displaying a
|
||||
dialog box under X).
|
||||
|
||||
#$$ Defined Data Types
|
||||
|
||||
In this draft, we define two composite data types, the text string and
|
||||
the binary prompt. They are the data types used to communicate
|
||||
authentication requests and responses.
|
||||
|
||||
#$$$#{text_string} text string
|
||||
|
||||
The text string is a simple sequence of non-NUL (NUL = 0x00)
|
||||
octets. Terminated with a single NUL (0x00) octet. The character set
|
||||
employed in the octet sequence may be negotiated out of band, but
|
||||
defaults to utf-8.
|
||||
|
||||
## --------------------------- ##
|
||||
## [ character data | NUL ] ##
|
||||
## [ octet sequence | 0x00 ] ##
|
||||
## --------------------------- ##
|
||||
|
||||
Within the rest of this text, PAM text strings are delimited with a
|
||||
pair of double quotes. Example, "this" = {'t';'h';'i';'s';0x00}.
|
||||
|
||||
#$$$#{binary_prompt} binary prompt
|
||||
|
||||
A binary prompt consists of a stream of octets arranged as follows:
|
||||
|
||||
## ---------------------------------------- ##
|
||||
## [ u32 | u8 | (length-5 octets) ] ##
|
||||
## [ length | control | data ] ##
|
||||
## ---------------------------------------- ##
|
||||
|
||||
That is, a 32-bit unsigned integer in network byte order, a single
|
||||
unsigned byte of control information and a sequence of octets of
|
||||
length (length-5). The composition of the _data_ is context dependent
|
||||
but is generally not a concern for either the server or the client. It
|
||||
is very much the concern of modules and agents.
|
||||
|
||||
For purposes of interoperability, we define the following control
|
||||
characters as legal.
|
||||
|
||||
## value symbol description ##
|
||||
## ------------------------------------------------- ##
|
||||
## 0x01 PAM_BPC_OK - continuation packet ##
|
||||
## 0x02 PAM_BPC_SELECT - initialization packet ##
|
||||
## 0x03 PAM_BPC_DONE - termination packet ##
|
||||
## 0x04 PAM_BPC_FAIL - unable to execute ##
|
||||
|
||||
The following control characters are only legal for exchanges between
|
||||
an agent and a client (it is the responsibility of the client to
|
||||
enforce this rule in the face of a rogue server):
|
||||
|
||||
## 0x41 PAM_BPC_GETENV - obtain client env.var ##
|
||||
## 0x42 PAM_BPC_PUTENV - set client env.var ##
|
||||
## 0x43 PAM_BPC_TEXT - display message ##
|
||||
## 0x44 PAM_BPC_ERROR - display error message ##
|
||||
## 0x45 PAM_BPC_PROMPT - echo'd text prompt ##
|
||||
## 0x46 PAM_BPC_PASS - non-echo'd text prompt##
|
||||
|
||||
Note, length is always equal to the total length of the binary
|
||||
prompt and represented by a network ordered unsigned 32 bit integer.
|
||||
|
||||
#$$$$#{agent_ids} PAM_BPC_SELECT binary prompts
|
||||
|
||||
Binary prompts of control type PAM_BPC_SELECT have a defined
|
||||
data part. It is composed of three elements:
|
||||
|
||||
{agent_id;'/';data}
|
||||
|
||||
The agent_id is a sequence of characters satisfying the following
|
||||
regexp:
|
||||
|
||||
/^[a-z0-9\_]+(@[a-z0-9\_.]+)?$/
|
||||
|
||||
and has a specific form for each independent agent.
|
||||
|
||||
o Agent_ids that do not contain an at-sign (@) are reserved to be
|
||||
assigned by IANA (Internet Assigned Numbers Authority). Names of
|
||||
this format MUST NOT be used without first registering with IANA.
|
||||
Registered names MUST NOT contain an at-sign (@).
|
||||
|
||||
o Anyone can define additional agents by using names in the format
|
||||
name@domainname, e.g. "ouragent@example.com". The part following
|
||||
the at-sign MUST be a valid fully qualified internet domain name
|
||||
[RFC-1034] controlled by the person or organization defining the
|
||||
name. (Said another way, if you control the email address that
|
||||
your agent has as an identifier, they you are entitled to use
|
||||
this identifier.) It is up to each domain how it manages its local
|
||||
namespace.
|
||||
|
||||
The '/' character is a mandatory delimiter, indicating the end of the
|
||||
agent_id. The trailing data is of a format specific to the agent with
|
||||
the given agent_id.
|
||||
|
||||
|
||||
#$$ Special cases
|
||||
|
||||
In a previous section (#{players}) we identified the most general
|
||||
selection of authentication participants. In the case of network
|
||||
authentication, it is straightforward to ascribe identities to the
|
||||
defined participants. However, there are also special (less general)
|
||||
cases that we recognize 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: PAM_RUSER is NULL.
|
||||
|
||||
Some client-server implementations (telnet for example) provide
|
||||
effective full tty connections. In these cases, the four simple text
|
||||
string prompting cases (see below) can be handled as in the primary
|
||||
login step. In other words, the server absorbs most of the overhead of
|
||||
propagating authentication messages. In these cases, there is special
|
||||
client/server support for handling binary prompts.
|
||||
|
||||
#$ Defined interfaces for information flow
|
||||
|
||||
Here, we discuss the information exchange interfaces between the
|
||||
players in the authentication process. It should be understood that
|
||||
the server side is responsible for driving the authentication of the
|
||||
applicant. Notably, every request received by the client from the
|
||||
server must be matched with a single response from the client to the
|
||||
server.
|
||||
|
||||
#$$#{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 directly to an applicant:
|
||||
|
||||
echo text string
|
||||
echo error text string
|
||||
prompt with text string for echo'd text string input
|
||||
prompt with text string for concealed text string 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} 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
|
||||
binary prompt agent expecting binary prompt reply to client
|
||||
|
||||
agent -> client
|
||||
binary prompt reply from agent to clients binary prompt
|
||||
|
||||
Following the acceptance of a binary prompt by the agent, the agent
|
||||
may attempt to exchange information with the client before returning
|
||||
its binary prompt reply. Permitted exchanges are binary prompts of the
|
||||
following types:
|
||||
|
||||
agent -> client
|
||||
set environment variable (A)
|
||||
get environment variable (B)
|
||||
echo text string (C)
|
||||
echo error text string (D)
|
||||
prompt for echo'd text string input (E)
|
||||
prompt for concealed text string input (F)
|
||||
|
||||
In response to these prompts, the client must legitimately respond
|
||||
with a corresponding binary prompt reply. We list a complete set of
|
||||
example exchanges, including each type of legitimate response (passes
|
||||
and a single fail):
|
||||
|
||||
## Type | Agent request | Client response ##
|
||||
## --------------------------------------------------------------- ##
|
||||
## (A) | {13;PAM_BPC_PUTENV;"FOO=BAR"} | {5;PAM_BPC_OK;} ##
|
||||
## | {10;PAM_BPC_PUTENV;"FOO="} | {5;PAM_BPC_OK;} ##
|
||||
## | {9;PAM_BPC_PUTENV;"FOO"} (*) | {5;PAM_BPC_OK;} ##
|
||||
## | {9;PAM_BPC_PUTENV;"BAR"} (*) | {5;PAM_BPC_FAIL;} ##
|
||||
## --------------------------------------------------------------- ##
|
||||
## (B) | {10;PAM_BPC_GETENV;"TERM"} | {11;PAM_BPC_OK;"vt100"} ##
|
||||
## | {9;PAM_BPC_GETENV;"FOO"} | {5;PAM_BPC_FAIL;} ##
|
||||
## --------------------------------------------------------------- ##
|
||||
## (C) | {12;PAM_BPC_TEXT;"hello!"} | {5;PAM_BPC_OK;} ##
|
||||
## | {12;PAM_BPC_TEXT;"hello!"} | {5;PAM_BPC_FAIL;} ##
|
||||
## --------------------------------------------------------------- ##
|
||||
## (D) | {11;PAM_BPC_TEXT;"ouch!"} | {5;PAM_BPC_OK;} ##
|
||||
## | {11;PAM_BPC_TEXT;"ouch!"} | {5;PAM_BPC_FAIL;} ##
|
||||
## --------------------------------------------------------------- ##
|
||||
## (E) | {13;PAM_BPC_PROMPT;"login: "} | {9;PAM_BPC_OK;"joe"} ##
|
||||
## | {13;PAM_BPC_PROMPT;"login: "} | {6;PAM_BPC_OK;""} ##
|
||||
## | {13;PAM_BPC_PROMPT;"login: "} | {5;PAM_BPC_FAIL;} ##
|
||||
## --------------------------------------------------------------- ##
|
||||
## (F) | {16;PAM_BPC_PASS;"password: "} | {9;PAM_BPC_OK;"XYZ"} ##
|
||||
## | {16;PAM_BPC_PASS;"password: "} | {6;PAM_BPC_OK;""} ##
|
||||
## | {16;PAM_BPC_PASS;"password: "} | {5;PAM_BPC_FAIL;} ##
|
||||
|
||||
(*) Used to attempt the removal of a pre-existing environment
|
||||
variable.
|
||||
|
||||
#$$ 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 responsible for driving the authentication process.
|
||||
|
||||
General servers can request the following from the client:
|
||||
|
||||
(to be forwarded by the client to the applicant)
|
||||
echo text string
|
||||
echo error text string
|
||||
prompt for echo'd text string response
|
||||
prompt for concealed text string response
|
||||
|
||||
(to be forwarded by the client to the appropriate agent)
|
||||
binary prompt for a binary prompt response
|
||||
|
||||
Client side agents are required to process binary prompts. The
|
||||
agents' binary prompt responses are returned 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. Every message sent by a
|
||||
module should be acknowledged.
|
||||
|
||||
General conversation functions can support the following five
|
||||
conversation requests:
|
||||
|
||||
echo text string
|
||||
echo error string
|
||||
prompt for echo'd text string response
|
||||
prompt for concealed text string response
|
||||
binary prompt for binary prompt response
|
||||
|
||||
The server is responsible for redirecting these requests to the
|
||||
client.
|
||||
|
||||
#$ C API for application interfaces (client and server)
|
||||
|
||||
#$$ 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.
|
||||
|
||||
All that is important is that the client application is able to
|
||||
present the applicant with textual output and to receive textual
|
||||
input from the applicant. The forms of textual exchange are listed
|
||||
in an earlier section (#{applicant_client}). Other methods of
|
||||
data input/output are better suited to being handled via an
|
||||
authentication agent.
|
||||
|
||||
#$$ Client <-> agent
|
||||
|
||||
The client makes use of a general API for communicating with
|
||||
agents. The client is not required to communicate directly with
|
||||
available agents, instead a layer of abstraction (in the form of a
|
||||
library: libpamc) takes care of loading and maintaining communication
|
||||
with all requested agents. This layer of abstraction will choose which
|
||||
agents to interact with based on the content of binary prompts it
|
||||
receives that have the control type PAM_BPC_SELECT.
|
||||
|
||||
#$$$ Client <-> libpamc
|
||||
|
||||
#$$$$ Compilation information
|
||||
|
||||
The C-header file provided for client-agent abstraction is included
|
||||
with the following source line:
|
||||
|
||||
\#include <security/pam_client.h>
|
||||
|
||||
The library providing the corresponding client-agent abstraction
|
||||
functions is, libpamc.
|
||||
|
||||
cc .... -lpamc
|
||||
|
||||
#$$$$ Initializing libpamc
|
||||
|
||||
The libpamc library is initialized with a call to the following
|
||||
function:
|
||||
|
||||
pamc_handle_t pamc_start(void);
|
||||
|
||||
This function is responsible for configuring the library and
|
||||
registering the location of available agents. The location of the
|
||||
available agents on the system is implementation specific.
|
||||
|
||||
pamc_start() function returns NULL on failure. Otherwise, the return
|
||||
value is a pointer to an opaque data type which provides a handle to
|
||||
the libpamc library. On systems where threading is available, the
|
||||
libpamc libraray is thread safe provided a single (pamc_handler_t *)
|
||||
is used by each thread.
|
||||
|
||||
#$$$$ Client (Applicant) selection of agents
|
||||
|
||||
For the purpose of applicant and client review of available agents,
|
||||
the following function is provided.
|
||||
|
||||
char **pamc_list_agents(pamc_handle_t pch);
|
||||
|
||||
This returns a list of pointers to the agent_id's of the agents which
|
||||
are available on the system. The list is terminated by a NULL pointer.
|
||||
It is the clients responsibility to free this memory area by calling
|
||||
free() on each agent id and the block of agent_id pointers in the
|
||||
result.
|
||||
|
||||
PAM represents a server-driven authentication model, so by default
|
||||
any available agent may be invoked in the authentication process.
|
||||
|
||||
#$$$$$ Client demands agent
|
||||
|
||||
If the client requires that a specific authentication agent is
|
||||
satisfied during the authentication process, then the client should
|
||||
call the following function, immediately after obtaining a
|
||||
pamc_handle_t from pamc_start().
|
||||
|
||||
int pamc_load(pamc_handle_t pch, const char *agent_id);
|
||||
|
||||
agent_id is a PAM text string (see section #{agent_ids}) and is not
|
||||
suffixed with a '/' delimiter. The return value for this function is:
|
||||
|
||||
PAM_BPC_TRUE - agent located and loaded.
|
||||
PAM_BPC_FALSE - agent is not available.
|
||||
|
||||
Note, although the agent is loaded, no data is fed to it. The agent's
|
||||
opportunity to inform the client that it does not trust the server is
|
||||
when the agent is shutdown.
|
||||
|
||||
#$$$$$ Client marks agent as unusable
|
||||
|
||||
The applicant might prefer that a named agent is marked as not
|
||||
available. To do this, the client would invoke the following function
|
||||
immediately after obtaining a pamc_handle_t from pam_start().
|
||||
|
||||
int pamc_disable(pamc_handle_t pch, const char *agent_id);
|
||||
|
||||
here agent_id is a PAM text string containing an agent_id (section
|
||||
#{agent_ids}).
|
||||
|
||||
The return value for this function is:
|
||||
|
||||
PAM_BPC_TRUE - agent is disabled. This is the response
|
||||
independent of whether the agent is locally
|
||||
available.
|
||||
|
||||
PAM_BPC_FALSE - agent cannot be disabled (this may be because
|
||||
it has already been invoked).
|
||||
|
||||
#$$$$ Allocating and manipulating binary prompts
|
||||
|
||||
All conversation between an client and an agent takes place with
|
||||
respect to binary prompts. A binary prompt (see section #{binary_prompt}), is
|
||||
obtained, resized and deleted via the following C-macro:
|
||||
|
||||
CREATION of a binary prompt with control X1 and data length Y1:
|
||||
|
||||
pamc_bp_t prompt = NULL;
|
||||
PAM_BP_RENEW(&prompt, X1, Y1);
|
||||
|
||||
REPLACEMENT of a binary prompt with a control X2 and data length Y2:
|
||||
|
||||
PAM_BP_RENEW(&prompt, X2, Y2);
|
||||
|
||||
DELETION of a binary prompt (the referenced prompt is scrubbed):
|
||||
|
||||
PAM_BP_RENEW(&prompt, 0, 0);
|
||||
|
||||
Note, the PAM_BP_RENEW macro always overwrites any prompt that you
|
||||
call it with, deleting and liberating the old contents in a secure
|
||||
fashion. Also note that PAM_BP_RENEW, when returning a prompt of data
|
||||
size Y1>0, will always append a '\0' byte to the end of the prompt (at
|
||||
data offset Y1). It is thus, by definition, acceptable to treat the
|
||||
data contents of a binary packet as a text string (see #{text_string}).
|
||||
|
||||
FILLING a binary prompt from a memory pointer U1 from offset O1 of
|
||||
length L1:
|
||||
|
||||
PAM_BP_FILL(prompt, O1, L1, U1);
|
||||
|
||||
the CONTROL type for the packet can be obtained as follows:
|
||||
|
||||
control = PAM_PB_CONTROL(prompt);
|
||||
|
||||
the LENGTH of a data within the prompt (_excluding_ its header
|
||||
information) can be obtained as follows:
|
||||
|
||||
length = PAM_BP_LENGTH(prompt);
|
||||
|
||||
the total SIZE of the prompt (_including_ its header information)
|
||||
can be obtained as follows:
|
||||
|
||||
size = PAM_BP_SIZE(prompt);
|
||||
|
||||
EXTRACTING data from a binary prompt from offset O2 of length L2 to
|
||||
a memory pointer U2:
|
||||
|
||||
PAM_BP_EXTRACT(prompt, O2, L2, U2);
|
||||
|
||||
If you require direct access to the raw prompt DATA, you should use
|
||||
the following macro:
|
||||
|
||||
__u8 *raw_data = PAM_BP_DATA(prompt);
|
||||
|
||||
#$$$$ Client<->agent conversations
|
||||
|
||||
All exchanges of binary prompts with agents are handled with the
|
||||
single function:
|
||||
|
||||
int pamc_converse(pamc_handle_t *pch, pamc_bp_t *prompt_p);
|
||||
|
||||
The return value for pamc_converse(...) is PAM_BPC_TRUE when there is
|
||||
a response packet and PAM_BPC_FALSE when the client is unable to
|
||||
handle the request represented by the original prompt. In this latter
|
||||
case, *prompt_p is set to NULL.
|
||||
|
||||
This function takes a binary prompt and returns a replacement binary
|
||||
prompt that is either a request from an agent to be acted upon by the
|
||||
client or the 'result' which should be forwarded to the server. In the
|
||||
former case, the following macro will return 1 (PAM_BPC_TRUE) and in
|
||||
all other cases, 0 (PAM_BPC_FALSE):
|
||||
|
||||
PAM_BPC_FOR_CLIENT(/* pamc_bp_t */ prompt)
|
||||
|
||||
Note, all non-NULL binary prompts returned by pamc_converse(...), are
|
||||
terminated with a '\0', even when the full length of the prompt (as
|
||||
returned by the agent) does not contain this delimiter. This is a
|
||||
defined property of the PAM_BP_RENEW macro, and can be relied upon.
|
||||
|
||||
Important security note: in certain implementations, agents are
|
||||
implemented by executable binaries, which are transparently loaded and
|
||||
managed by the PAM client library. To ensure there is never a leakage
|
||||
of elevated privilege to an unprivileged agent, the client application
|
||||
should go to some effort to lower its level of privilege. It remains
|
||||
the responsibility of the applicant and the client to ensure that it
|
||||
is not compromised by a rogue agent.
|
||||
|
||||
#$$$$ Termination of agents
|
||||
|
||||
When closing the authentication session and severing the connection
|
||||
between a client and a selection of agents, the following function is
|
||||
used:
|
||||
|
||||
int pamc_end(pamc_handle_t *pch);
|
||||
|
||||
Following a call to pamc_end, the pamc_handle_t will be invalid.
|
||||
|
||||
The return value for this function is one of the following:
|
||||
|
||||
PAM_BPC_TRUE - all invoked agents are content with
|
||||
authentication (the server is _not_ judged
|
||||
_un_trustworthy by any agent)
|
||||
|
||||
PAM_BPC_FALSE - one or more agents were unsatisfied at
|
||||
being terminated. In general, the client
|
||||
should terminate its connection to the
|
||||
server and indicate to the applicant that
|
||||
the server is untrusted.
|
||||
|
||||
#$$$ libpamc <-> agents
|
||||
|
||||
The agents are manipulated from within libpamc. Each agent is an
|
||||
executable in its own right. This permits the agent to have access to
|
||||
sensitive data not accessible directly from the client. The mode of
|
||||
communication between libpamc and an agent is through a pair of
|
||||
pipes. The agent reads binary prompts (section #{binary_prompt})
|
||||
through its standard input file descriptor and writes response (to the
|
||||
server) binary prompts and instruction binary prompts (instructions
|
||||
for the client) through its standard output file descriptor.
|
||||
|
||||
#$$ Client <-> server
|
||||
|
||||
This interface is concerned with the exchange of text and binary
|
||||
prompts between the client application and the server application. No
|
||||
API is provided for this as it is considered specific to the transport
|
||||
protocol shared by the client and the server.
|
||||
|
||||
#$$ Server <-> modules
|
||||
|
||||
The server makes use of a general API for communicating with
|
||||
modules. The client is not required to communicate directly with
|
||||
available modules. By abstracting the authentication interface, it
|
||||
becomes possible for the local administrator to make a run time
|
||||
decision about the authentication method adopted by the server.
|
||||
|
||||
#$$$ Functions and definitions available to servers and modules
|
||||
|
||||
[This section will document the following functions
|
||||
|
||||
pam_set_item()
|
||||
pam_get_item()
|
||||
pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec)
|
||||
pam_get_env(pam_handle_t *pamh, const char *varname)
|
||||
pam_strerror(pam_handle_t *pamh, int pam_errno)
|
||||
]
|
||||
|
||||
#$$$ Server <-> libpam
|
||||
|
||||
[This section will document the following pam_ calls:
|
||||
|
||||
pam_start
|
||||
pam_end
|
||||
pam_authenticate (*)
|
||||
pam_setcred
|
||||
pam_acct_mgmt
|
||||
pam_open_session
|
||||
pam_close_session
|
||||
pam_chauthtok (*)
|
||||
|
||||
The asterisked functions may return PAM_INCOMPLETE. In such cases, the
|
||||
application should be aware that the conversation function was called
|
||||
and that it returned PAM_CONV_AGAIN to a module. The correct action
|
||||
for the application to take in response to receiving PAM_INCOMPLETE,
|
||||
is to acquire the replies so that the next time the conversation
|
||||
function is called it will be able to provide the desired
|
||||
responses. And then recall pam_authenticate (pam_chauthtok) with the
|
||||
same arguments. Libpam will arrange that the module stack is resumed
|
||||
from the module that returned before. This functionality is required
|
||||
for programs whose user interface is maintained by an event loop. ]
|
||||
|
||||
#$$$ libpam <-> modules
|
||||
|
||||
[This section will document the following pam_ and pam_sm_ calls:
|
||||
|
||||
functions provided by libpam
|
||||
|
||||
pam_set_data
|
||||
pam_get_data
|
||||
|
||||
functions provided to libpam by each module
|
||||
|
||||
groups:
|
||||
AUTHENTICATION
|
||||
pam_sm_authenticate
|
||||
pam_sm_setcred
|
||||
ACCOUNT
|
||||
pam_sm_acct_mgmt
|
||||
SESSION
|
||||
pam_sm_open_session
|
||||
pam_sm_close_session
|
||||
AUTHENTICATION TOKEN MANAGEMENT
|
||||
pam_sm_chauthtok
|
||||
]
|
||||
|
||||
#$ 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 G. Morgan
|
||||
Email: morgan@ftp.kernel.org
|
||||
|
||||
## $Id: draft-morgan-pam.raw,v 1.1.1.1 2000/06/20 22:11:07 agmorgan Exp $ ##
|
||||
|
@ -1,45 +1,14 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.19 1997/04/05 06:58:43 morgan Exp morgan $
|
||||
# $Id: Makefile,v 1.4 2001/02/10 07:17:53 agmorgan Exp $
|
||||
#
|
||||
# $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.
|
||||
#
|
||||
|
||||
include ../Make.Rules
|
||||
|
||||
# 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)
|
||||
ifeq ($(WITH_LIBDEBUG),yes)
|
||||
LIBNAME=libpamd
|
||||
else
|
||||
LIBNAME=libpam
|
||||
@ -49,12 +18,13 @@ MODIFICATION=.$(MINOR_REL)
|
||||
|
||||
# ---------------------------------------------
|
||||
|
||||
dummy:
|
||||
@echo "*** This is not a top-level Makefile!"
|
||||
dummy: ../Make.Rules all
|
||||
|
||||
# ---------------------------------------------
|
||||
|
||||
CFLAGS += $(DYNAMIC) $(STATIC) $(MOREFLAGS)
|
||||
CFLAGS += $(DYNAMIC) $(STATIC) $(MOREFLAGS) \
|
||||
-DLIBPAM_VERSION_MAJOR=$(MAJOR_REL) \
|
||||
-DLIBPAM_VERSION_MINOR=$(MINOR_REL)
|
||||
|
||||
# dynamic library names
|
||||
|
||||
@ -67,8 +37,11 @@ LIBPAMFULL = $(LIBPAMNAME)$(MODIFICATION)
|
||||
LIBPAMSTATIC = $(LIBNAME).a
|
||||
|
||||
ifdef STATIC
|
||||
@echo Did you mean to set STATIC\?
|
||||
MODULES = $(shell cat ../modules/_static_module_objects)
|
||||
STATICOBJ = pam_static.o
|
||||
else
|
||||
MODULES =
|
||||
endif
|
||||
|
||||
ifdef MEMORY_DEBUG
|
||||
@ -80,15 +53,16 @@ LIBOBJECTS = pam_item.o pam_strerror.o pam_end.o pam_start.o pam_data.o \
|
||||
pam_account.o pam_auth.o pam_session.o pam_password.o \
|
||||
pam_env.o pam_log.o $(EXTRAS)
|
||||
|
||||
ifdef DYNAMIC_LIBPAM
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
# libpam.so needs -ldl, too.
|
||||
DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS) $(STATICOBJ))
|
||||
ifdef STATICOBJ
|
||||
ifeq ($(STATICOBJ),yes)
|
||||
dynamic/pam_static.o: pam_static.c ../modules/_static_module_objects
|
||||
$(CC) $(CFLAGS) -c pam_static.c -o $@
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef STATIC_LIBPAM
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ))
|
||||
ifdef STATICOBJ
|
||||
static/pam_static.o: pam_static.c ../modules/_static_module_objects
|
||||
@ -99,45 +73,46 @@ endif
|
||||
# ---------------------------------------------
|
||||
## rules
|
||||
|
||||
all: dirs $(LIBPAM) $(LIBPAMSTATIC)
|
||||
all: dirs $(LIBPAM) $(LIBPAMSTATIC) ../Make.Rules
|
||||
|
||||
dirs:
|
||||
ifdef DYNAMIC_LIBPAM
|
||||
mkdir -p dynamic
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
$(MKDIR) dynamic
|
||||
endif
|
||||
ifdef STATIC_LIBPAM
|
||||
mkdir -p static
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(MKDIR) static
|
||||
endif
|
||||
|
||||
dynamic/%.o : %.c
|
||||
$(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
|
||||
static/%.o : %.c
|
||||
$(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
|
||||
$(LIBPAM): $(DLIBOBJECTS)
|
||||
ifdef DYNAMIC_LIBPAM
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
ifeq ($(USESONAME),yes)
|
||||
$(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) $(MODULES)
|
||||
$(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) \
|
||||
$(MODULES) $(LINKLIBS)
|
||||
else
|
||||
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
|
||||
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
|
||||
endif
|
||||
ifeq ($(NEEDSONAME),yes)
|
||||
rm -f $(LIBPAMFULL)
|
||||
ln -s $(LIBPAM) $(LIBPAMFULL)
|
||||
ln -sf $(LIBPAM) $(LIBPAMFULL)
|
||||
rm -f $(LIBPAMNAME)
|
||||
ln -s $(LIBPAM) $(LIBPAMNAME)
|
||||
ln -sf $(LIBPAM) $(LIBPAMNAME)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(LIBPAMSTATIC): $(SLIBOBJECTS)
|
||||
ifdef STATIC_LIBPAM
|
||||
$(AR) $@ $(SLIBOBJECTS) $(MODULES)
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
ar cr $@ $(SLIBOBJECTS) $(MODULES)
|
||||
$(RANLIB) $@
|
||||
endif
|
||||
|
||||
install: all
|
||||
$(MKDIR) $(FAKEROOT)$(INCLUDED)
|
||||
$(MKDIR) $(FAKEROOT)$(INCLUDED) $(FAKEROOT)$(libdir)
|
||||
$(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)
|
||||
@ -146,15 +121,16 @@ install: all
|
||||
ifdef MEMORY_DEBUG
|
||||
$(INSTALL) -m 644 include/security/pam_malloc.h $(FAKEROOT)$(INCLUDED)
|
||||
endif
|
||||
ifdef DYNAMIC_LIBPAM
|
||||
$(INSTALL) -m $(SHLIBMODE) $(LIBPAM) $(FAKEROOT)$(LIBDIR)/$(LIBPAMFULL)
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
$(INSTALL) -m $(SHLIBMODE) $(LIBPAM) $(FAKEROOT)$(libdir)/$(LIBPAMFULL)
|
||||
$(LDCONFIG)
|
||||
ifneq ($(DYNTYPE),"sl")
|
||||
( cd $(FAKEROOT)$(LIBDIR) ; rm -f $(LIBPAM) ; ln -s $(LIBPAMNAME) $(LIBPAM) )
|
||||
( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBPAM) ; \
|
||||
ln -sf $(LIBPAMNAME) $(LIBPAM) )
|
||||
endif
|
||||
endif
|
||||
ifdef STATIC_LIBPAM
|
||||
$(INSTALL) -m 644 $(LIBPAMSTATIC) $(FAKEROOT)$(LIBDIR)
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(INSTALL) -m 644 $(LIBPAMSTATIC) $(FAKEROOT)$(libdir)
|
||||
endif
|
||||
|
||||
remove:
|
||||
@ -163,15 +139,13 @@ remove:
|
||||
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)
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBPAM).*
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBPAM)
|
||||
$(LDCONFIG)
|
||||
rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAMSTATIC)
|
||||
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/*~
|
||||
rm -f *.a *.o *.so ./include/security/*~
|
||||
if [ -d dynamic ]; then rmdir dynamic ; fi
|
||||
if [ -d static ]; then rmdir static ; fi
|
||||
|
@ -2,7 +2,10 @@
|
||||
#define _PAM_COMPAT_H
|
||||
|
||||
/*
|
||||
* $Id: _pam_compat.h,v 1.1.1.1 2000/06/20 22:11:21 agmorgan Exp $
|
||||
*
|
||||
* This file was contributed by Derrick J Brashear <shadow@dementia.org>
|
||||
* slight modification by Brad M. Garcia <bgarcia@fore.com>
|
||||
*
|
||||
* A number of operating systems have started to implement PAM.
|
||||
* unfortunately, they have a different set of numeric values for
|
||||
@ -12,17 +15,25 @@
|
||||
/* Solaris uses different constants. We redefine to those here */
|
||||
#if defined(solaris) || (defined(__SVR4) && defined(sun))
|
||||
|
||||
#ifndef _SECURITY__PAM_TYPES_H
|
||||
|
||||
# ifdef _SECURITY_PAM_MODULES_H
|
||||
|
||||
/* flags for pam_chauthtok() */
|
||||
# undef PAM_PRELIM_CHECK
|
||||
# define PAM_PRELIM_CHECK 0x1
|
||||
|
||||
# undef PAM_UPDATE_AUTHTOK
|
||||
# define PAM_UPDATE_AUTHTOK 0x2
|
||||
|
||||
# endif /* _SECURITY_PAM_MODULES_H */
|
||||
|
||||
#else /* _SECURITY__PAM_TYPES_H */
|
||||
|
||||
/* 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
|
||||
@ -33,8 +44,8 @@
|
||||
# undef PAM_REINITIALIZE_CRED
|
||||
# define PAM_REINITIALIZE_CRED 0x4
|
||||
|
||||
# define PAM_REFRESH_CRED 0x8
|
||||
# undef PAM_REFRESH_CRED
|
||||
# define PAM_REFRESH_CRED 0x8
|
||||
|
||||
/* another binary incompatibility comes from the return codes! */
|
||||
|
||||
@ -104,6 +115,8 @@
|
||||
# undef PAM_TRY_AGAIN
|
||||
# define PAM_TRY_AGAIN 27
|
||||
|
||||
#endif /* _SECURITY__PAM_TYPES_H */
|
||||
|
||||
#endif /* defined(solaris) || (defined(__SVR4) && defined(sun)) */
|
||||
|
||||
#endif /* _PAM_COMPAT_H */
|
||||
|
@ -9,7 +9,9 @@
|
||||
|
||||
/* a 'safe' version of strdup */
|
||||
|
||||
extern char *strdup(const char *s);
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define x_strdup(s) ( (s) ? strdup(s):NULL )
|
||||
|
||||
/* Good policy to strike out passwords with some characters not just
|
||||
@ -61,8 +63,10 @@ do { \
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* This is for debugging purposes ONLY. DO NOT use on live systems !!!
|
||||
@ -80,37 +84,55 @@ 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"))) {
|
||||
int must_close = 1, fd;
|
||||
|
||||
#ifdef O_NOFOLLOW
|
||||
if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) {
|
||||
#else
|
||||
if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) {
|
||||
#endif
|
||||
if (!(logfile = fdopen(fd,"a"))) {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
must_close = 0;
|
||||
}
|
||||
fprintf(logfile,"[%s:%s(%d)] ",file, fn, line);
|
||||
if (must_close) {
|
||||
fflush(logfile);
|
||||
fflush(logfile);
|
||||
if (must_close)
|
||||
fclose(logfile);
|
||||
}
|
||||
}
|
||||
|
||||
static void _pam_output_debug(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
FILE *logfile;
|
||||
int must_close = 1;
|
||||
int must_close = 1, fd;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
#ifdef O_NOFOLLOW
|
||||
if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) {
|
||||
#else
|
||||
if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) {
|
||||
#endif
|
||||
if (!(logfile = fdopen(fd,"a"))) {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
}
|
||||
vfprintf(logfile, format, args);
|
||||
fprintf(logfile, "\n");
|
||||
if (must_close) {
|
||||
fflush(logfile);
|
||||
fflush(logfile);
|
||||
if (must_close)
|
||||
fclose(logfile);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* <security/_pam_types.h>
|
||||
*
|
||||
* $Id: _pam_types.h,v 1.10 1997/04/05 06:52:50 morgan Exp morgan $
|
||||
* $Id: _pam_types.h,v 1.4 2001/01/22 06:07:29 agmorgan Exp $
|
||||
*
|
||||
* This file defines all of the types common to the Linux-PAM library
|
||||
* applications and modules.
|
||||
@ -9,13 +9,16 @@
|
||||
* 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
|
||||
|
||||
#ifndef __LIBPAM_VERSION
|
||||
# define __LIBPAM_VERSION __libpam_version
|
||||
#endif
|
||||
extern unsigned int __libpam_version;
|
||||
|
||||
/*
|
||||
* include local definition for POSIX - NULL
|
||||
*/
|
||||
@ -88,7 +91,10 @@ typedef struct pam_handle pam_handle_t;
|
||||
calling again, verify that conversation
|
||||
is completed */
|
||||
|
||||
/* Add new #define's here */
|
||||
/*
|
||||
* Add new #define's here - take care to also extend the libpam code:
|
||||
* pam_strerror() and "libpam/pam_tokens.h" .
|
||||
*/
|
||||
|
||||
#define _PAM_RETURN_VALUES 32 /* this is the number of return values */
|
||||
|
||||
@ -141,7 +147,6 @@ typedef struct pam_handle pam_handle_t;
|
||||
#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 ----------- */
|
||||
|
||||
@ -178,50 +183,18 @@ extern char **pam_getenvlist(pam_handle_t *pamh);
|
||||
* 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);
|
||||
* void (*fail_delay)(int status, unsigned int delay, void *appdata_ptr);
|
||||
*/
|
||||
|
||||
#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, ... );
|
||||
#include <syslog.h>
|
||||
#ifndef LOG_AUTHPRIV
|
||||
# ifdef LOG_PRIV
|
||||
# define LOG_AUTHPRIV LOG_PRIV
|
||||
# endif /* LOG_PRIV */
|
||||
#endif /* !LOG_AUTHPRIV */
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
/*
|
||||
@ -246,14 +219,8 @@ extern void pam_system_log(const pam_handle_t *pamh,
|
||||
#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 */
|
||||
part of the X/Open PAM specification. */
|
||||
|
||||
#define PAM_BINARY_MSG 6
|
||||
#define PAM_BINARY_PROMPT 7
|
||||
|
||||
/* maximum size of messages/responses etc.. (these are mostly
|
||||
@ -280,10 +247,11 @@ struct pam_message {
|
||||
|
||||
struct {
|
||||
u32 length; # network byte order
|
||||
unsigned char data[length];
|
||||
unsigned char type;
|
||||
unsigned char data[length-5];
|
||||
};
|
||||
|
||||
The 'libpam_client' library is designed around this flavor of
|
||||
The 'libpamc' library is designed around this flavor of
|
||||
message and should be used to handle this flavor of msg_style.
|
||||
*/
|
||||
|
||||
|
@ -10,27 +10,16 @@
|
||||
* 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 $
|
||||
*
|
||||
* $Id: pam_appl.h,v 1.3 2000/11/19 23:54:02 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#ifndef _SECURITY_PAM_APPL_H
|
||||
#define _SECURITY_PAM_APPL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <security/_pam_types.h> /* Linux-PAM common defined types */
|
||||
|
||||
/* -------------- The Linux-PAM Framework layer API ------------- */
|
||||
@ -58,6 +47,10 @@ extern int pam_close_session(pam_handle_t *pamh, int flags);
|
||||
|
||||
extern int pam_chauthtok(pam_handle_t *pamh, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* take care of any compatibility issues */
|
||||
#include <security/_pam_compat.h>
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
/* $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
|
||||
*
|
||||
/*
|
||||
* $Id: pam_malloc.h,v 1.2 2000/12/04 19:02:34 baggins Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -6,8 +6,18 @@
|
||||
|
||||
int pam_acct_mgmt(pam_handle_t *pamh, int flags)
|
||||
{
|
||||
int retval;
|
||||
|
||||
D(("called"));
|
||||
|
||||
IF_NO_PAMH("pam_acct_mgmt",pamh,PAM_SYSTEM_ERR);
|
||||
return _pam_dispatch(pamh, flags, PAM_ACCOUNT);
|
||||
IF_NO_PAMH("pam_acct_mgmt", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
retval = _pam_dispatch(pamh, flags, PAM_ACCOUNT);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -1,11 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* $Id: pam_auth.c,v 1.3 2001/01/22 06:07:28 agmorgan Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -20,6 +16,13 @@ int pam_authenticate(pam_handle_t *pamh, int flags)
|
||||
|
||||
D(("pam_authenticate called"));
|
||||
|
||||
IF_NO_PAMH("pam_authenticate", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
if (pamh->former.choice == PAM_NOT_STACKED) {
|
||||
_pam_sanitize(pamh);
|
||||
_pam_start_timer(pamh); /* we try to make the time for a failure
|
||||
@ -27,7 +30,6 @@ int pam_authenticate(pam_handle_t *pamh, int flags)
|
||||
fail */
|
||||
}
|
||||
|
||||
IF_NO_PAMH("pam_authenticate",pamh,PAM_SYSTEM_ERR);
|
||||
retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE);
|
||||
|
||||
if (retval != PAM_INCOMPLETE) {
|
||||
@ -45,9 +47,14 @@ int pam_setcred(pam_handle_t *pamh, int flags)
|
||||
{
|
||||
int retval;
|
||||
|
||||
D(("pam_setcred called"));
|
||||
|
||||
IF_NO_PAMH("pam_setcred", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
D(("pam_setcred called"));
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
if (! flags) {
|
||||
flags = PAM_ESTABLISH_CRED;
|
||||
|
@ -1,23 +1,7 @@
|
||||
/* 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
|
||||
*
|
||||
*
|
||||
* $Id: pam_data.c,v 1.2 2001/01/22 06:07:28 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -25,7 +9,26 @@
|
||||
|
||||
#include "pam_private.h"
|
||||
|
||||
struct pam_data *_pam_locate_data(const pam_handle_t *pamh, const char *name);
|
||||
static struct pam_data *_pam_locate_data(const pam_handle_t *pamh,
|
||||
const char *name)
|
||||
{
|
||||
struct pam_data *data;
|
||||
|
||||
D(("called"));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int pam_set_data(
|
||||
pam_handle_t *pamh,
|
||||
@ -35,21 +38,27 @@ int pam_set_data(
|
||||
{
|
||||
struct pam_data *data_entry;
|
||||
|
||||
IF_NO_PAMH("pam_set_data",pamh,PAM_SYSTEM_ERR);
|
||||
D(("called"));
|
||||
|
||||
IF_NO_PAMH("pam_set_data", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_APP(pamh)) {
|
||||
D(("called from application!?"));
|
||||
return 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 );
|
||||
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_system_log(LOG_CRIT, "pam_set_data: no memory for data name");
|
||||
_pam_drop(data_entry);
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
@ -57,8 +66,7 @@ int pam_set_data(
|
||||
pamh->data = data_entry;
|
||||
data_entry->name = tname;
|
||||
} else {
|
||||
pam_system_log(pamh, NULL, LOG_CRIT,
|
||||
"pam_set_data: cannot allocate data entry");
|
||||
_pam_system_log(LOG_CRIT, "pam_set_data: cannot allocate data entry");
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
@ -75,7 +83,14 @@ int pam_get_data(
|
||||
{
|
||||
struct pam_data *data;
|
||||
|
||||
IF_NO_PAMH("pam_get_data",pamh,PAM_SYSTEM_ERR);
|
||||
D(("called"));
|
||||
|
||||
IF_NO_PAMH("pam_get_data", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_APP(pamh)) {
|
||||
D(("called from application!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
data = _pam_locate_data(pamh, module_data_name);
|
||||
if (data) {
|
||||
@ -86,29 +101,14 @@ int pam_get_data(
|
||||
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 */);
|
||||
D(("called"));
|
||||
|
||||
IF_NO_PAMH("_pam_free_data", pamh, /* no return value for void fn */);
|
||||
data = pamh->data;
|
||||
|
||||
while (data) {
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* pam_delay.c
|
||||
*
|
||||
* Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org> 1996-8
|
||||
* Copyright (c) Andrew G. Morgan <morgan@kernel.org> 1996-9
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Id: pam_delay.c,v 1.5 1997/04/05 06:54:19 morgan Exp $
|
||||
* $Id: pam_delay.c,v 1.3 2001/01/22 06:07:28 agmorgan Exp $
|
||||
*
|
||||
* $Log: pam_delay.c,v $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -94,13 +93,20 @@ void _pam_await_timer(pam_handle_t *pamh, int status)
|
||||
if (pamh->fail_delay.delay_fn_ptr) {
|
||||
union {
|
||||
const void *value;
|
||||
void (*fn)(int, unsigned);
|
||||
void (*fn)(int, unsigned, void *);
|
||||
} hack_fn_u;
|
||||
void *appdata_ptr;
|
||||
|
||||
if (pamh->pam_conversation) {
|
||||
appdata_ptr = pamh->pam_conversation->appdata_ptr;
|
||||
} else {
|
||||
appdata_ptr = NULL;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
hack_fn_u.fn(status, delay, appdata_ptr);
|
||||
|
||||
} else if (status != PAM_SUCCESS && pamh->fail_delay.set) {
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* pam_dispatch.c - handles module function dispatch */
|
||||
|
||||
/*
|
||||
* $Id: pam_dispatch.c,v 1.8 1997/01/04 20:04:09 morgan Exp morgan $
|
||||
* Copyright (c) 1998 Andrew G. Morgan <morgan@kernel.org>
|
||||
*
|
||||
* last modified by AGM
|
||||
* $Id: pam_dispatch.c,v 1.3 2001/02/05 06:50:41 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -28,7 +28,7 @@
|
||||
*/
|
||||
|
||||
static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
_pam_boolean resumed)
|
||||
_pam_boolean resumed, int use_cached_chain)
|
||||
{
|
||||
int depth, impression, status, skip_depth;
|
||||
|
||||
@ -38,9 +38,8 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
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>" );
|
||||
_pam_system_log(LOG_ERR, "no modules loaded for `%s' service",
|
||||
service ? service:"<unknown>" );
|
||||
service = NULL;
|
||||
return PAM_MUST_FAIL_CODE;
|
||||
}
|
||||
@ -63,7 +62,7 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
|
||||
/* Loop through module logic stack */
|
||||
for (depth=0 ; h != NULL ; h = h->next, ++depth) {
|
||||
int retval, action;
|
||||
int retval, cached_retval, action;
|
||||
|
||||
/* skip leading modules if they have already returned */
|
||||
if (depth < skip_depth) {
|
||||
@ -79,7 +78,7 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
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"));
|
||||
D(("module poorly listed in PAM config; forcing failure"));
|
||||
retval = PAM_MUST_FAIL_CODE;
|
||||
}
|
||||
}
|
||||
@ -100,23 +99,57 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (use_cached_chain) {
|
||||
/* a former stack execution has frozen the chain */
|
||||
cached_retval = *(h->cached_retval_p);
|
||||
} else {
|
||||
/* this stack execution is defining the frozen chain */
|
||||
cached_retval = h->cached_retval = retval;
|
||||
}
|
||||
|
||||
/* verify that the return value is a valid one */
|
||||
if (retval < PAM_SUCCESS || retval >= _PAM_RETURN_VALUES) {
|
||||
if ((cached_retval < PAM_SUCCESS)
|
||||
|| (cached_retval >= _PAM_RETURN_VALUES)) {
|
||||
retval = PAM_MUST_FAIL_CODE;
|
||||
action = _PAM_ACTION_BAD;
|
||||
} else {
|
||||
action = h->actions[retval];
|
||||
/* We treat the current retval with some respect. It may
|
||||
(for example, in the case of setcred) have a value that
|
||||
needs to be propagated to the user. We want to use the
|
||||
cached_retval to determine the modules to be executed
|
||||
in the stacked chain, but we want to treat each
|
||||
non-ignored module in the cached chain as now being
|
||||
'required'. We only need to treat the,
|
||||
_PAM_ACTION_IGNORE, _PAM_ACTION_IS_JUMP and
|
||||
_PAM_ACTION_RESET actions specially. */
|
||||
|
||||
action = h->actions[cached_retval];
|
||||
}
|
||||
|
||||
D((stderr,
|
||||
"use_cached_chain=%d action=%d cached_retval=%d retval=%d\n",
|
||||
use_cached_chain, action, cached_retval, retval));
|
||||
|
||||
/* decide what to do */
|
||||
switch (action) {
|
||||
case _PAM_ACTION_RESET:
|
||||
|
||||
/* if (use_cached_chain) {
|
||||
XXX - we need to consider the use_cached_chain case
|
||||
do we want to trash accumulated info here..?
|
||||
} */
|
||||
|
||||
impression = _PAM_UNDEF;
|
||||
status = PAM_MUST_FAIL_CODE;
|
||||
break;
|
||||
|
||||
case _PAM_ACTION_OK:
|
||||
case _PAM_ACTION_DONE:
|
||||
|
||||
/* XXX - should we maintain cached_status and status in
|
||||
the case of use_cached_chain? The same with BAD&DIE
|
||||
below */
|
||||
|
||||
if ( impression == _PAM_UNDEF
|
||||
|| (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) {
|
||||
impression = _PAM_POSITIVE;
|
||||
@ -130,7 +163,7 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
case _PAM_ACTION_BAD:
|
||||
case _PAM_ACTION_DIE:
|
||||
#ifdef PAM_FAIL_NOW_ON
|
||||
if ( retval == PAM_ABORT ) {
|
||||
if ( cached_retval == PAM_ABORT ) {
|
||||
impression = _PAM_NEGATIVE;
|
||||
status = PAM_PERM_DENIED;
|
||||
goto decision_made;
|
||||
@ -146,6 +179,11 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
break;
|
||||
|
||||
case _PAM_ACTION_IGNORE:
|
||||
/* if (use_cached_chain) {
|
||||
XXX - when evaluating a cached
|
||||
chain, do we still want to ignore the module's
|
||||
return value?
|
||||
} */
|
||||
break;
|
||||
|
||||
/* if we get here, we expect action is a positive number --
|
||||
@ -153,6 +191,20 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
|
||||
default:
|
||||
if ( _PAM_ACTION_IS_JUMP(action) ) {
|
||||
|
||||
/* If we are evaluating a cached chain, we treat this
|
||||
module as required (aka _PAM_ACTION_OK) as well as
|
||||
executing the jump. */
|
||||
|
||||
if (use_cached_chain) {
|
||||
if (impression == _PAM_UNDEF
|
||||
|| (impression == _PAM_POSITIVE
|
||||
&& status == PAM_SUCCESS) ) {
|
||||
impression = _PAM_POSITIVE;
|
||||
status = retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* this means that we need to skip #action stacked modules */
|
||||
do {
|
||||
h = h->next;
|
||||
@ -193,24 +245,32 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
|
||||
int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
|
||||
{
|
||||
struct handler *h = NULL;
|
||||
int retval;
|
||||
int retval, use_cached_chain;
|
||||
_pam_boolean resumed;
|
||||
|
||||
IF_NO_PAMH("_pam_dispatch",pamh,PAM_SYSTEM_ERR);
|
||||
IF_NO_PAMH("_pam_dispatch", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from a module!?"));
|
||||
return 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");
|
||||
_pam_system_log(LOG_ERR, "unable to dispatch function");
|
||||
return retval;
|
||||
}
|
||||
|
||||
use_cached_chain = 0; /* default to setting h->cached_retval */
|
||||
|
||||
switch (choice) {
|
||||
case PAM_AUTHENTICATE:
|
||||
h = pamh->handlers.conf.authenticate;
|
||||
break;
|
||||
case PAM_SETCRED:
|
||||
h = pamh->handlers.conf.setcred;
|
||||
use_cached_chain = 1;
|
||||
break;
|
||||
case PAM_ACCOUNT:
|
||||
h = pamh->handlers.conf.acct_mgmt;
|
||||
@ -220,12 +280,16 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
|
||||
break;
|
||||
case PAM_CLOSE_SESSION:
|
||||
h = pamh->handlers.conf.close_session;
|
||||
use_cached_chain = 1;
|
||||
break;
|
||||
case PAM_CHAUTHTOK:
|
||||
h = pamh->handlers.conf.chauthtok;
|
||||
if (flags & PAM_UPDATE_AUTHTOK) {
|
||||
use_cached_chain = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pam_system_log(pamh, NULL, LOG_ERR, "undefined fn choice; %d", choice);
|
||||
_pam_system_log(LOG_ERR, "undefined fn choice; %d", choice);
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -256,9 +320,9 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
|
||||
/* 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);
|
||||
_pam_system_log(LOG_ERR,
|
||||
"application failed to re-exec stack [%d:%d]",
|
||||
pamh->former.choice, choice);
|
||||
return PAM_ABORT;
|
||||
}
|
||||
resumed = PAM_TRUE;
|
||||
@ -266,10 +330,14 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
|
||||
resumed = PAM_FALSE;
|
||||
}
|
||||
|
||||
__PAM_TO_MODULE(pamh);
|
||||
|
||||
/* call the list of module functions */
|
||||
retval = _pam_dispatch_aux(pamh, flags, h, resumed);
|
||||
retval = _pam_dispatch_aux(pamh, flags, h, resumed, use_cached_chain);
|
||||
resumed = PAM_FALSE;
|
||||
|
||||
__PAM_TO_APP(pamh);
|
||||
|
||||
/* Should we recall where to resume next time? */
|
||||
if (retval == PAM_INCOMPLETE) {
|
||||
D(("module [%d] returned PAM_INCOMPLETE"));
|
||||
@ -281,6 +349,3 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: pam_dispatch.c,v $
|
||||
*/
|
||||
|
@ -1,9 +1,7 @@
|
||||
/* pam_end.c */
|
||||
|
||||
/*
|
||||
* $Id: pam_end.c,v 1.5 1996/12/01 03:14:13 morgan Exp $
|
||||
*
|
||||
* $Log: pam_end.c,v $
|
||||
* $Id: pam_end.c,v 1.2 2001/01/22 06:07:28 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -14,9 +12,14 @@ int pam_end(pam_handle_t *pamh, int pam_status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
D(("entering pam_end()"));
|
||||
|
||||
IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
D(("entering pam_end()"));
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
/* first liberate the modules (it is not inconcevible that the
|
||||
modules may need to use the service_name etc. to clean up) */
|
||||
@ -64,9 +67,6 @@ int pam_end(pam_handle_t *pamh, int pam_status)
|
||||
_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);
|
||||
|
@ -7,14 +7,7 @@
|
||||
* 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
|
||||
* $Id: pam_env.c,v 1.2 2001/01/22 06:07:28 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@ -54,6 +47,7 @@ static void _pam_dump_env(pam_handle_t *pamh)
|
||||
int _pam_make_env(pam_handle_t *pamh)
|
||||
{
|
||||
D(("called."));
|
||||
|
||||
IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
|
||||
|
||||
/*
|
||||
@ -62,7 +56,7 @@ int _pam_make_env(pam_handle_t *pamh)
|
||||
|
||||
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");
|
||||
_pam_system_log(LOG_CRIT, "_pam_make_env: out of memory");
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
@ -72,8 +66,7 @@ int _pam_make_env(pam_handle_t *pamh)
|
||||
|
||||
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_system_log(LOG_CRIT, "_pam_make_env: no memory for list");
|
||||
_pam_drop(pamh->env);
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
@ -163,8 +156,7 @@ int pam_putenv(pam_handle_t *pamh, const char *name_value)
|
||||
IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
|
||||
|
||||
if (name_value == NULL) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR,
|
||||
"pam_putenv: no variable indicated");
|
||||
_pam_system_log(LOG_ERR, "pam_putenv: no variable indicated");
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
@ -174,7 +166,7 @@ int pam_putenv(pam_handle_t *pamh, const char *name_value)
|
||||
|
||||
for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
|
||||
if (l2eq <= 0) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: bad variable");
|
||||
_pam_system_log(LOG_ERR, "pam_putenv: bad variable");
|
||||
return PAM_BAD_ITEM;
|
||||
}
|
||||
|
||||
@ -183,8 +175,8 @@ int pam_putenv(pam_handle_t *pamh, const char *name_value)
|
||||
*/
|
||||
|
||||
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");
|
||||
_pam_system_log(LOG_ERR, "pam_putenv: no env%s found",
|
||||
pamh->env == NULL ? "":"-list");
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -206,8 +198,8 @@ int pam_putenv(pam_handle_t *pamh, const char *name_value)
|
||||
, sizeof(char *) );
|
||||
if (tmp == NULL) {
|
||||
/* nothing has changed - old env intact */
|
||||
pam_system_log(pamh, NULL, LOG_CRIT,
|
||||
"pam_putenv: cannot grow environment");
|
||||
_pam_system_log(LOG_CRIT,
|
||||
"pam_putenv: cannot grow environment");
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
@ -258,8 +250,7 @@ int pam_putenv(pam_handle_t *pamh, const char *name_value)
|
||||
/* 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",
|
||||
_pam_system_log(LOG_ERR, "pam_putenv: delete non-existent entry; %s",
|
||||
name_value);
|
||||
return PAM_BAD_ITEM;
|
||||
}
|
||||
@ -298,14 +289,13 @@ const char *pam_getenv(pam_handle_t *pamh, const char *name)
|
||||
IF_NO_PAMH("pam_getenv", pamh, NULL);
|
||||
|
||||
if (name == NULL) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR,
|
||||
"pam_getenv: no variable indicated");
|
||||
_pam_system_log(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" );
|
||||
_pam_system_log(LOG_ERR, "pam_getenv: no env%s found",
|
||||
pamh->env == NULL ? "":"-list" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -371,25 +361,22 @@ char **pam_getenvlist(pam_handle_t *pamh)
|
||||
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" );
|
||||
_pam_system_log(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_system_log(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_system_log(LOG_ERR, "pam_getenvlist: environment broken");
|
||||
_pam_dump_env(pamh); /* only active when debugging */
|
||||
return NULL; /* somehow we've broken the environment!? */
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* 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 $
|
||||
* $Id: pam_handlers.c,v 1.3 2001/02/05 06:50:41 agmorgan Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -13,11 +13,13 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef PAM_SHL
|
||||
# include <dl.h>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
#ifdef PAM_DYNAMIC
|
||||
# ifdef PAM_SHL
|
||||
# include <dl.h>
|
||||
# else /* PAM_SHL */
|
||||
# include <dlfcn.h>
|
||||
# endif /* PAM_SHL */
|
||||
#endif /* PAM_DYNAMIC */
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -33,8 +35,9 @@
|
||||
# define SHLIB_SYM_PREFIX ""
|
||||
#endif
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
#define MODULE_CHUNK 4
|
||||
#define BUF_SIZE 1024
|
||||
#define MODULE_CHUNK 4
|
||||
#define UNKNOWN_MODULE_PATH "<*unknown module path*>"
|
||||
|
||||
static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
|
||||
|
||||
@ -110,9 +113,8 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
|
||||
} 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);
|
||||
_pam_system_log(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 */
|
||||
}
|
||||
@ -162,8 +164,8 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
|
||||
} 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);
|
||||
_pam_system_log(LOG_ERR,
|
||||
"(%s) no module name supplied", this_service);
|
||||
mod_path = NULL;
|
||||
must_fail = 1;
|
||||
}
|
||||
@ -198,8 +200,6 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
|
||||
actions[y]>0 ? "jump":
|
||||
_pam_token_actions[-actions[y]]));
|
||||
}
|
||||
fprintf(stderr, "pause to look at debugging: ");
|
||||
getchar();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -207,8 +207,7 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
|
||||
, module_type, actions, mod_path
|
||||
, argc, argv, argvlen);
|
||||
if (res != PAM_SUCCESS) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR,
|
||||
"error loading %s", mod_path);
|
||||
_pam_system_log(LOG_ERR, "error loading %s", mod_path);
|
||||
D(("failed to load module - aborting"));
|
||||
return PAM_ABORT;
|
||||
}
|
||||
@ -240,8 +239,8 @@ int _pam_init_handlers(pam_handle_t *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");
|
||||
_pam_system_log(LOG_CRIT,
|
||||
"_pam_init_handlers: no memory loading module");
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
pamh->handlers.modules_allocated = MODULE_CHUNK;
|
||||
@ -258,9 +257,8 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
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");
|
||||
_pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile ("
|
||||
PAM_LOCK_FILE ") exists - aborting");
|
||||
(void) close(fd_tmp);
|
||||
/*
|
||||
* to avoid swamping the system with requests
|
||||
@ -289,9 +287,9 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
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);
|
||||
_pam_system_log(LOG_ERR,
|
||||
"_pam_init_handlers: no memory; service %s",
|
||||
pamh->service_name);
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
|
||||
@ -306,12 +304,11 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
);
|
||||
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));
|
||||
_pam_system_log(LOG_ERR,
|
||||
"_pam_init_handlers: error reading %s",
|
||||
filename);
|
||||
_pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]",
|
||||
pam_strerror(pamh, retval));
|
||||
} else {
|
||||
read_something = 1;
|
||||
}
|
||||
@ -348,20 +345,20 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
);
|
||||
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));
|
||||
_pam_system_log(LOG_ERR,
|
||||
"_pam_init_handlers: error reading %s",
|
||||
PAM_DEFAULT_SERVICE_FILE);
|
||||
_pam_system_log(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);
|
||||
_pam_system_log(LOG_ERR,
|
||||
"_pam_init_handlers: no default config %s",
|
||||
PAM_DEFAULT_SERVICE_FILE);
|
||||
}
|
||||
if (!read_something) { /* nothing read successfully */
|
||||
retval = PAM_ABORT;
|
||||
@ -369,9 +366,8 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
}
|
||||
} else {
|
||||
if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR,
|
||||
"_pam_init_handlers: could not open "
|
||||
PAM_CONFIG );
|
||||
_pam_system_log(LOG_ERR, "_pam_init_handlers: could not open "
|
||||
PAM_CONFIG );
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -388,8 +384,7 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
|
||||
if (retval != PAM_SUCCESS) {
|
||||
/* Read error */
|
||||
pam_system_log(pamh, NULL, LOG_ERR,
|
||||
"error reading PAM configuration file");
|
||||
_pam_system_log(LOG_ERR, "error reading PAM configuration file");
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -404,7 +399,7 @@ int _pam_init_handlers(pam_handle_t *pamh)
|
||||
* preceeded by lines of comments and also extended with "\\\n"
|
||||
*/
|
||||
|
||||
int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
|
||||
static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
|
||||
{
|
||||
char *p = buffer;
|
||||
char *s, *os;
|
||||
@ -506,12 +501,20 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
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] != '/') {
|
||||
switch (mod_path != NULL) {
|
||||
default:
|
||||
if (mod_path[0] == '/') {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
if (mod_full_path) {
|
||||
sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
|
||||
mod_path = mod_full_path;
|
||||
break;
|
||||
}
|
||||
_pam_system_log(LOG_CRIT, "cannot malloc full mod path");
|
||||
case 0:
|
||||
mod_path = UNKNOWN_MODULE_PATH;
|
||||
}
|
||||
|
||||
D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
|
||||
@ -533,8 +536,8 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
*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_system_log(LOG_ERR,
|
||||
"realloc returned NULL in _pam_add_handler");
|
||||
_pam_drop(mod_full_path);
|
||||
return PAM_ABORT;
|
||||
}
|
||||
@ -556,10 +559,9 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
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);
|
||||
_pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path);
|
||||
# ifndef PAM_SHL
|
||||
pam_system_log(pamh, NULL, LOG_ERR, "[dlerror: %s]", dlerror());
|
||||
_pam_system_log(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... */
|
||||
@ -579,8 +581,8 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
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);
|
||||
_pam_system_log(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"));
|
||||
@ -595,16 +597,14 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
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);
|
||||
_pam_system_log(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);
|
||||
_pam_system_log(LOG_ERR, "no memory for module path", mod_path);
|
||||
success = PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -693,9 +693,9 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
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);
|
||||
_pam_system_log(LOG_ERR,
|
||||
"internal error: module library type not known: %s;%d",
|
||||
sym, mod->type);
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -710,15 +710,13 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
(func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
|
||||
# endif /* PAM_SHL */
|
||||
) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
|
||||
sym);
|
||||
_pam_system_log(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);
|
||||
_pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym);
|
||||
}
|
||||
#endif
|
||||
if (sym2) {
|
||||
@ -731,16 +729,14 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
(func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
|
||||
# endif /* PAM_SHL */
|
||||
) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
|
||||
sym2);
|
||||
_pam_system_log(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);
|
||||
_pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -753,14 +749,15 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
}
|
||||
|
||||
if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
|
||||
pam_system_log(pamh, NULL, LOG_CRIT,
|
||||
"cannot malloc struct handler #1");
|
||||
_pam_system_log(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)->cached_retval = -1; /* error */
|
||||
(*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
|
||||
(*handler_p)->argc = argc;
|
||||
(*handler_p)->argv = argv; /* not a copy */
|
||||
(*handler_p)->next = NULL;
|
||||
@ -773,19 +770,20 @@ int _pam_add_handler(pam_handle_t *pamh
|
||||
}
|
||||
|
||||
if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
|
||||
pam_system_log(pamh, NULL, LOG_CRIT,
|
||||
"cannot malloc struct handler #2");
|
||||
_pam_system_log(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)->cached_retval = -1; /* ignored */
|
||||
/* Note, this next entry points to the handler_p value! */
|
||||
(*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
|
||||
(*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");
|
||||
_pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2");
|
||||
return (PAM_ABORT);
|
||||
}
|
||||
memcpy((*handler_p2)->argv, argv, argvlen);
|
||||
@ -816,11 +814,13 @@ int _pam_free_handlers(pam_handle_t *pamh)
|
||||
D(("_pam_free_handlers: dlclose(%s)", mod->name));
|
||||
free(mod->name);
|
||||
#ifdef PAM_DYNAMIC
|
||||
if (mod->type == PAM_MT_DYNAMIC_MOD) {
|
||||
# ifdef PAM_SHL
|
||||
if (mod->type == PAM_MT_DYNAMIC_MOD) shl_unload(mod->dl_handle);
|
||||
shl_unload(mod->dl_handle);
|
||||
# else
|
||||
if (mod->type == PAM_MT_DYNAMIC_MOD) dlclose(mod->dl_handle);
|
||||
dlclose(mod->dl_handle);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
mod++;
|
||||
pamh->handlers.modules_used--;
|
||||
|
@ -1,9 +1,7 @@
|
||||
/* pam_item.c */
|
||||
|
||||
/*
|
||||
* $Id: pam_item.c,v 1.8 1997/02/15 15:58:49 morgan Exp morgan $
|
||||
*
|
||||
* $Log: pam_item.c,v $
|
||||
* $Id: pam_item.c,v 1.3 2001/01/22 06:07:28 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@ -23,12 +21,13 @@
|
||||
} \
|
||||
}
|
||||
|
||||
/* handy version id */
|
||||
|
||||
unsigned int __libpam_version = LIBPAM_VERSION;
|
||||
|
||||
/* functions */
|
||||
|
||||
int pam_set_item (
|
||||
pam_handle_t *pamh,
|
||||
int item_type,
|
||||
const void *item)
|
||||
int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@ -39,6 +38,7 @@ int pam_set_item (
|
||||
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.
|
||||
@ -51,57 +51,72 @@ int pam_set_item (
|
||||
*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_);
|
||||
/*
|
||||
* PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
|
||||
* modules.
|
||||
*/
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
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_);
|
||||
}
|
||||
} else {
|
||||
retval = PAM_BAD_ITEM;
|
||||
}
|
||||
|
||||
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_);
|
||||
/*
|
||||
* PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
|
||||
* modules.
|
||||
*/
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
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_);
|
||||
}
|
||||
} else {
|
||||
retval = PAM_BAD_ITEM;
|
||||
}
|
||||
|
||||
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");
|
||||
_pam_system_log(LOG_ERR,
|
||||
"pam_set_item: attempt to set conv() to NULL");
|
||||
retval = PAM_PERM_DENIED;
|
||||
} else {
|
||||
struct pam_conv *tconv;
|
||||
@ -109,8 +124,8 @@ int pam_set_item (
|
||||
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");
|
||||
_pam_system_log(LOG_CRIT,
|
||||
"pam_set_item: malloc failed for pam_conv");
|
||||
retval = PAM_BUF_ERR;
|
||||
} else {
|
||||
memcpy(tconv, item, sizeof(struct pam_conv));
|
||||
@ -119,48 +134,28 @@ int pam_set_item (
|
||||
}
|
||||
}
|
||||
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);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int pam_get_item (
|
||||
const pam_handle_t *pamh,
|
||||
int item_type,
|
||||
const void **item)
|
||||
int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
|
||||
{
|
||||
int retval = PAM_SUCCESS;
|
||||
|
||||
D(("called."));
|
||||
IF_NO_PAMH("pam_get_item",pamh,PAM_SYSTEM_ERR);
|
||||
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");
|
||||
_pam_system_log(LOG_ERR,
|
||||
"pam_get_item: nowhere to place requested item");
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
@ -168,46 +163,72 @@ int pam_get_item (
|
||||
case PAM_SERVICE:
|
||||
*item = pamh->service_name;
|
||||
break;
|
||||
|
||||
case PAM_USER:
|
||||
D(("returning user=%s", pamh->user));
|
||||
*item = pamh->user;
|
||||
break;
|
||||
|
||||
case PAM_USER_PROMPT:
|
||||
D(("returning userprompt=%s", pamh->user));
|
||||
*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;
|
||||
/*
|
||||
* PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
|
||||
* modules.
|
||||
*/
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
*item = pamh->authtok;
|
||||
} else {
|
||||
retval = PAM_BAD_ITEM;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAM_OLDAUTHTOK:
|
||||
*item = pamh->oldauthtok;
|
||||
/*
|
||||
* PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
|
||||
* modules.
|
||||
*/
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
*item = pamh->oldauthtok;
|
||||
} else {
|
||||
retval = PAM_BAD_ITEM;
|
||||
}
|
||||
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;
|
||||
retval = PAM_BAD_ITEM;
|
||||
}
|
||||
|
||||
return PAM_SUCCESS;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* added by AGM 1996/3/2 */
|
||||
/*
|
||||
* This function is the 'preferred method to obtain the username'.
|
||||
*/
|
||||
|
||||
int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
|
||||
{
|
||||
@ -220,14 +241,12 @@ int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
|
||||
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");
|
||||
_pam_system_log(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");
|
||||
_pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username");
|
||||
return PAM_PERM_DENIED;
|
||||
} else
|
||||
*user = NULL;
|
||||
@ -251,7 +270,7 @@ int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
|
||||
if (pamh->former.want_user) {
|
||||
/* must have a prompt to resume with */
|
||||
if (! pamh->former.prompt) {
|
||||
pam_system_log(pamh, NULL, LOG_ERR,
|
||||
_pam_system_log(LOG_ERR,
|
||||
"pam_get_user: failed to resume with prompt"
|
||||
);
|
||||
return PAM_ABORT;
|
||||
@ -259,8 +278,8 @@ int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
|
||||
|
||||
/* 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");
|
||||
_pam_system_log(LOG_ERR,
|
||||
"pam_get_user: resumed with different prompt");
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
@ -309,5 +328,6 @@ int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
|
||||
_pam_drop_reply(resp, 1);
|
||||
}
|
||||
|
||||
D(("completed"));
|
||||
return retval; /* pass on any error from conversation */
|
||||
}
|
||||
|
@ -1,13 +1,5 @@
|
||||
/*
|
||||
* $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
|
||||
*
|
||||
* $Id: pam_malloc.c,v 1.3 2000/12/04 19:02:34 baggins Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -52,7 +44,7 @@
|
||||
* default debugging level
|
||||
*/
|
||||
|
||||
int pam_malloc_flags = PAM_MALLOC_DEFAULT;
|
||||
int pam_malloc_flags = PAM_MALLOC_ALL;
|
||||
int pam_malloc_delay_length = 4;
|
||||
|
||||
#define on(x) ((pam_malloc_flags&(x))==(x))
|
||||
@ -80,18 +72,27 @@ static void set_last_(const char *x, const char *f
|
||||
static void _pam_output_xdebug_info(void)
|
||||
{
|
||||
FILE *logfile;
|
||||
int must_close = 1;
|
||||
|
||||
if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
int must_close = 1, fd;
|
||||
|
||||
#ifdef O_NOFOLLOW
|
||||
if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) {
|
||||
#else
|
||||
if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) {
|
||||
#endif
|
||||
if (!(logfile = fdopen(fd,"a"))) {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
logfile = stderr;
|
||||
must_close = 0;
|
||||
}
|
||||
fprintf(logfile, "[%s:%s(%d)->%s()] ",
|
||||
last_file, last_call, last_line, last_fn);
|
||||
if (must_close) {
|
||||
fflush(logfile);
|
||||
fflush(logfile);
|
||||
if (must_close)
|
||||
fclose(logfile);
|
||||
}
|
||||
}
|
||||
|
||||
static void hinder(void)
|
||||
|
@ -1,11 +1,10 @@
|
||||
/* pam_map.c - PAM mapping interface
|
||||
*
|
||||
* $Id$
|
||||
* $Id: pam_map.c,v 1.2 2000/12/04 19:02:34 baggins Exp $
|
||||
*
|
||||
* 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>
|
||||
|
@ -1,35 +1,7 @@
|
||||
/* 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
|
||||
*
|
||||
/*
|
||||
* $Id: pam_misc.c,v 1.2 2001/01/22 06:07:29 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
@ -125,8 +97,7 @@ char *_pam_strdup(const char *x)
|
||||
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");
|
||||
_pam_system_log(LOG_CRIT, "_pam_strdup: failed to get memory");
|
||||
} else {
|
||||
while (i-- > 0) {
|
||||
new[i] = x[i];
|
||||
@ -160,15 +131,15 @@ int _pam_mkargv(char *s, char ***argv, int *argc)
|
||||
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");
|
||||
_pam_system_log(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");
|
||||
_pam_system_log(LOG_CRIT,
|
||||
"pam_mkargv: null returned by malloc");
|
||||
} else {
|
||||
char *tmp=NULL;
|
||||
|
||||
@ -206,11 +177,15 @@ int _pam_mkargv(char *s, char ***argv, int *argc)
|
||||
|
||||
void _pam_sanitize(pam_handle_t *pamh)
|
||||
{
|
||||
int old_caller_is = pamh->caller_is;
|
||||
|
||||
/*
|
||||
* this is for security. We reset the auth-tokens here.
|
||||
*/
|
||||
pam_set_item(pamh,PAM_AUTHTOK,NULL);
|
||||
pam_set_item(pamh,PAM_OLDAUTHTOK,NULL);
|
||||
__PAM_TO_MODULE(pamh);
|
||||
pam_set_item(pamh, PAM_AUTHTOK, NULL);
|
||||
pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
|
||||
pamh->caller_is = old_caller_is;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -247,7 +222,7 @@ void _pam_parse_control(int *control_array, char *tok)
|
||||
int act, len;
|
||||
|
||||
/* skip leading space */
|
||||
while (isspace(*tok) && *++tok);
|
||||
while (isspace((int)*tok) && *++tok);
|
||||
if (!*tok)
|
||||
break;
|
||||
|
||||
@ -264,21 +239,21 @@ void _pam_parse_control(int *control_array, char *tok)
|
||||
}
|
||||
|
||||
/* observe '=' */
|
||||
while (isspace(*tok) && *++tok);
|
||||
while (isspace((int)*tok) && *++tok);
|
||||
if (!*tok || *tok++ != '=') {
|
||||
error = "expecting '='";
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
/* skip leading space */
|
||||
while (isspace(*tok) && *++tok);
|
||||
while (isspace((int)*tok) && *++tok);
|
||||
if (!*tok) {
|
||||
error = "expecting action";
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
/* observe action type */
|
||||
for (act=0; act<=-_PAM_ACTION_UNDEF; ++act) {
|
||||
for (act=0; act < (-(_PAM_ACTION_UNDEF)); ++act) {
|
||||
len = strlen(_pam_token_actions[act]);
|
||||
if (!strncmp(_pam_token_actions[act], tok, len)) {
|
||||
act *= -1;
|
||||
@ -296,7 +271,7 @@ void _pam_parse_control(int *control_array, char *tok)
|
||||
* cause looping problems. So, for now, we will just
|
||||
* allow forward jumps. (AGM 1998/1/7)
|
||||
*/
|
||||
if (!isdigit(*tok)) {
|
||||
if (!isdigit((int)*tok)) {
|
||||
error = "expecting jump number";
|
||||
goto parse_error;
|
||||
}
|
||||
@ -305,7 +280,7 @@ void _pam_parse_control(int *control_array, char *tok)
|
||||
do {
|
||||
act *= 10;
|
||||
act += *tok - '0'; /* XXX - this assumes ascii behavior */
|
||||
} while (*++tok && isdigit(*tok));
|
||||
} while (*++tok && isdigit((int)*tok));
|
||||
if (! act) {
|
||||
/* we do not allow 0 jumps. There is a token ('ignore')
|
||||
for that */
|
||||
@ -328,7 +303,7 @@ void _pam_parse_control(int *control_array, char *tok)
|
||||
|
||||
parse_error:
|
||||
/* treat everything as bad */
|
||||
pam_system_log(NULL, NULL, LOG_ERR, "pam_parse: %s; [...%s]", error, tok);
|
||||
_pam_system_log(LOG_ERR, "pam_parse: %s; [...%s]", error, tok);
|
||||
for (ret=0; ret<_PAM_RETURN_VALUES; control_array[ret++]=_PAM_ACTION_BAD);
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
/* 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 $
|
||||
* $Id: pam_password.c,v 1.2 2001/01/22 06:07:29 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include "pam_private.h"
|
||||
|
||||
int pam_chauthtok(pam_handle_t *pamh, int flags)
|
||||
@ -19,6 +19,11 @@ int pam_chauthtok(pam_handle_t *pamh, int flags)
|
||||
|
||||
IF_NO_PAMH("pam_chauthtok", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return 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
|
||||
@ -27,10 +32,11 @@ int pam_chauthtok(pam_handle_t *pamh, int flags)
|
||||
pamh->former.update = PAM_FALSE;
|
||||
}
|
||||
|
||||
/* first loop through to check if there will be a problem */
|
||||
/* first call to check if there will be a problem */
|
||||
if (pamh->former.update ||
|
||||
(retval = _pam_dispatch(pamh, flags|PAM_PRELIM_CHECK,
|
||||
PAM_CHAUTHTOK)) == PAM_SUCCESS) {
|
||||
D(("completed check ok: former=%d", pamh->former.update));
|
||||
pamh->former.update = PAM_TRUE;
|
||||
retval = _pam_dispatch(pamh, flags|PAM_UPDATE_AUTHTOK,
|
||||
PAM_CHAUTHTOK);
|
||||
@ -41,9 +47,9 @@ int pam_chauthtok(pam_handle_t *pamh, int flags)
|
||||
_pam_sanitize(pamh);
|
||||
pamh->former.update = PAM_FALSE;
|
||||
_pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
|
||||
D(("pam_authenticate exit"));
|
||||
D(("pam_chauthtok exit %d - %d", retval, pamh->former.choice));
|
||||
} else {
|
||||
D(("will resume when ready"));
|
||||
D(("will resume when ready", retval));
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* pam_private.h
|
||||
*
|
||||
* $Id: pam_private.h,v 1.12 1997/04/05 06:57:37 morgan Exp morgan $
|
||||
* $Id: pam_private.h,v 1.4 2001/02/05 06:50:41 agmorgan Exp $
|
||||
*
|
||||
* This is the Linux-PAM Library Private Header. It contains things
|
||||
* internal to the Linux-PAM library. Things not needed by either an
|
||||
@ -10,16 +10,16 @@
|
||||
* Please see end of file for copyright.
|
||||
*
|
||||
* Creator: Marc Ewing.
|
||||
* Maintained: AGM
|
||||
*
|
||||
* $Log: pam_private.h,v $
|
||||
* Maintained: CVS
|
||||
*/
|
||||
|
||||
#ifndef _PAM_PRIVATE_H
|
||||
#define _PAM_PRIVATE_H
|
||||
|
||||
#include <security/_pam_aconf.h>
|
||||
|
||||
/* this is not used at the moment --- AGM */
|
||||
#define LIBPAM_VERSION 65
|
||||
#define LIBPAM_VERSION (LIBPAM_VERSION_MAJOR*0x100 + LIBPAM_VERSION_MINOR)
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_modules.h>
|
||||
@ -47,6 +47,9 @@ struct handler {
|
||||
int must_fail;
|
||||
int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv);
|
||||
int actions[_PAM_RETURN_VALUES];
|
||||
/* set by authenticate, open_session, chauthtok(1st)
|
||||
consumed by setcred, close_session, chauthtok(2nd) */
|
||||
int cached_retval; int *cached_retval_p;
|
||||
int argc;
|
||||
char **argv;
|
||||
struct handler *next;
|
||||
@ -126,6 +129,7 @@ struct _pam_former_state {
|
||||
|
||||
struct pam_handle {
|
||||
char *authtok;
|
||||
unsigned caller_is;
|
||||
struct pam_conv *pam_conversation;
|
||||
char *oldauthtok;
|
||||
char *prompt; /* for use by pam_get_user() */
|
||||
@ -134,7 +138,6 @@ struct pam_handle {
|
||||
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 */
|
||||
@ -191,8 +194,6 @@ 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
|
||||
@ -207,16 +208,13 @@ 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);
|
||||
struct pam_module * _pam_open_static_handler(const char *path);
|
||||
|
||||
/* Return pointer to function requested from static module */
|
||||
|
||||
@ -250,6 +248,9 @@ void _pam_set_default_control(int *control_array, int default_action);
|
||||
|
||||
void _pam_parse_control(int *control_array, char *tok);
|
||||
|
||||
void _pam_system_log(int priority, const char *format, ... );
|
||||
#define _PAM_SYSTEM_LOG_PREFIX "PAM "
|
||||
|
||||
/*
|
||||
* XXX - Take care with this. It could confuse the logic of a trailing
|
||||
* else
|
||||
@ -257,7 +258,7 @@ void _pam_parse_control(int *control_array, char *tok);
|
||||
|
||||
#define IF_NO_PAMH(X,pamh,ERR) \
|
||||
if ((pamh) == NULL) { \
|
||||
pam_system_log(NULL, NULL, LOG_ERR, X ": NULL pam handle passed"); \
|
||||
_pam_system_log(LOG_ERR, X ": NULL pam handle passed"); \
|
||||
return ERR; \
|
||||
}
|
||||
|
||||
@ -265,25 +266,28 @@ if ((pamh) == NULL) { \
|
||||
|
||||
#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>
|
||||
|
||||
/* used to work out where control currently resides (in an application
|
||||
or in a module) */
|
||||
|
||||
#define _PAM_CALLED_FROM_MODULE 1
|
||||
#define _PAM_CALLED_FROM_APP 2
|
||||
|
||||
#define __PAM_FROM_MODULE(pamh) ((pamh)->caller_is == _PAM_CALLED_FROM_MODULE)
|
||||
#define __PAM_FROM_APP(pamh) ((pamh)->caller_is == _PAM_CALLED_FROM_APP)
|
||||
#define __PAM_TO_MODULE(pamh) \
|
||||
do { (pamh)->caller_is = _PAM_CALLED_FROM_MODULE; } while (0)
|
||||
#define __PAM_TO_APP(pamh) \
|
||||
do { (pamh)->caller_is = _PAM_CALLED_FROM_APP; } while (0)
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995 by Red Hat Software, Marc Ewing
|
||||
* Copyright (c) 1996-8, Andrew G. Morgan <morgan@linux.kernel.org>
|
||||
* Copyright (c) 1996-8,2001 by Andrew G. Morgan <morgan@kernel.org>
|
||||
*
|
||||
* All rights reserved
|
||||
*
|
||||
|
@ -2,9 +2,8 @@
|
||||
* pam_second.c -- PAM secondary authentication
|
||||
* (based on XSSO draft spec of March 1997)
|
||||
*
|
||||
* $Id$
|
||||
* $Id: pam_second.c,v 1.2 2000/12/04 19:02:34 baggins Exp $
|
||||
*
|
||||
* $Log$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -1,17 +1,7 @@
|
||||
/* 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.
|
||||
*
|
||||
*
|
||||
* $Id: pam_session.c,v 1.3 2001/01/22 06:07:29 agmorgan Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -22,7 +12,13 @@ int pam_open_session(pam_handle_t *pamh, int flags)
|
||||
{
|
||||
D(("called"));
|
||||
|
||||
IF_NO_PAMH("pam_open_session",pamh,PAM_SYSTEM_ERR);
|
||||
IF_NO_PAMH("pam_open_session", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
return _pam_dispatch(pamh, flags, PAM_OPEN_SESSION);
|
||||
}
|
||||
|
||||
@ -30,6 +26,12 @@ int pam_close_session(pam_handle_t *pamh, int flags)
|
||||
{
|
||||
D(("called"));
|
||||
|
||||
IF_NO_PAMH("pam_close_session",pamh,PAM_SYSTEM_ERR);
|
||||
IF_NO_PAMH("pam_close_session", pamh, PAM_SYSTEM_ERR);
|
||||
|
||||
if (__PAM_FROM_MODULE(pamh)) {
|
||||
D(("called from module!?"));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
return _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);
|
||||
}
|
||||
|
@ -3,9 +3,8 @@
|
||||
/* Creator Marc Ewing
|
||||
* Maintained by AGM
|
||||
*
|
||||
* $Id: pam_start.c,v 1.10 1997/04/05 06:58:11 morgan Exp $
|
||||
* $Id: pam_start.c,v 1.2 2001/01/22 06:07:29 agmorgan Exp $
|
||||
*
|
||||
* $Log: pam_start.c,v $
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@ -26,17 +25,21 @@ int pam_start (
|
||||
,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");
|
||||
_pam_system_log(LOG_CRIT, "pam_start: calloc failed for *pamh");
|
||||
return (PAM_BUF_ERR);
|
||||
}
|
||||
|
||||
/* Mark the caller as the application - permission to do certain
|
||||
things is limited to a module or an application */
|
||||
|
||||
__PAM_TO_APP(*pamh);
|
||||
|
||||
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_system_log(LOG_CRIT,
|
||||
"pam_start: _pam_strdup failed for service name");
|
||||
_pam_drop(*pamh);
|
||||
return (PAM_BUF_ERR);
|
||||
}
|
||||
@ -47,8 +50,8 @@ int pam_start (
|
||||
|
||||
if (user) {
|
||||
if (((*pamh)->user = _pam_strdup(user)) == NULL) {
|
||||
pam_system_log(NULL, NULL, LOG_CRIT,
|
||||
"pam_start: _pam_strdup failed for user");
|
||||
_pam_system_log(LOG_CRIT,
|
||||
"pam_start: _pam_strdup failed for user");
|
||||
_pam_drop((*pamh)->service_name);
|
||||
_pam_drop(*pamh);
|
||||
return (PAM_BUF_ERR);
|
||||
@ -68,8 +71,7 @@ int pam_start (
|
||||
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_system_log(LOG_CRIT, "pam_start: malloc failed for pam_conv");
|
||||
_pam_drop((*pamh)->service_name);
|
||||
_pam_drop((*pamh)->user);
|
||||
_pam_drop(*pamh);
|
||||
@ -81,8 +83,7 @@ int pam_start (
|
||||
|
||||
(*pamh)->data = NULL;
|
||||
if ( _pam_make_env(*pamh) != PAM_SUCCESS ) {
|
||||
pam_system_log(NULL, NULL, LOG_ERR,
|
||||
"pam_start: failed to initialize environment");
|
||||
_pam_system_log(LOG_ERR,"pam_start: failed to initialize environment");
|
||||
_pam_drop((*pamh)->service_name);
|
||||
_pam_drop((*pamh)->user);
|
||||
_pam_drop(*pamh);
|
||||
@ -96,21 +97,15 @@ int pam_start (
|
||||
/* 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_system_log(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;
|
||||
|
@ -1,20 +1,7 @@
|
||||
/* 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 ;)
|
||||
*
|
||||
/*
|
||||
* $Id: pam_strerror.c,v 1.2 2000/12/04 19:02:34 baggins Exp $
|
||||
*/
|
||||
|
||||
#include "pam_private.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* pam_tokens.h
|
||||
*
|
||||
* $Id$
|
||||
* $Id: pam_tokens.h,v 1.3 2001/01/22 06:07:29 agmorgan Exp $
|
||||
*
|
||||
* This is a Linux-PAM Library Private Header file. It contains tokens
|
||||
* that are used when we parse the configuration file(s).
|
||||
@ -9,8 +9,7 @@
|
||||
* Please see end of file for copyright.
|
||||
*
|
||||
* Creator: Andrew Morgan.
|
||||
*
|
||||
* $Log$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PAM_TOKENS_H
|
||||
@ -60,13 +59,15 @@ const char * const _pam_token_returns[_PAM_RETURN_VALUES+1] = {
|
||||
"authtok_expired", /* 27 */
|
||||
"module_unknown", /* 28 */
|
||||
"bad_item", /* 29 */
|
||||
"conv_again", /* 30 */
|
||||
"incomplete", /* 31 */
|
||||
/* 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>
|
||||
* Copyright (C) 1998,2001 Andrew G. Morgan <morgan@kernel.org>
|
||||
*
|
||||
* All rights reserved
|
||||
*
|
||||
|
@ -1,109 +1,106 @@
|
||||
# $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
|
||||
# $Id: Makefile,v 1.3 2001/02/10 07:17:53 agmorgan Exp $
|
||||
#
|
||||
|
||||
dummy:
|
||||
@echo "*** This is not a top-level Makefile!"
|
||||
# lots of debugging information goes to /tmp/pam-debug.log
|
||||
#MOREFLAGS += -D"DEBUG"
|
||||
|
||||
# ///////////////////////////////////////////////////////////////////
|
||||
include ../Make.Rules
|
||||
|
||||
# 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
|
||||
ifeq ($(WITH_LIBDEBUG),yes)
|
||||
LIBNAME=libpam_miscd
|
||||
else
|
||||
LIBNAME=pam_misc
|
||||
LIBNAME=libpam_misc
|
||||
endif
|
||||
LIBMAJOR=$(MAJOR_REL)
|
||||
LIBMINOR=$(MINOR_REL)
|
||||
VERSION=.$(MAJOR_REL)
|
||||
MODIFICATION=.$(MINOR_REL)
|
||||
|
||||
FILES=misc_conv help_env
|
||||
CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC)
|
||||
|
||||
#
|
||||
# Probably no need to alter anything below here.
|
||||
#
|
||||
# dynamic library names
|
||||
|
||||
# build dynamic library names
|
||||
|
||||
LIBDYNAMIC=lib$(LIBNAME).$(DYNTYPE)
|
||||
LIBDYNMAJ=$(LIBDYNAMIC).$(LIBMAJOR)
|
||||
LIBDYNMIN=$(LIBDYNMAJ).$(LIBMINOR)
|
||||
LIBNAMED = $(LIBNAME).$(DYNTYPE)
|
||||
LIBNAMEDNAME = $(LIBNAMED)$(VERSION)
|
||||
LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION)
|
||||
|
||||
# static library name
|
||||
|
||||
LIBSTATIC = lib$(LIBNAME).a
|
||||
LIBNAMEDSTATIC = $(LIBNAME).a
|
||||
|
||||
# sources and object files
|
||||
LIBOBJECTS = help_env.o misc_conv.o
|
||||
|
||||
LIBSRC = $(addsuffix .c,$(FILES))
|
||||
LIBOBJ = $(addsuffix .o,$(FILES))
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS))
|
||||
endif
|
||||
|
||||
# rules
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS))
|
||||
endif
|
||||
|
||||
all: $(LIBSTATIC) $(LIBDYNAMIC)
|
||||
# ---------------------------------------------
|
||||
## rules
|
||||
|
||||
$(LIBDYNAMIC): $(LIBOBJ)
|
||||
ifdef MAKE_DYNAMIC
|
||||
all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC)
|
||||
|
||||
dirs:
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
$(MKDIR) dynamic
|
||||
endif
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(MKDIR) static
|
||||
endif
|
||||
|
||||
dynamic/%.o : %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
|
||||
static/%.o : %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
|
||||
$(LIBNAMED): $(DLIBOBJECTS)
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
ifeq ($(USESONAME),yes)
|
||||
$(LD_L) $(SOSWITCH) $(LIBDYNMAJ) -o $@ $(LIBOBJ)
|
||||
$(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
|
||||
else
|
||||
$(LD_L) -o $@ $(LIBOBJ)
|
||||
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
|
||||
endif
|
||||
ifeq ($(NEEDSONAME),yes)
|
||||
rm -f $(LIBDYNMIN)
|
||||
ln -s $(LIBDYNAMIC) $(LIBDYNMAJ)
|
||||
rm -f $(LIBDYNMAJ)
|
||||
ln -s $(LIBDYNAMIC) $(LIBDYNMIN)
|
||||
rm -f $(LIBNAMEDFULL)
|
||||
ln -s $(LIBNAMED) $(LIBNAMEDFULL)
|
||||
rm -f $(LIBNAMEDNAME)
|
||||
ln -s $(LIBNAMED) $(LIBNAMEDNAME)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(LIBSTATIC): $(LIBOBJ)
|
||||
$(AR) $@ $(LIBOBJ)
|
||||
$(LIBNAMEDSTATIC): $(SLIBOBJECTS)
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(AR) rc $@ $(SLIBOBJECTS) $(MODULES)
|
||||
$(RANLIB) $@
|
||||
endif
|
||||
|
||||
install: all
|
||||
$(MKDIR) $(FAKEROOT)$(INCLUDED)
|
||||
$(INSTALL) -m 644 ./pam_misc.h $(FAKEROOT)$(INCLUDED)
|
||||
ifdef MAKE_DYNAMIC
|
||||
$(INSTALL) -m $(SHLIBMODE) $(LIBDYNAMIC) $(FAKEROOT)$(LIBDIR)/$(LIBDYNMIN)
|
||||
$(INSTALL) -m 644 include/security/pam_misc.h $(FAKEROOT)$(INCLUDED)
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
$(MKDIR) $(FAKEROOT)$(libdir)
|
||||
$(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL)
|
||||
$(LDCONFIG)
|
||||
ifneq ($(DYNTYPE),"sl")
|
||||
( cd $(FAKEROOT)$(LIBDIR) ; ln -sf $(LIBDYNMAJ) $(LIBDYNAMIC) )
|
||||
( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) )
|
||||
endif
|
||||
endif
|
||||
$(INSTALL) -m 644 $(LIBSTATIC) $(FAKEROOT)$(LIBDIR)
|
||||
|
||||
clean:
|
||||
rm -f *.so *.a core a.out *~
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir)
|
||||
endif
|
||||
|
||||
remove:
|
||||
rm -f $(FAKEROOT)$(INCLUDED)/pam_misc.h
|
||||
rm -f $(FAKEROOT)$(LIBDIR)/$(LIBDYNAMIC).*
|
||||
rm -f $(FAKEROOT)$(LIBDIR)/$(LIBDYNAMIC)
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL)
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED)
|
||||
$(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
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC)
|
||||
|
||||
clean:
|
||||
rm -f a.out core *~ static/*.o dynamic/*.o
|
||||
rm -f *.a *.out *.o *.so ./include/security/*~
|
||||
if [ -d dynamic ]; then rmdir dynamic ; fi
|
||||
if [ -d static ]; then rmdir static ; fi
|
||||
|
@ -1,15 +1,8 @@
|
||||
/*
|
||||
* $Id: help_env.c,v 1.2 1997/01/04 20:19:20 morgan Exp morgan $
|
||||
* $Id: help_env.c,v 1.2 2000/12/04 19:02:34 baggins Exp $
|
||||
*
|
||||
* 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>
|
||||
|
57
contrib/libpam/libpam_misc/include/security/pam_misc.h
Normal file
57
contrib/libpam/libpam_misc/include/security/pam_misc.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* $Id: pam_misc.h,v 1.3 2001/01/20 22:29:47 agmorgan Exp $ */
|
||||
|
||||
#ifndef __PAMMISC_H
|
||||
#define __PAMMISC_H
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_client.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)(void *appdata, pamc_bp_t *prompt_p);
|
||||
extern void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p);
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
|
@ -1,32 +1,12 @@
|
||||
/*
|
||||
* $Id: misc_conv.c,v 1.5 1997/01/04 20:16:48 morgan Exp morgan $
|
||||
* $Id: misc_conv.c,v 1.3 2001/01/20 22:29:47 agmorgan Exp $
|
||||
*
|
||||
* 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 <security/_pam_aconf.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
@ -57,39 +37,23 @@ 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;
|
||||
/*
|
||||
* These functions are for binary prompt manipulation.
|
||||
* The manner in which a binary prompt is processed is application
|
||||
* specific, so these function pointers are provided and can be
|
||||
* initialized by the application prior to the conversation function
|
||||
* being used.
|
||||
*/
|
||||
|
||||
length = 4+(packet[0]<<24)+(packet[1]<<16)+(packet[2]<<8)+packet[3];
|
||||
memset(packet, 0, length);
|
||||
free(packet);
|
||||
*delete_me = packet = NULL;
|
||||
}
|
||||
static void pam_misc_conv_delete_binary(void *appdata,
|
||||
pamc_bp_t *delete_me)
|
||||
{
|
||||
PAM_BP_RENEW(delete_me, 0, 0);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p) = NULL;
|
||||
void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p)
|
||||
= pam_misc_conv_delete_binary;
|
||||
|
||||
/* the following code is used to get text input */
|
||||
|
||||
@ -293,26 +257,26 @@ int misc_conv(int num_msg, const struct pam_message **msgm,
|
||||
break;
|
||||
case PAM_BINARY_PROMPT:
|
||||
{
|
||||
void *pack_out=NULL;
|
||||
const void *pack_in = msgm[count]->msg;
|
||||
pamc_bp_t binary_prompt = NULL;
|
||||
|
||||
if (!pam_binary_handler_fn
|
||||
|| pam_binary_handler_fn(pack_in, &pack_out) != PAM_SUCCESS
|
||||
|| pack_out == NULL) {
|
||||
if (!msgm[count]->msg || !pam_binary_handler_fn) {
|
||||
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) {
|
||||
PAM_BP_RENEW(&binary_prompt,
|
||||
PAM_BP_RCONTROL(msgm[count]->msg),
|
||||
PAM_BP_LENGTH(msgm[count]->msg));
|
||||
PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg),
|
||||
PAM_BP_RDATA(msgm[count]->msg));
|
||||
|
||||
if (pam_binary_handler_fn(appdata_ptr,
|
||||
&binary_prompt) != PAM_SUCCESS
|
||||
|| (binary_prompt == NULL)) {
|
||||
goto failed_conversation;
|
||||
}
|
||||
string = (char *) binary_prompt;
|
||||
binary_prompt = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -351,11 +315,11 @@ int misc_conv(int num_msg, const struct pam_message **msgm,
|
||||
free(reply[count].resp);
|
||||
break;
|
||||
case PAM_BINARY_PROMPT:
|
||||
pam_binary_handler_free((void **) &reply[count].resp);
|
||||
pam_binary_handler_free(appdata_ptr,
|
||||
(pamc_bp_t *) &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);
|
||||
}
|
||||
|
42
contrib/libpam/libpamc/License
Normal file
42
contrib/libpam/libpamc/License
Normal file
@ -0,0 +1,42 @@
|
||||
Unless otherwise *explicitly* stated the following text describes the
|
||||
licensed conditions under which the contents of this libpamc release
|
||||
may be distributed:
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms of libpamc,
|
||||
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 Library General Public License (LGPL), in which case the
|
||||
provisions of the GNU LGPL are required INSTEAD OF the above
|
||||
restrictions. (This clause is necessary due to a potential conflict
|
||||
between the GNU LGPL 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.
|
||||
-------------------------------------------------------------------------
|
||||
|
107
contrib/libpam/libpamc/Makefile
Normal file
107
contrib/libpam/libpamc/Makefile
Normal file
@ -0,0 +1,107 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.3 2001/02/10 07:17:53 agmorgan Exp $
|
||||
#
|
||||
|
||||
# lots of debugging information goes to /tmp/pam-debug.log
|
||||
#MOREFLAGS += -D"DEBUG"
|
||||
|
||||
include ../Make.Rules
|
||||
|
||||
ifeq ($(DEBUG_REL),yes)
|
||||
LIBNAME=libpamcd
|
||||
else
|
||||
LIBNAME=libpamc
|
||||
endif
|
||||
VERSION=.$(MAJOR_REL)
|
||||
MODIFICATION=.$(MINOR_REL)
|
||||
|
||||
CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC)
|
||||
|
||||
# dynamic library names
|
||||
|
||||
LIBNAMED = $(LIBNAME).$(DYNTYPE)
|
||||
LIBNAMEDNAME = $(LIBNAMED)$(VERSION)
|
||||
LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION)
|
||||
|
||||
# static library name
|
||||
|
||||
LIBNAMEDSTATIC = $(LIBNAME).a
|
||||
|
||||
LIBOBJECTS = pamc_client.o pamc_converse.o pamc_load.o
|
||||
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS))
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS))
|
||||
endif
|
||||
|
||||
# ---------------------------------------------
|
||||
## rules
|
||||
|
||||
all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC)
|
||||
|
||||
dirs:
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
$(MKDIR) dynamic
|
||||
endif
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(MKDIR) static
|
||||
endif
|
||||
|
||||
dynamic/%.o : %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
|
||||
static/%.o : %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
|
||||
|
||||
$(LIBNAMED): $(DLIBOBJECTS)
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
ifeq ($(USESONAME),yes)
|
||||
$(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
|
||||
else
|
||||
$(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
|
||||
endif
|
||||
ifeq ($(NEEDSONAME),yes)
|
||||
rm -f $(LIBNAMEDFULL)
|
||||
ln -s $(LIBNAMED) $(LIBNAMEDFULL)
|
||||
rm -f $(LIBNAMEDNAME)
|
||||
ln -s $(LIBNAMED) $(LIBNAMEDNAME)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(LIBNAMEDSTATIC): $(SLIBOBJECTS)
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(AR) rc $@ $(SLIBOBJECTS) $(MODULES)
|
||||
$(RANLIB) $@
|
||||
endif
|
||||
|
||||
install: all
|
||||
$(MKDIR) $(FAKEROOT)$(INCLUDED)
|
||||
$(INSTALL) -m 644 include/security/pam_client.h $(FAKEROOT)$(INCLUDED)
|
||||
ifeq ($(DYNAMIC_LIBPAM),yes)
|
||||
$(MKDIR) $(FAKEROOT)$(libdir)
|
||||
$(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL)
|
||||
$(LDCONFIG)
|
||||
ifneq ($(DYNTYPE),"sl")
|
||||
( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) )
|
||||
endif
|
||||
endif
|
||||
ifeq ($(STATIC_LIBPAM),yes)
|
||||
$(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir)
|
||||
endif
|
||||
|
||||
remove:
|
||||
rm -f $(FAKEROOT)$(INCLUDED)/pam_client.h
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL)
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED)
|
||||
$(LDCONFIG)
|
||||
rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC)
|
||||
|
||||
clean:
|
||||
rm -f a.out core *~ static/*.o dynamic/*.o
|
||||
rm -f *.a *.out *.o *.so ./include/security/*~
|
||||
if [ -d dynamic ]; then rmdir dynamic ; fi
|
||||
if [ -d static ]; then rmdir static ; fi
|
||||
|
190
contrib/libpam/libpamc/include/security/pam_client.h
Normal file
190
contrib/libpam/libpamc/include/security/pam_client.h
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* $Id: pam_client.h,v 1.4 2001/01/20 22:29:47 agmorgan Exp $
|
||||
*
|
||||
* Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org>
|
||||
*
|
||||
* This header file provides the prototypes for the PAM client API
|
||||
*/
|
||||
|
||||
#ifndef PAM_CLIENT_H
|
||||
#define PAM_CLIENT_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* opaque agent handling structure */
|
||||
|
||||
typedef struct pamc_handle_s *pamc_handle_t;
|
||||
|
||||
/* binary prompt structure pointer */
|
||||
#ifndef __u32
|
||||
# define __u32 unsigned int
|
||||
#endif
|
||||
#ifndef __u8
|
||||
# define __u8 unsigned char
|
||||
#endif
|
||||
typedef struct { __u32 length; __u8 control; } *pamc_bp_t;
|
||||
|
||||
/*
|
||||
* functions provided by libpamc
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize the agent abstraction library
|
||||
*/
|
||||
|
||||
pamc_handle_t pamc_start(void);
|
||||
|
||||
/*
|
||||
* Terminate the authentication process
|
||||
*/
|
||||
|
||||
int pamc_end(pamc_handle_t *pch);
|
||||
|
||||
/*
|
||||
* force the loading of a specified agent
|
||||
*/
|
||||
|
||||
int pamc_load(pamc_handle_t pch, const char *agent_id);
|
||||
|
||||
/*
|
||||
* Single conversation interface for binary prompts
|
||||
*/
|
||||
|
||||
int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p);
|
||||
|
||||
/*
|
||||
* disable an agent
|
||||
*/
|
||||
|
||||
int pamc_disable(pamc_handle_t pch, const char *agent_id);
|
||||
|
||||
/*
|
||||
* obtain a list of available agents
|
||||
*/
|
||||
|
||||
char **pamc_list_agents(pamc_handle_t pch);
|
||||
|
||||
/*
|
||||
* PAM_BP_ MACROS for creating, destroying and manipulating binary prompts
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef PAM_BP_ASSERT
|
||||
# define PAM_BP_ASSERT(x) do { printf(__FILE__ "(%d): %s\n", \
|
||||
__LINE__, x) ; exit(1); } while (0)
|
||||
#endif /* PAM_BP_ASSERT */
|
||||
|
||||
#ifndef PAM_BP_CALLOC
|
||||
# define PAM_BP_CALLOC calloc
|
||||
#endif /* PAM_BP_CALLOC */
|
||||
|
||||
#ifndef PAM_BP_FREE
|
||||
# define PAM_BP_FREE free
|
||||
#endif /* PAM_BP_FREE */
|
||||
|
||||
#define __PAM_BP_WOCTET(x,y) (*((y) + (__u8 *)(x)))
|
||||
#define __PAM_BP_ROCTET(x,y) (*((y) + (const __u8 *)(x)))
|
||||
|
||||
#define PAM_BP_MIN_SIZE (sizeof(__u32) + sizeof(__u8))
|
||||
#define PAM_BP_MAX_LENGTH 0x20000 /* an advisory limit */
|
||||
#define PAM_BP_WCONTROL(x) (__PAM_BP_WOCTET(x,4))
|
||||
#define PAM_BP_RCONTROL(x) (__PAM_BP_ROCTET(x,4))
|
||||
#define PAM_BP_SIZE(x) ((__PAM_BP_ROCTET(x,0)<<24)+ \
|
||||
(__PAM_BP_ROCTET(x,1)<<16)+ \
|
||||
(__PAM_BP_ROCTET(x,2)<< 8)+ \
|
||||
(__PAM_BP_ROCTET(x,3) ))
|
||||
#define PAM_BP_LENGTH(x) (PAM_BP_SIZE(x) - PAM_BP_MIN_SIZE)
|
||||
#define PAM_BP_WDATA(x) (PAM_BP_MIN_SIZE + (__u8 *) (x))
|
||||
#define PAM_BP_RDATA(x) (PAM_BP_MIN_SIZE + (const __u8 *) (x))
|
||||
|
||||
/* Note, this macro always '\0' terminates renewed packets */
|
||||
|
||||
#define PAM_BP_RENEW(old_p, cntrl, data_length) \
|
||||
do { \
|
||||
if (old_p) { \
|
||||
if (*(old_p)) { \
|
||||
__u32 __size; \
|
||||
__size = PAM_BP_SIZE(*(old_p)); \
|
||||
memset(*(old_p), 0, __size); \
|
||||
PAM_BP_FREE(*(old_p)); \
|
||||
} \
|
||||
if (cntrl) { \
|
||||
__u32 __size; \
|
||||
\
|
||||
__size = PAM_BP_MIN_SIZE + data_length; \
|
||||
if ((*(old_p) = PAM_BP_CALLOC(1, 1+__size))) { \
|
||||
__PAM_BP_WOCTET(*(old_p), 3) = __size & 0xFF; \
|
||||
__PAM_BP_WOCTET(*(old_p), 2) = (__size>>=8) & 0xFF; \
|
||||
__PAM_BP_WOCTET(*(old_p), 1) = (__size>>=8) & 0xFF; \
|
||||
__PAM_BP_WOCTET(*(old_p), 0) = (__size>>=8) & 0xFF; \
|
||||
(*(old_p))->control = cntrl; \
|
||||
} else { \
|
||||
PAM_BP_ASSERT("out of memory for binary prompt"); \
|
||||
} \
|
||||
} else { \
|
||||
*old_p = NULL; \
|
||||
} \
|
||||
} else { \
|
||||
PAM_BP_ASSERT("programming error, invalid binary prompt pointer"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PAM_BP_FILL(prmpt, offset, length, data) \
|
||||
do { \
|
||||
int bp_length; \
|
||||
__u8 *prompt = (__u8 *) (prmpt); \
|
||||
bp_length = PAM_BP_LENGTH(prompt); \
|
||||
if (bp_length < ((length)+(offset))) { \
|
||||
PAM_BP_ASSERT("attempt to write over end of prompt"); \
|
||||
} \
|
||||
memcpy((offset) + PAM_BP_WDATA(prompt), (data), (length)); \
|
||||
} while (0)
|
||||
|
||||
#define PAM_BP_EXTRACT(prmpt, offset, length, data) \
|
||||
do { \
|
||||
int __bp_length; \
|
||||
const __u8 *__prompt = (const __u8 *) (prmpt); \
|
||||
__bp_length = PAM_BP_LENGTH(__prompt); \
|
||||
if (((offset) < 0) || (__bp_length < ((length)+(offset))) \
|
||||
|| ((length) < 0)) { \
|
||||
PAM_BP_ASSERT("invalid extraction from prompt"); \
|
||||
} \
|
||||
memcpy((data), (offset) + PAM_BP_RDATA(__prompt), (length)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Control types */
|
||||
|
||||
#define PAM_BPC_FALSE 0
|
||||
#define PAM_BPC_TRUE 1
|
||||
|
||||
#define PAM_BPC_OK 0x01 /* continuation packet */
|
||||
#define PAM_BPC_SELECT 0x02 /* initialization packet */
|
||||
#define PAM_BPC_DONE 0x03 /* termination packet */
|
||||
#define PAM_BPC_FAIL 0x04 /* unable to execute */
|
||||
|
||||
/* The following control characters are only legal for echanges
|
||||
between an agent and a client (it is the responsibility of the
|
||||
client to enforce this rule in the face of a rogue server): */
|
||||
|
||||
#define PAM_BPC_GETENV 0x41 /* obtain client env.var */
|
||||
#define PAM_BPC_PUTENV 0x42 /* set client env.var */
|
||||
#define PAM_BPC_TEXT 0x43 /* display message */
|
||||
#define PAM_BPC_ERROR 0x44 /* display error message */
|
||||
#define PAM_BPC_PROMPT 0x45 /* echo'd text prompt */
|
||||
#define PAM_BPC_PASS 0x46 /* non-echo'd text prompt*/
|
||||
|
||||
/* quick check for prompts that are legal for the client (by
|
||||
implication the server too) to send to libpamc */
|
||||
|
||||
#define PAM_BPC_FOR_CLIENT(/* pamc_bp_t */ prompt) \
|
||||
(((prompt)->control <= PAM_BPC_FAIL && (prompt)->control >= PAM_BPC_OK) \
|
||||
? PAM_BPC_TRUE:PAM_BPC_FALSE)
|
||||
|
||||
|
||||
#endif /* PAM_CLIENT_H */
|
63
contrib/libpam/libpamc/libpamc.h
Normal file
63
contrib/libpam/libpamc/libpamc.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* $Id: libpamc.h,v 1.2 2000/11/19 23:54:03 agmorgan Exp $
|
||||
*
|
||||
* Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBPAMC_H
|
||||
#define LIBPAMC_H
|
||||
|
||||
#include <security/pam_client.h>
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define _PAMC_DEFAULT_TOP_FD 10
|
||||
|
||||
struct pamc_handle_s {
|
||||
struct pamc_agent_s *current;
|
||||
struct pamc_agent_s *chain;
|
||||
struct pamc_blocked_s *blocked_agents;
|
||||
int max_path;
|
||||
char **agent_paths;
|
||||
int combined_status;
|
||||
int highest_fd_to_close;
|
||||
};
|
||||
|
||||
typedef struct pamc_blocked_s {
|
||||
char *id; /* <NUL> terminated */
|
||||
struct pamc_blocked_s *next;
|
||||
} pamc_blocked_t;
|
||||
|
||||
typedef struct pamc_agent_s {
|
||||
char *id;
|
||||
int id_length;
|
||||
struct pamc_agent_s *next;
|
||||
int writer; /* write to agent */
|
||||
int reader; /* read from agent */
|
||||
pid_t pid; /* agent process id */
|
||||
} pamc_agent_t;
|
||||
|
||||
/* used to build a tree of unique, sorted agent ids */
|
||||
|
||||
typedef struct pamc_id_node {
|
||||
struct pamc_id_node *left, *right;
|
||||
int child_count;
|
||||
char *agent_id;
|
||||
} pamc_id_node_t;
|
||||
|
||||
/* internal function */
|
||||
int __pamc_valid_agent_id(int id_length, const char *id);
|
||||
|
||||
#define PAMC_SYSTEM_AGENT_PATH "/lib/pamc:/usr/lib/pamc"
|
||||
#define PAMC_SYSTEM_AGENT_SEPARATOR ':'
|
||||
|
||||
#endif /* LIBPAMC_H */
|
189
contrib/libpam/libpamc/pamc_client.c
Normal file
189
contrib/libpam/libpamc/pamc_client.c
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* $Id: pamc_client.c,v 1.1.1.1 2000/06/20 22:11:25 agmorgan Exp $
|
||||
*
|
||||
* Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org>
|
||||
*
|
||||
* pamc_start and pamc_end
|
||||
*/
|
||||
|
||||
#include "libpamc.h"
|
||||
|
||||
/*
|
||||
* liberate path list
|
||||
*/
|
||||
|
||||
static void __pamc_delete_path_list(pamc_handle_t pch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; pch->agent_paths[i]; ++i) {
|
||||
free(pch->agent_paths[i]);
|
||||
pch->agent_paths[i] = NULL;
|
||||
}
|
||||
|
||||
free(pch->agent_paths);
|
||||
pch->agent_paths = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* open the pamc library
|
||||
*/
|
||||
|
||||
pamc_handle_t pamc_start(void)
|
||||
{
|
||||
int i, count, last, this;
|
||||
const char *default_path;
|
||||
pamc_handle_t pch;
|
||||
|
||||
pch = calloc(1, sizeof(struct pamc_handle_s));
|
||||
if (pch == NULL) {
|
||||
D(("no memory for *pch"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pch->highest_fd_to_close = _PAMC_DEFAULT_TOP_FD;
|
||||
|
||||
default_path = getenv("PAMC_AGENT_PATH");
|
||||
if (default_path == NULL) {
|
||||
default_path = PAMC_SYSTEM_AGENT_PATH;
|
||||
}
|
||||
|
||||
/* number of individual paths */
|
||||
for (count=1, i=0; default_path[i]; ++i) {
|
||||
if (default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
pch->agent_paths = calloc(count+1, sizeof(char *));
|
||||
if (pch->agent_paths == NULL) {
|
||||
D(("no memory for path list"));
|
||||
goto drop_pch;
|
||||
}
|
||||
|
||||
this = last = i = 0;
|
||||
while ( default_path[i] || (i != last) ) {
|
||||
if ( default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR
|
||||
|| !default_path[i] ) {
|
||||
int length;
|
||||
|
||||
pch->agent_paths[this] = malloc(length = 1+i-last);
|
||||
|
||||
if (pch->agent_paths[this] == NULL) {
|
||||
D(("no memory for next path"));
|
||||
goto drop_list;
|
||||
}
|
||||
|
||||
memcpy(pch->agent_paths[this], default_path + last, i-last);
|
||||
pch->agent_paths[this][i-last] = '\0';
|
||||
if (length > pch->max_path) {
|
||||
pch->max_path = length;
|
||||
}
|
||||
|
||||
if (++this == count) {
|
||||
break;
|
||||
}
|
||||
|
||||
last = ++i;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return pch;
|
||||
|
||||
drop_list:
|
||||
__pamc_delete_path_list(pch);
|
||||
|
||||
drop_pch:
|
||||
free(pch);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* shutdown each of the loaded agents and
|
||||
*/
|
||||
|
||||
static int __pamc_shutdown_agents(pamc_handle_t pch)
|
||||
{
|
||||
int retval = PAM_BPC_TRUE;
|
||||
|
||||
D(("called"));
|
||||
|
||||
while (pch->chain) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
pamc_agent_t *this;
|
||||
|
||||
this = pch->chain;
|
||||
D(("cleaning up agent %p", this));
|
||||
pch->chain = pch->chain->next;
|
||||
this->next = NULL;
|
||||
D(("cleaning up agent: %s", this->id));
|
||||
|
||||
/* close off contact with agent and wait for it to shutdown */
|
||||
|
||||
close(this->writer);
|
||||
this->writer = -1;
|
||||
close(this->reader);
|
||||
this->reader = -1;
|
||||
|
||||
pid = waitpid(this->pid, &status, 0);
|
||||
if (pid == this->pid) {
|
||||
|
||||
D(("is exit:%d, exit val:%d",
|
||||
WIFEXITED(status), WEXITSTATUS(status)));
|
||||
|
||||
if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
|
||||
retval = PAM_BPC_FALSE;
|
||||
}
|
||||
} else {
|
||||
D(("problem shutting down agent (%s): pid(%d) != waitpid(%d)!?",
|
||||
this->id, this->pid, pid));
|
||||
retval = PAM_BPC_FALSE;
|
||||
}
|
||||
pid = this->pid = 0;
|
||||
|
||||
memset(this->id, 0, this->id_length);
|
||||
free(this->id);
|
||||
this->id = NULL;
|
||||
this->id_length = 0;
|
||||
|
||||
free(this);
|
||||
this = NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* close the pamc library
|
||||
*/
|
||||
|
||||
int pamc_end(pamc_handle_t *pch_p)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (pch_p == NULL) {
|
||||
D(("called with no pch_p"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
if (*pch_p == NULL) {
|
||||
D(("called with no *pch_p"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
D(("removing path_list"));
|
||||
__pamc_delete_path_list(*pch_p);
|
||||
|
||||
D(("shutting down agents"));
|
||||
retval = __pamc_shutdown_agents(*pch_p);
|
||||
|
||||
D(("freeing *pch_p"));
|
||||
free(*pch_p);
|
||||
*pch_p = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
211
contrib/libpam/libpamc/pamc_converse.c
Normal file
211
contrib/libpam/libpamc/pamc_converse.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* $Id: pamc_converse.c,v 1.2 2001/01/20 22:29:47 agmorgan Exp $
|
||||
*
|
||||
* Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org>
|
||||
*
|
||||
* pamc_converse
|
||||
*/
|
||||
|
||||
#include "libpamc.h"
|
||||
|
||||
/*
|
||||
* select agent
|
||||
*/
|
||||
|
||||
static int __pamc_select_agent(pamc_handle_t pch, char *agent_id)
|
||||
{
|
||||
pamc_agent_t *agent;
|
||||
|
||||
for (agent = pch->chain; agent; agent = agent->next) {
|
||||
if (!strcmp(agent->id, agent_id)) {
|
||||
pch->current = agent;
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
D(("failed to locate agent"));
|
||||
pch->current = NULL;
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* pass a binary prompt to the active agent and wait for a reply prompt
|
||||
*/
|
||||
|
||||
int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p)
|
||||
{
|
||||
__u32 size, offset=0;
|
||||
__u8 control, raw[PAM_BP_MIN_SIZE];
|
||||
|
||||
D(("called"));
|
||||
|
||||
if (pch == NULL) {
|
||||
D(("null pch"));
|
||||
goto pamc_converse_failure;
|
||||
}
|
||||
|
||||
if (prompt_p == NULL) {
|
||||
D(("null prompt_p"));
|
||||
goto pamc_converse_failure;
|
||||
}
|
||||
|
||||
if (*prompt_p == NULL) {
|
||||
D(("null *prompt_p"));
|
||||
goto pamc_converse_failure;
|
||||
}
|
||||
|
||||
/* from here on, failures are interoperability problems.. */
|
||||
|
||||
size = PAM_BP_SIZE(*prompt_p);
|
||||
if (size < PAM_BP_MIN_SIZE) {
|
||||
D(("problem with size being too short (%u)", size));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
|
||||
if (PAM_BPC_FOR_CLIENT(*prompt_p) != PAM_BPC_TRUE) {
|
||||
D(("*prompt_p is not legal for the client to use"));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
|
||||
/* do we need to select the agent? */
|
||||
if ((*prompt_p)->control == PAM_BPC_SELECT) {
|
||||
char *rawh;
|
||||
int i, retval;
|
||||
|
||||
D(("selecting a specified agent"));
|
||||
|
||||
rawh = (char *) *prompt_p;
|
||||
for (i = PAM_BP_MIN_SIZE; i<size; ++i) {
|
||||
if (rawh[i] == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (i >= size)
|
||||
|| !__pamc_valid_agent_id(i-PAM_BP_MIN_SIZE,
|
||||
rawh + PAM_BP_MIN_SIZE) ) {
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
|
||||
rawh[i] = '\0';
|
||||
retval = pamc_load(pch, PAM_BP_MIN_SIZE + rawh);
|
||||
if (retval == PAM_BPC_TRUE) {
|
||||
retval = __pamc_select_agent(pch, PAM_BP_MIN_SIZE + rawh);
|
||||
}
|
||||
rawh[i] = '/';
|
||||
|
||||
if (retval != PAM_BPC_TRUE) {
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
|
||||
D(("agent is loaded"));
|
||||
}
|
||||
|
||||
if (pch->current == NULL) {
|
||||
D(("unable to address agent"));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
|
||||
/* pump all of the prompt into the agent */
|
||||
do {
|
||||
int rval = write(pch->current->writer,
|
||||
offset + (const __u8 *) (*prompt_p),
|
||||
size - offset);
|
||||
if (rval == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
break;
|
||||
default:
|
||||
D(("problem writing to agent: %s", strerror(errno)));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
} else {
|
||||
offset += rval;
|
||||
}
|
||||
} while (offset < size);
|
||||
|
||||
D(("whole prompt sent to agent"));
|
||||
|
||||
/* read size and control for response prompt */
|
||||
|
||||
offset = 0;
|
||||
memset(raw, 0, sizeof(raw));
|
||||
do {
|
||||
int rval;
|
||||
|
||||
rval = read(pch->current->reader, raw + offset,
|
||||
PAM_BP_MIN_SIZE - offset);
|
||||
|
||||
if (rval == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
break;
|
||||
default:
|
||||
D(("problem reading from agent: %s", strerror(errno)));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
} else if (rval) {
|
||||
offset += rval;
|
||||
} else {
|
||||
D(("agent has closed its output pipe - nothing more to read"));
|
||||
goto pamc_converse_failure;
|
||||
}
|
||||
} while (offset < PAM_BP_MIN_SIZE);
|
||||
|
||||
/* construct the whole reply prompt */
|
||||
|
||||
size = PAM_BP_SIZE(raw);
|
||||
control = PAM_BP_RCONTROL(raw);
|
||||
memset(raw, 0, sizeof(raw));
|
||||
|
||||
D(("agent replied with prompt of size %d and control %u",
|
||||
size, control));
|
||||
|
||||
PAM_BP_RENEW(prompt_p, control, size - PAM_BP_MIN_SIZE);
|
||||
if (*prompt_p == NULL) {
|
||||
D(("problem making a new prompt for reply"));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
|
||||
/* read the rest of the reply prompt -- note offset has the correct
|
||||
value from the previous loop */
|
||||
|
||||
while (offset < size) {
|
||||
int rval = read(pch->current->reader, offset + (__u8 *) *prompt_p,
|
||||
size-offset);
|
||||
|
||||
if (rval == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
break;
|
||||
default:
|
||||
D(("problem reading from agent: %s", strerror(errno)));
|
||||
goto pamc_unknown_prompt;
|
||||
}
|
||||
} else if (rval) {
|
||||
offset += rval;
|
||||
} else {
|
||||
D(("problem reading prompt (%d) with %d to go",
|
||||
size, size-offset));
|
||||
goto pamc_converse_failure;
|
||||
}
|
||||
}
|
||||
|
||||
D(("returning success"));
|
||||
|
||||
return PAM_BPC_TRUE;
|
||||
|
||||
pamc_converse_failure:
|
||||
|
||||
D(("conversation failure"));
|
||||
PAM_BP_RENEW(prompt_p, 0, 0);
|
||||
return PAM_BPC_FALSE;
|
||||
|
||||
pamc_unknown_prompt:
|
||||
|
||||
/* the server is trying something that the client does not support */
|
||||
D(("unknown prompt"));
|
||||
PAM_BP_RENEW(prompt_p, PAM_BPC_FAIL, 0);
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
|
477
contrib/libpam/libpamc/pamc_load.c
Normal file
477
contrib/libpam/libpamc/pamc_load.c
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* $Id: pamc_load.c,v 1.1.1.1 2000/06/20 22:11:26 agmorgan Exp $
|
||||
*
|
||||
* Copyright (c) 1999 Andrew G. Morgan <morgan@ftp.kernel.org>
|
||||
*
|
||||
* pamc_load
|
||||
*/
|
||||
|
||||
#include "libpamc.h"
|
||||
|
||||
static int __pamc_exec_agent(pamc_handle_t pch, pamc_agent_t *agent)
|
||||
{
|
||||
char *full_path;
|
||||
int found_agent, length, reset_length, to_agent[2], from_agent[2];
|
||||
int return_code = PAM_BPC_FAIL;
|
||||
|
||||
if (agent->id[agent->id_length] != '\0') {
|
||||
PAM_BP_ASSERT("libpamc: internal error agent_id not terminated");
|
||||
}
|
||||
|
||||
for (length=0; (length < agent->id_length); ++length) {
|
||||
switch (agent->id[length]) {
|
||||
case '/':
|
||||
D(("ill formed agent id"));
|
||||
return PAM_BPC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* enough memory for any path + this agent */
|
||||
reset_length = 3 + pch->max_path + agent->id_length;
|
||||
D(("reset_length = %d (3+%d+%d)",
|
||||
reset_length, pch->max_path, agent->id_length));
|
||||
full_path = malloc(reset_length);
|
||||
if (full_path == NULL) {
|
||||
D(("no memory for agent path"));
|
||||
return PAM_BPC_FAIL;
|
||||
}
|
||||
|
||||
found_agent = 0;
|
||||
for (length=0; pch->agent_paths[length]; ++length) {
|
||||
struct stat buf;
|
||||
|
||||
D(("path: [%s]", pch->agent_paths[length]));
|
||||
D(("agent id: [%s]", agent->id));
|
||||
|
||||
sprintf(full_path, "%s/%s", pch->agent_paths[length], agent->id);
|
||||
|
||||
D(("looking for agent here: [%s]\n", full_path));
|
||||
if (stat(full_path, &buf) == 0) {
|
||||
D(("file existis"));
|
||||
found_agent = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found_agent) {
|
||||
D(("no agent was found"));
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
if (pipe(to_agent)) {
|
||||
D(("failed to open pipe to agent"));
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
if (pipe(from_agent)) {
|
||||
D(("failed to open pipe from agent"));
|
||||
goto close_the_agent;
|
||||
}
|
||||
|
||||
agent->pid = fork();
|
||||
if (agent->pid == -1) {
|
||||
|
||||
D(("failed to fork for agent"));
|
||||
goto close_both_pipes;
|
||||
|
||||
} else if (agent->pid == 0) {
|
||||
|
||||
int i;
|
||||
|
||||
dup2(from_agent[1], STDOUT_FILENO);
|
||||
dup2(to_agent[0], STDIN_FILENO);
|
||||
|
||||
/* we close all of the files that have filedescriptors lower
|
||||
and equal to twice the highest we have seen, The idea is
|
||||
that we don't want to leak filedescriptors to agents from a
|
||||
privileged client application.
|
||||
|
||||
XXX - this is a heuristic at this point. There is a growing
|
||||
need for an extra 'set param' libpamc function, that could
|
||||
be used to supply info like the highest fd to close etc..
|
||||
*/
|
||||
|
||||
if (from_agent[1] > pch->highest_fd_to_close) {
|
||||
pch->highest_fd_to_close = 2*from_agent[1];
|
||||
}
|
||||
|
||||
for (i=0; i <= pch->highest_fd_to_close; ++i) {
|
||||
switch (i) {
|
||||
case STDOUT_FILENO:
|
||||
case STDERR_FILENO:
|
||||
case STDIN_FILENO:
|
||||
/* only these three remain open */
|
||||
break;
|
||||
default:
|
||||
(void) close(i); /* don't care if its not open */
|
||||
}
|
||||
}
|
||||
|
||||
/* we make no attempt to drop other privileges - this library
|
||||
has no idea how that would be done in the general case. It
|
||||
is up to the client application (when calling
|
||||
pamc_converse) to make sure no privilege will leak into an
|
||||
(untrusted) agent. */
|
||||
|
||||
/* we propogate no environment - future versions of this
|
||||
library may have the ability to audit all agent
|
||||
transactions. */
|
||||
|
||||
D(("exec'ing agent %s", full_path));
|
||||
execle(full_path, "pam-agent", NULL, NULL);
|
||||
|
||||
D(("exec failed"));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
close(to_agent[0]);
|
||||
close(from_agent[1]);
|
||||
|
||||
agent->writer = to_agent[1];
|
||||
agent->reader = from_agent[0];
|
||||
|
||||
return_code = PAM_BPC_TRUE;
|
||||
goto free_and_return;
|
||||
|
||||
close_both_pipes:
|
||||
close(from_agent[0]);
|
||||
close(from_agent[1]);
|
||||
|
||||
close_the_agent:
|
||||
close(to_agent[0]);
|
||||
close(to_agent[1]);
|
||||
|
||||
free_and_return:
|
||||
memset(full_path, 0, reset_length);
|
||||
free(full_path);
|
||||
|
||||
D(("returning %d", return_code));
|
||||
|
||||
return return_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* has the named agent been loaded?
|
||||
*/
|
||||
|
||||
static int __pamc_agent_is_enabled(pamc_handle_t pch, const char *agent_id)
|
||||
{
|
||||
pamc_agent_t *agent;
|
||||
|
||||
for (agent = pch->chain; agent; agent = agent->next) {
|
||||
if (!strcmp(agent->id, agent_id)) {
|
||||
D(("agent already loaded"));
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
D(("agent is not loaded"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* has the named agent been disabled?
|
||||
*/
|
||||
|
||||
static int __pamc_agent_is_disabled(pamc_handle_t pch, const char *agent_id)
|
||||
{
|
||||
pamc_blocked_t *blocked;
|
||||
|
||||
for (blocked=pch->blocked_agents; blocked; blocked = blocked->next) {
|
||||
if (!strcmp(agent_id, blocked->id)) {
|
||||
D(("agent is disabled"));
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
D(("agent is not disabled"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* disable an agent
|
||||
*/
|
||||
|
||||
int pamc_disable(pamc_handle_t pch, const char *agent_id)
|
||||
{
|
||||
pamc_blocked_t *block;
|
||||
|
||||
if (pch == NULL) {
|
||||
D(("pch is NULL"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
if (agent_id == NULL) {
|
||||
D(("agent_id is NULL"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
if (__pamc_agent_is_enabled(pch, agent_id) != PAM_BPC_FALSE) {
|
||||
D(("agent is already loaded"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
if (__pamc_agent_is_disabled(pch, agent_id) != PAM_BPC_FALSE) {
|
||||
D(("agent is already disabled"));
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
|
||||
block = calloc(1, sizeof(pamc_blocked_t));
|
||||
if (block == NULL) {
|
||||
D(("no memory for new blocking structure"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
block->id = malloc(1 + strlen(agent_id));
|
||||
if (block->id == NULL) {
|
||||
D(("no memory for agent id"));
|
||||
free(block);
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
strcpy(block->id, agent_id);
|
||||
block->next = pch->blocked_agents;
|
||||
pch->blocked_agents = block;
|
||||
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* force the loading of a particular agent
|
||||
*/
|
||||
|
||||
int pamc_load(pamc_handle_t pch, const char *agent_id)
|
||||
{
|
||||
pamc_agent_t *agent;
|
||||
int length;
|
||||
|
||||
/* santity checking */
|
||||
|
||||
if (pch == NULL) {
|
||||
D(("pch is NULL"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
if (agent_id == NULL) {
|
||||
D(("agent_id is NULL"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
if (__pamc_agent_is_disabled(pch, agent_id) != PAM_BPC_FALSE) {
|
||||
D(("sorry agent is disabled"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
length = strlen(agent_id);
|
||||
|
||||
/* scan list to see if agent is loaded */
|
||||
|
||||
if (__pamc_agent_is_enabled(pch, agent_id) == PAM_BPC_TRUE) {
|
||||
D(("no need to load an already loaded agent (%s)", agent_id));
|
||||
return PAM_BPC_TRUE;
|
||||
}
|
||||
|
||||
/* not in the list, so we need to load it and add it to the head
|
||||
of the chain */
|
||||
|
||||
agent = calloc(1, sizeof(pamc_agent_t));
|
||||
if (agent == NULL) {
|
||||
D(("no memory for new agent"));
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
agent->id = calloc(1, 1+length);
|
||||
if (agent->id == NULL) {
|
||||
D(("no memory for new agent's id"));
|
||||
goto fail_free_agent;
|
||||
}
|
||||
memcpy(agent->id, agent_id, length);
|
||||
agent->id[length] = '\0';
|
||||
agent->id_length = length;
|
||||
|
||||
if (__pamc_exec_agent(pch, agent) != PAM_BPC_TRUE) {
|
||||
D(("unable to exec agent"));
|
||||
goto fail_free_agent_id;
|
||||
}
|
||||
|
||||
agent->next = pch->chain;
|
||||
pch->chain = agent;
|
||||
|
||||
return PAM_BPC_TRUE;
|
||||
|
||||
fail_free_agent_id:
|
||||
|
||||
memset(agent->id, 0, agent->id_length);
|
||||
free(agent->id);
|
||||
|
||||
memset(agent, 0, sizeof(*agent));
|
||||
|
||||
fail_free_agent:
|
||||
|
||||
free(agent);
|
||||
return PAM_BPC_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* what's a valid agent name?
|
||||
*/
|
||||
|
||||
int __pamc_valid_agent_id(int id_length, const char *id)
|
||||
{
|
||||
int post, i;
|
||||
|
||||
for (i=post=0 ; i < id_length; ++i) {
|
||||
int ch = id[i++];
|
||||
|
||||
if (isalpha(ch) || isdigit(ch) || (ch == '_')) {
|
||||
continue;
|
||||
} else if (post && (ch == '.')) {
|
||||
continue;
|
||||
} else if ((i > 1) && (!post) && (ch == '@')) {
|
||||
post = 1;
|
||||
} else {
|
||||
D(("id=%s contains '%c' which is illegal", id, ch));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i) {
|
||||
D(("length of id is 0"));
|
||||
return 0;
|
||||
} else {
|
||||
return 1; /* id is valid */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* building a tree of available agent names
|
||||
*/
|
||||
|
||||
static pamc_id_node_t *__pamc_add_node(pamc_id_node_t *root, const char *id,
|
||||
int *counter)
|
||||
{
|
||||
if (root) {
|
||||
|
||||
int cmp;
|
||||
|
||||
if ((cmp = strcmp(id, root->agent_id))) {
|
||||
if (cmp > 0) {
|
||||
root->right = __pamc_add_node(root->right, id,
|
||||
&(root->child_count));
|
||||
} else {
|
||||
root->left = __pamc_add_node(root->left, id,
|
||||
&(root->child_count));
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
|
||||
} else {
|
||||
|
||||
pamc_id_node_t *node = calloc(1, sizeof(pamc_id_node_t));
|
||||
|
||||
if (node) {
|
||||
node->agent_id = malloc(1+strlen(id));
|
||||
if (node->agent_id) {
|
||||
strcpy(node->agent_id, id);
|
||||
} else {
|
||||
free(node);
|
||||
node = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
(*counter)++;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* drop all of the tree and any remaining ids
|
||||
*/
|
||||
|
||||
static pamc_id_node_t *__pamc_liberate_nodes(pamc_id_node_t *tree)
|
||||
{
|
||||
if (tree) {
|
||||
if (tree->agent_id) {
|
||||
free(tree->agent_id);
|
||||
tree->agent_id = NULL;
|
||||
}
|
||||
|
||||
tree->left = __pamc_liberate_nodes(tree->left);
|
||||
tree->right = __pamc_liberate_nodes(tree->right);
|
||||
|
||||
tree->child_count = 0;
|
||||
free(tree);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill a list with the contents of the tree (in ascii order)
|
||||
*/
|
||||
|
||||
static void __pamc_fill_list_from_tree(pamc_id_node_t *tree, char **agent_list,
|
||||
int *counter)
|
||||
{
|
||||
if (tree) {
|
||||
__pamc_fill_list_from_tree(tree->left, agent_list, counter);
|
||||
agent_list[(*counter)++] = tree->agent_id;
|
||||
tree->agent_id = NULL;
|
||||
__pamc_fill_list_from_tree(tree->right, agent_list, counter);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get a list of the available agents
|
||||
*/
|
||||
|
||||
char **pamc_list_agents(pamc_handle_t pch)
|
||||
{
|
||||
int i, total_agent_count=0;
|
||||
pamc_id_node_t *tree = NULL;
|
||||
char **agent_list;
|
||||
|
||||
/* loop over agent paths */
|
||||
|
||||
for (i=0; pch->agent_paths[i]; ++i) {
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(pch->agent_paths[i]);
|
||||
if (dir) {
|
||||
struct dirent *item;
|
||||
|
||||
while ((item = readdir(dir))) {
|
||||
|
||||
/* this is a cheat on recognizing agent_ids */
|
||||
if (!__pamc_valid_agent_id(strlen(item->d_name),
|
||||
item->d_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tree = __pamc_add_node(tree, item->d_name, &total_agent_count);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* now, we build a list of ids */
|
||||
D(("total of %d available agents\n", total_agent_count));
|
||||
|
||||
agent_list = calloc(total_agent_count+1, sizeof(char *));
|
||||
if (agent_list) {
|
||||
int counter=0;
|
||||
|
||||
__pamc_fill_list_from_tree(tree, agent_list, &counter);
|
||||
if (counter != total_agent_count) {
|
||||
PAM_BP_ASSERT("libpamc: internal error transcribing tree");
|
||||
}
|
||||
} else {
|
||||
D(("no memory for agent list"));
|
||||
}
|
||||
|
||||
__pamc_liberate_nodes(tree);
|
||||
|
||||
return agent_list;
|
||||
}
|
308
contrib/libpam/libpamc/test/agents/secret@here
Executable file
308
contrib/libpam/libpamc/test/agents/secret@here
Executable file
@ -0,0 +1,308 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# This is a simple example PAM authentication agent, it implements a
|
||||
# simple shared secret authentication scheme. The PAM module pam_secret.so
|
||||
# is its counter part. Both the agent and the remote server are able to
|
||||
# authenticate one another, but the server is given the opportunity to
|
||||
# ignore a failed authentication.
|
||||
#
|
||||
|
||||
$^W = 1;
|
||||
use strict;
|
||||
use IPC::Open2;
|
||||
$| = 1;
|
||||
|
||||
# display extra information to STDERR
|
||||
my $debug = 0;
|
||||
if (scalar @ARGV) {
|
||||
$debug = 1;
|
||||
}
|
||||
|
||||
# Globals
|
||||
|
||||
my %state;
|
||||
my $default_key;
|
||||
|
||||
my $next_key = $$;
|
||||
|
||||
# loop over binary prompts
|
||||
for (;;) {
|
||||
my ($control, $data) = ReadBinaryPrompt();
|
||||
my ($reply_control, $reply_data);
|
||||
|
||||
if ($control == 0) {
|
||||
if ($debug) {
|
||||
print STDERR "agent: no packet to read\n";
|
||||
}
|
||||
last;
|
||||
} elsif ($control == 0x02) {
|
||||
($reply_control, $reply_data) = HandleAgentSelection($data);
|
||||
} elsif ($control == 0x01) {
|
||||
($reply_control, $reply_data) = HandleContinuation($data);
|
||||
} else {
|
||||
if ($debug) {
|
||||
print STDERR
|
||||
"agent: unrecognized packet $control {$data} to read\n";
|
||||
}
|
||||
($reply_control, $reply_data) = (0x04, "");
|
||||
}
|
||||
|
||||
WriteBinaryPrompt($reply_control, $reply_data);
|
||||
}
|
||||
|
||||
# Only willing to exit well if we've completed our authentication exchange
|
||||
|
||||
if (scalar keys %state) {
|
||||
if ($debug) {
|
||||
print STDERR "The following sessions are still active:\n ";
|
||||
print STDERR join ', ', keys %state;
|
||||
print STDERR "\n";
|
||||
}
|
||||
exit 1;
|
||||
} else {
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub HandleAgentSelection ($) {
|
||||
my ($data) = @_;
|
||||
|
||||
unless ( $data =~ /^([a-zA-Z0-9_]+\@?[a-zA-Z0-9_.]*)\/(.*)$/ ) {
|
||||
return (0x04, "");
|
||||
}
|
||||
|
||||
my ($agent_name, $payload) = ($1, $2);
|
||||
if ($debug) {
|
||||
print STDERR "agent: ". "agent=$agent_name, payload=$payload\n";
|
||||
}
|
||||
|
||||
# this agent has a defined name
|
||||
if ($agent_name ne "secret\@here") {
|
||||
if ($debug) {
|
||||
print STDERR "bad agent name: [$agent_name]\n";
|
||||
}
|
||||
return (0x04, "");
|
||||
}
|
||||
|
||||
# the selection request is acompanied with a hexadecimal cookie
|
||||
my @tokens = split '\|', $payload;
|
||||
|
||||
unless ((scalar @tokens) == 2) {
|
||||
if ($debug) {
|
||||
print STDERR "bad payload\n";
|
||||
}
|
||||
return (0x04, "");
|
||||
}
|
||||
|
||||
unless ($tokens[1] =~ /^[a-z0-9]+$/) {
|
||||
if ($debug) {
|
||||
print STDERR "bad server cookie\n";
|
||||
}
|
||||
return (0x04, "");
|
||||
}
|
||||
|
||||
my $shared_secret = IdentifyLocalSecret($tokens[0]);
|
||||
|
||||
unless (defined $shared_secret) {
|
||||
# make a secret up
|
||||
if ($debug) {
|
||||
print STDERR "agent: cannot authenticate user\n";
|
||||
}
|
||||
$shared_secret = GetRandom();
|
||||
}
|
||||
|
||||
my $local_cookie = GetRandom();
|
||||
$default_key = $next_key++;
|
||||
|
||||
$state{$default_key} = $local_cookie ."|". $tokens[1] ."|". $shared_secret;
|
||||
|
||||
if ($debug) {
|
||||
print STDERR "agent: \$state{$default_key} = $state{$default_key}\n";
|
||||
}
|
||||
|
||||
return (0x01, $default_key ."|". $local_cookie);
|
||||
}
|
||||
|
||||
sub HandleContinuation ($) {
|
||||
my ($data) = @_;
|
||||
|
||||
my ($key, $server_digest) = split '\|', $data;
|
||||
|
||||
unless (defined $state{$key}) {
|
||||
# retries and out of sequence prompts are not permitted
|
||||
return (0x04, "");
|
||||
}
|
||||
|
||||
my $expected_digest = CreateDigest($state{$key});
|
||||
my ($local_cookie, $remote_cookie, $shared_secret)
|
||||
= split '\|', $state{$key};
|
||||
delete $state{$key};
|
||||
|
||||
unless ($expected_digest eq $server_digest) {
|
||||
if ($debug) {
|
||||
print STDERR "agent: don't trust server - faking reply\n";
|
||||
print STDERR "agent: got ($server_digest)\n";
|
||||
print STDERR "agent: expected ($expected_digest)\n";
|
||||
}
|
||||
|
||||
## FIXME: Agent should exchange a prompt with the client warning
|
||||
## that the server is faking us out.
|
||||
|
||||
return (0x03, CreateDigest($expected_digest . $data . GetRandom()));
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
print STDERR "agent: server appears to know the secret\n";
|
||||
}
|
||||
|
||||
my $session_authenticated_ticket =
|
||||
CreateDigest($remote_cookie."|".$shared_secret."|".$local_cookie);
|
||||
|
||||
# FIXME: Agent should set a derived session key environment
|
||||
# variable (available for the client (and its children) to sign
|
||||
# future data exchanges.
|
||||
|
||||
if ($debug) {
|
||||
print STDERR "agent: should putenv("
|
||||
."\"AUTH_SESSION_TICKET=$session_authenticated_ticket\")\n";
|
||||
}
|
||||
|
||||
# return agent's authenticating digest
|
||||
return (0x03, CreateDigest($shared_secret."|".$remote_cookie
|
||||
."|".$local_cookie));
|
||||
}
|
||||
|
||||
sub ReadBinaryPrompt {
|
||||
my $buffer = " ";
|
||||
my $count = read(STDIN, $buffer, 5);
|
||||
if ($count == 0) {
|
||||
# no more packets to read
|
||||
return (0, "");
|
||||
}
|
||||
|
||||
if ($count != 5) {
|
||||
# broken packet header
|
||||
return (-1, "");
|
||||
}
|
||||
|
||||
my ($length, $control) = unpack("N C", $buffer);
|
||||
if ($length < 5) {
|
||||
# broken packet length
|
||||
return (-1, "");
|
||||
}
|
||||
|
||||
my $data = "";
|
||||
$length -= 5;
|
||||
while ($count = read(STDIN, $buffer, $length)) {
|
||||
$data .= $buffer;
|
||||
if ($count != $length) {
|
||||
$length -= $count;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
print STDERR "agent: ". "data is [$data]\n";
|
||||
}
|
||||
|
||||
return ($control, $data);
|
||||
}
|
||||
|
||||
# broken packet data
|
||||
return (-1, "");
|
||||
}
|
||||
|
||||
sub WriteBinaryPrompt ($$) {
|
||||
my ($control, $data) = @_;
|
||||
|
||||
my $length = 5 + length($data);
|
||||
if ($debug) {
|
||||
printf STDERR "agent: ". "{%d|0x%.2x|%s}\n", $length, $control, $data;
|
||||
}
|
||||
my $bp = pack("N C a*", $length, $control, $data);
|
||||
print STDOUT $bp;
|
||||
if ($debug) {
|
||||
printf STDERR "agent: ". "agent has replied\n";
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
## Here is where we parse the simple secret file
|
||||
## The format of this file is a list of lines of the following form:
|
||||
##
|
||||
## user@client0.host.name secret_string1
|
||||
## user@client1.host.name secret_string2
|
||||
## user@client2.host.name secret_string3
|
||||
##
|
||||
|
||||
sub IdentifyLocalSecret ($) {
|
||||
my ($identifier) = @_;
|
||||
my $secret;
|
||||
|
||||
if (open SECRETS, "< ". (getpwuid($<))[7] ."/.secret\@here") {
|
||||
my $line;
|
||||
while (defined ($line = <SECRETS>)) {
|
||||
my ($id, $sec) = split /[\s]+/, $line;
|
||||
if ((defined $id) && ($id eq $identifier)) {
|
||||
$secret = $sec;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close SECRETS;
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
## Here is where we generate a message digest
|
||||
|
||||
sub CreateDigest ($) {
|
||||
my ($data) = @_;
|
||||
|
||||
my $pid = open2(\*MD5out, \*MD5in, "/usr/bin/md5sum -")
|
||||
or die "you'll need /usr/bin/md5sum installed";
|
||||
|
||||
my $oldfd = select MD5in; $|=1; select $oldfd;
|
||||
if ($debug) {
|
||||
print STDERR "agent: ". "telling md5: <$data>\n";
|
||||
}
|
||||
print MD5in "$data";
|
||||
close MD5in;
|
||||
my $reply = <MD5out>;
|
||||
($reply) = split /\s/, $reply;
|
||||
if ($debug) {
|
||||
print STDERR "agent: ". "md5 said: <$reply>\n";
|
||||
}
|
||||
close MD5out;
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
## get a random number
|
||||
|
||||
sub GetRandom {
|
||||
|
||||
if ( -r "/dev/urandom" ) {
|
||||
open RANDOM, "< /dev/urandom" or die "crazy";
|
||||
|
||||
my $i;
|
||||
my $reply = "";
|
||||
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
my $buffer = " ";
|
||||
while (read(RANDOM, $buffer, 4) != 4) {
|
||||
;
|
||||
}
|
||||
$reply .= sprintf "%.8x", unpack("N", $buffer);
|
||||
if ($debug) {
|
||||
print STDERR "growing reply: [$reply]\n";
|
||||
}
|
||||
}
|
||||
close RANDOM;
|
||||
|
||||
return $reply;
|
||||
} else {
|
||||
print STDERR "agent: ". "[got linux?]\n";
|
||||
return "%.8x%.8x%.8x%.8x", time, time, time, time;
|
||||
}
|
||||
|
||||
}
|
||||
|
9
contrib/libpam/libpamc/test/modules/Makefile
Normal file
9
contrib/libpam/libpamc/test/modules/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
CFLAGS = -g -fPIC -I"../../include"
|
||||
|
||||
pam_secret.so: pam_secret.o
|
||||
ld -x --shared -o pam_secret.so pam_secret.o -lc
|
||||
|
||||
.o.c:
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o
|
670
contrib/libpam/libpamc/test/modules/pam_secret.c
Normal file
670
contrib/libpam/libpamc/test/modules/pam_secret.c
Normal file
@ -0,0 +1,670 @@
|
||||
/*
|
||||
* $Id: pam_secret.c,v 1.2 2001/01/20 22:29:47 agmorgan Exp $
|
||||
*
|
||||
* Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING: AS WRITTEN THIS CODE IS NOT SECURE. THE MD5 IMPLEMENTATION
|
||||
* NEEDS TO BE INTEGRATED MORE NATIVELY.
|
||||
*/
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/pam_client.h>
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
/*
|
||||
* This is a sample module that demonstrates the use of binary prompts
|
||||
* and how they can be used to implement sophisticated authentication
|
||||
* schemes.
|
||||
*/
|
||||
|
||||
struct ps_state_s {
|
||||
int retval; /* last retval returned by the authentication fn */
|
||||
int state; /* what state the module was in when it
|
||||
returned incomplete */
|
||||
|
||||
char *username; /* the name of the local user */
|
||||
|
||||
char server_cookie[33]; /* storage for 32 bytes of server cookie */
|
||||
char client_cookie[33]; /* storage for 32 bytes of client cookie */
|
||||
|
||||
char *secret_data; /* pointer to <NUL> terminated secret_data */
|
||||
int invalid_secret; /* indication of whether the secret is valid */
|
||||
|
||||
pamc_bp_t current_prompt; /* place to store the current prompt */
|
||||
pamc_bp_t current_reply; /* place to receive the reply prompt */
|
||||
};
|
||||
|
||||
#define PS_STATE_ID "PAM_SECRET__STATE"
|
||||
#define PS_AGENT_ID "secret@here"
|
||||
#define PS_STATE_DEAD 0
|
||||
#define PS_STATE_INIT 1
|
||||
#define PS_STATE_PROMPT1 2
|
||||
#define PS_STATE_PROMPT2 3
|
||||
|
||||
#define MAX_LEN_HOSTNAME 512
|
||||
#define MAX_FILE_LINE_LEN 1024
|
||||
|
||||
/*
|
||||
* Routine for generating 16*8 bits of random data represented in ASCII hex
|
||||
*/
|
||||
|
||||
static int generate_cookie(unsigned char *buffer_33)
|
||||
{
|
||||
static const char hexarray[] = "0123456789abcdef";
|
||||
int i, fd;
|
||||
|
||||
/* fill buffer_33 with 32 hex characters (lower case) + '\0' */
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
D(("failed to open /dev/urandom"));
|
||||
return 0;
|
||||
}
|
||||
read(fd, buffer_33 + 16, 16);
|
||||
close(fd);
|
||||
|
||||
/* expand top 16 bytes into 32 nibbles */
|
||||
for (i=0; i<16; ++i) {
|
||||
buffer_33[2*i ] = hexarray[(buffer_33[16+i] & 0xf0)>>4];
|
||||
buffer_33[2*i+1] = hexarray[(buffer_33[16+i] & 0x0f)];
|
||||
}
|
||||
|
||||
buffer_33[32] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - This is a hack, and is fundamentally insecure. Its subject to
|
||||
* all sorts of attacks not to mention the fact that all our secrets
|
||||
* will be displayed on the command line for someone doing 'ps' to
|
||||
* see. This is just for programming convenience in this instance, it
|
||||
* needs to be replaced with the md5 code. Although I am loath to
|
||||
* add yet another instance of md5 code to the Linux-PAM source code.
|
||||
* [Need to think of a cleaner way to do this for the distribution as
|
||||
* a whole...]
|
||||
*/
|
||||
|
||||
#define COMMAND_FORMAT "/bin/echo -n '%s|%s|%s'|/usr/bin/md5sum -"
|
||||
|
||||
int create_digest(const char *d1, const char *d2, const char *d3,
|
||||
char *buffer_33)
|
||||
{
|
||||
int length;
|
||||
char *buffer;
|
||||
FILE *pipe;
|
||||
|
||||
length = strlen(d1)+strlen(d2)+strlen(d3)+sizeof(COMMAND_FORMAT);
|
||||
buffer = malloc(length);
|
||||
if (buffer == NULL) {
|
||||
D(("out of memory"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(buffer, COMMAND_FORMAT, d1,d2,d3);
|
||||
|
||||
D(("executing pipe [%s]", buffer));
|
||||
pipe = popen(buffer, "r");
|
||||
memset(buffer, 0, length);
|
||||
free(buffer);
|
||||
|
||||
if (pipe == NULL) {
|
||||
D(("failed to launch pipe"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fgets(buffer_33, 33, pipe) == NULL) {
|
||||
D(("failed to read digest"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strlen(buffer_33) != 32) {
|
||||
D(("digest was not 32 chars"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(pipe);
|
||||
|
||||
D(("done [%s]", buffer_33));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* method to attempt to instruct the application's conversation function
|
||||
*/
|
||||
|
||||
static int converse(pam_handle_t *pamh, struct ps_state_s *new)
|
||||
{
|
||||
int retval;
|
||||
struct pam_conv *conv;
|
||||
|
||||
D(("called"));
|
||||
|
||||
retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
|
||||
if (retval == PAM_SUCCESS) {
|
||||
struct pam_message msg;
|
||||
struct pam_response *single_reply;
|
||||
const struct pam_message *msg_ptr;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_style = PAM_BINARY_PROMPT;
|
||||
msg.msg = (const char *) new->current_prompt;
|
||||
msg_ptr = &msg;
|
||||
|
||||
single_reply = NULL;
|
||||
retval = conv->conv(1, &msg_ptr, &single_reply, conv->appdata_ptr);
|
||||
if (retval == PAM_SUCCESS) {
|
||||
if ((single_reply == NULL) || (single_reply->resp == NULL)) {
|
||||
retval == PAM_CONV_ERR;
|
||||
} else {
|
||||
new->current_reply = (pamc_bp_t) single_reply->resp;
|
||||
single_reply->resp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (single_reply) {
|
||||
free(single_reply);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (retval == PAM_SUCCESS) {
|
||||
D(("reply has length=%d and control=%u",
|
||||
PAM_BP_LENGTH(new->current_reply),
|
||||
PAM_BP_CONTROL(new->current_reply)));
|
||||
}
|
||||
D(("returning %s", pam_strerror(pamh, retval)));
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* identify the secret in question
|
||||
*/
|
||||
|
||||
#define SECRET_FILE_FORMAT "%s/.secret@here"
|
||||
|
||||
char *identify_secret(char *identity, const char *user)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
char *temp;
|
||||
FILE *secrets;
|
||||
int length_id;
|
||||
|
||||
pwd = getpwnam(user);
|
||||
if ((pwd == NULL) || (pwd->pw_dir == NULL)) {
|
||||
D(("user [%s] is not known", user));
|
||||
}
|
||||
|
||||
length_id = strlen(pwd->pw_dir) + sizeof(SECRET_FILE_FORMAT);
|
||||
temp = malloc(length_id);
|
||||
if (temp == NULL) {
|
||||
D(("out of memory"));
|
||||
pwd = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(temp, SECRET_FILE_FORMAT, pwd->pw_dir);
|
||||
pwd = NULL;
|
||||
|
||||
D(("opening key file [%s]", temp));
|
||||
secrets = fopen(temp, "r");
|
||||
memset(temp, 0, length_id);
|
||||
|
||||
if (secrets == NULL) {
|
||||
D(("failed to open key file"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length_id = strlen(identity);
|
||||
temp = malloc(MAX_FILE_LINE_LEN);
|
||||
|
||||
for (;;) {
|
||||
char *secret = NULL;
|
||||
|
||||
if (fgets(temp, MAX_FILE_LINE_LEN, secrets) == NULL) {
|
||||
fclose(secrets);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
D(("cf[%s][%s]", identity, temp));
|
||||
if (memcmp(temp, identity, length_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
D(("found entry"));
|
||||
fclose(secrets);
|
||||
|
||||
for (secret=temp+length_id; *secret; ++secret) {
|
||||
if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memmove(temp, secret, MAX_FILE_LINE_LEN-(secret-(temp+length_id)));
|
||||
secret = temp;
|
||||
|
||||
for (; *secret; ++secret) {
|
||||
if (*secret == ' ' || *secret == '\n' || *secret == '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*secret) {
|
||||
*secret = '\0';
|
||||
}
|
||||
|
||||
D(("secret found [%s]", temp));
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* function to perform the two message authentication process
|
||||
* (with support for event driven conversation functions)
|
||||
*/
|
||||
|
||||
static int auth_sequence(pam_handle_t *pamh,
|
||||
const struct ps_state_s *old, struct ps_state_s *new)
|
||||
{
|
||||
const char *rhostname;
|
||||
const char *rusername;
|
||||
int retval;
|
||||
|
||||
retval = pam_get_item(pamh, PAM_RUSER, (const void **) &rusername);
|
||||
if ((retval != PAM_SUCCESS) || (rusername == NULL)) {
|
||||
D(("failed to obtain an rusername"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
|
||||
retval = pam_get_item(pamh, PAM_RHOST, (const void **) &rhostname);
|
||||
if ((retval != PAM_SUCCESS) || (rhostname == NULL)) {
|
||||
D(("failed to identify local hostname: ", pam_strerror(pamh, retval)));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
|
||||
D(("switch on new->state=%d [%s@%s]", new->state, rusername, rhostname));
|
||||
switch (new->state) {
|
||||
|
||||
case PS_STATE_INIT:
|
||||
{
|
||||
const char *user = NULL;
|
||||
|
||||
retval = pam_get_user(pamh, &user, NULL);
|
||||
|
||||
if ((retval == PAM_SUCCESS) && (user == NULL)) {
|
||||
D(("success but no username?"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
retval = PAM_USER_UNKNOWN;
|
||||
}
|
||||
|
||||
if (retval != PAM_SUCCESS) {
|
||||
if (retval == PAM_CONV_AGAIN) {
|
||||
retval = PAM_INCOMPLETE;
|
||||
} else {
|
||||
new->state = PS_STATE_DEAD;
|
||||
}
|
||||
D(("state init failed: %s", pam_strerror(pamh, retval)));
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* nothing else in this 'case' can be retried */
|
||||
|
||||
new->username = strdup(user);
|
||||
if (new->username == NULL) {
|
||||
D(("out of memory"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
if (! generate_cookie(new->server_cookie)) {
|
||||
D(("problem generating server cookie"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
new->current_prompt = NULL;
|
||||
PAM_BP_RENEW(&new->current_prompt, PAM_BPC_SELECT,
|
||||
sizeof(PS_AGENT_ID) + strlen(rusername) + 1
|
||||
+ strlen(rhostname) + 1 + 32);
|
||||
sprintf(PAM_BP_WDATA(new->current_prompt),
|
||||
PS_AGENT_ID "/%s@%s|%.32s", rusername, rhostname,
|
||||
new->server_cookie);
|
||||
|
||||
/* note, the BP is guaranteed by the spec to be <NUL> terminated */
|
||||
D(("initialization packet [%s]", PAM_BP_DATA(new->current_prompt)));
|
||||
|
||||
/* fall through */
|
||||
new->state = PS_STATE_PROMPT1;
|
||||
|
||||
D(("fall through to state_prompt1"));
|
||||
}
|
||||
|
||||
case PS_STATE_PROMPT1:
|
||||
{
|
||||
int i, length;
|
||||
|
||||
/* send {secret@here/jdoe@client.host|<s_cookie>} */
|
||||
retval = converse(pamh, new);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
if (retval == PAM_CONV_AGAIN) {
|
||||
D(("conversation failed to complete"));
|
||||
return PAM_INCOMPLETE;
|
||||
} else {
|
||||
new->state = PS_STATE_DEAD;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval != PAM_SUCCESS) {
|
||||
D(("failed to read ruser@rhost"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
|
||||
/* expect to receive the following {<seqid>|<a_cookie>} */
|
||||
if (new->current_reply == NULL) {
|
||||
D(("converstation returned [%s] but gave no reply",
|
||||
pam_strerror(pamh, retval)));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
/* find | */
|
||||
length = PAM_BP_LENGTH(new->current_reply);
|
||||
for (i=0; i<length; ++i) {
|
||||
if (PAM_BP_RDATA(new->current_reply)[i] == '|') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= length) {
|
||||
D(("malformed response (no |) of length %d", length));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
if ((length - ++i) != 32) {
|
||||
D(("cookie is incorrect length (%d,%d) %d != 32",
|
||||
length, i, length-i));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
/* copy client cookie */
|
||||
memcpy(new->client_cookie, PAM_BP_RDATA(new->current_reply)+i, 32);
|
||||
|
||||
/* generate a prompt that is length(seqid) + length(|) + 32 long */
|
||||
PAM_BP_RENEW(&new->current_prompt, PAM_BPC_OK, i+32);
|
||||
/* copy the head of the response prompt */
|
||||
memcpy(PAM_BP_WDATA(new->current_prompt),
|
||||
PAM_BP_RDATA(new->current_reply), i);
|
||||
PAM_BP_RENEW(&new->current_reply, 0, 0);
|
||||
|
||||
/* look up the secret */
|
||||
new->invalid_secret = 0;
|
||||
|
||||
if (new->secret_data == NULL) {
|
||||
char *ruser_rhost;
|
||||
|
||||
ruser_rhost = malloc(strlen(rusername)+2+strlen(rhostname));
|
||||
if (ruser_rhost == NULL) {
|
||||
D(("out of memory"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
sprintf(ruser_rhost, "%s@%s", rusername, rhostname);
|
||||
new->secret_data = identify_secret(ruser_rhost, new->username);
|
||||
|
||||
memset(ruser_rhost, 0, strlen(ruser_rhost));
|
||||
free(ruser_rhost);
|
||||
}
|
||||
|
||||
if (new->secret_data == NULL) {
|
||||
D(("secret not found for user"));
|
||||
new->invalid_secret = 1;
|
||||
|
||||
/* need to make up a secret */
|
||||
new->secret_data = malloc(32 + 1);
|
||||
if (new->secret_data == NULL) {
|
||||
D(("out of memory"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
if (! generate_cookie(new->secret_data)) {
|
||||
D(("what's up - no fake cookie generated?"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
/* construct md5[<client_cookie>|<server_cookie>|<secret_data>] */
|
||||
if (! create_digest(new->client_cookie, new->server_cookie,
|
||||
new->secret_data,
|
||||
PAM_BP_WDATA(new->current_prompt)+i)) {
|
||||
D(("md5 digesting failed"));
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
/* prompt2 is now constructed - fall through to send it */
|
||||
}
|
||||
|
||||
case PS_STATE_PROMPT2:
|
||||
{
|
||||
/* send {<seqid>|md5[<client_cookie>|<server_cookie>|<secret_data>]} */
|
||||
retval = converse(pamh, new);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
if (retval == PAM_CONV_AGAIN) {
|
||||
D(("conversation failed to complete"));
|
||||
return PAM_INCOMPLETE;
|
||||
} else {
|
||||
new->state = PS_STATE_DEAD;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* After we complete this section, we should not be able to
|
||||
recall this authentication function. So, we force all
|
||||
future calls into the weeds. */
|
||||
|
||||
new->state = PS_STATE_DEAD;
|
||||
|
||||
/* expect reply:{md5[<secret_data>|<server_cookie>|<client_cookie>]} */
|
||||
|
||||
{
|
||||
int cf;
|
||||
char expectation[33];
|
||||
|
||||
if (!create_digest(new->secret_data, new->server_cookie,
|
||||
new->client_cookie, expectation)) {
|
||||
new->state = PS_STATE_DEAD;
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
cf = strcmp(expectation, PAM_BP_RDATA(new->current_reply));
|
||||
memset(expectation, 0, sizeof(expectation));
|
||||
if (cf || new->invalid_secret) {
|
||||
D(("failed to authenticate"));
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
D(("correctly authenticated :)"));
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
default:
|
||||
new->state = PS_STATE_DEAD;
|
||||
|
||||
case PS_STATE_DEAD:
|
||||
|
||||
D(("state is currently dead/unknown"));
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
|
||||
fprintf(stderr, "pam_secret: this should not be reached\n");
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
static void clean_data(pam_handle_t *pamh, void *datum, int error_status)
|
||||
{
|
||||
struct ps_state_s *data = datum;
|
||||
|
||||
D(("liberating datum=%p", datum));
|
||||
|
||||
if (data) {
|
||||
D(("renew prompt"));
|
||||
PAM_BP_RENEW(&data->current_prompt, 0, 0);
|
||||
D(("renew reply"));
|
||||
PAM_BP_RENEW(&data->current_reply, 0, 0);
|
||||
D(("overwrite datum"));
|
||||
memset(data, 0, sizeof(struct ps_state_s));
|
||||
D(("liberate datum"));
|
||||
free(data);
|
||||
}
|
||||
|
||||
D(("done."));
|
||||
}
|
||||
|
||||
/*
|
||||
* front end for the authentication function
|
||||
*/
|
||||
|
||||
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int retval;
|
||||
struct ps_state_s *new_data;
|
||||
const struct ps_state_s *old_data;
|
||||
|
||||
D(("called"));
|
||||
|
||||
new_data = calloc(1, sizeof(struct ps_state_s));
|
||||
if (new_data == NULL) {
|
||||
D(("out of memory"));
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
new_data->retval = PAM_SUCCESS;
|
||||
|
||||
retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data);
|
||||
if (retval == PAM_SUCCESS) {
|
||||
new_data->state = old_data->state;
|
||||
memcpy(new_data->server_cookie, old_data->server_cookie, 32);
|
||||
memcpy(new_data->client_cookie, old_data->client_cookie, 32);
|
||||
if (old_data->username) {
|
||||
new_data->username = strdup(old_data->username);
|
||||
}
|
||||
if (old_data->secret_data) {
|
||||
new_data->secret_data = strdup(old_data->secret_data);
|
||||
}
|
||||
if (old_data->current_prompt) {
|
||||
int length;
|
||||
|
||||
length = PAM_BP_LENGTH(old_data->current_prompt);
|
||||
PAM_BP_RENEW(&new_data->current_prompt,
|
||||
PAM_BP_CONTROL(old_data->current_prompt), length);
|
||||
PAM_BP_FILL(new_data->current_prompt, 0, length,
|
||||
PAM_BP_RDATA(old_data->current_prompt));
|
||||
}
|
||||
/* don't need to duplicate current_reply */
|
||||
} else {
|
||||
old_data = NULL;
|
||||
new_data->state = PS_STATE_INIT;
|
||||
}
|
||||
|
||||
D(("call auth_sequence"));
|
||||
new_data->retval = auth_sequence(pamh, old_data, new_data);
|
||||
D(("returned from auth_sequence"));
|
||||
|
||||
retval = pam_set_data(pamh, PS_STATE_ID, new_data, clean_data);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
D(("unable to store new_data"));
|
||||
} else {
|
||||
retval = new_data->retval;
|
||||
}
|
||||
|
||||
old_data = new_data = NULL;
|
||||
|
||||
D(("done (%d)", retval));
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* front end for the credential setting function
|
||||
*/
|
||||
|
||||
#define AUTH_SESSION_TICKET_ENV_FORMAT "AUTH_SESSION_TICKET="
|
||||
|
||||
int pam_sm_setcred(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int retval;
|
||||
const struct ps_state_s *old_data;
|
||||
|
||||
D(("called"));
|
||||
|
||||
/* XXX - need to pay attention to the various flavors of call */
|
||||
|
||||
/* XXX - need provide an option to turn this feature on/off: if
|
||||
other modules want to supply an AUTH_SESSION_TICKET, we should
|
||||
leave it up to the admin which module dominiates. */
|
||||
|
||||
retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
D(("no data to base decision on"));
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* If ok, export a derived shared secret session ticket to the
|
||||
* client's PAM environment - the ticket has the form
|
||||
*
|
||||
* AUTH_SESSION_TICKET =
|
||||
* md5[<server_cookie>|<secret_data>|<client_cookie>]
|
||||
*
|
||||
* This is a precursor to supporting a spoof resistant trusted
|
||||
* path mechanism. This shared secret ticket can be used to add
|
||||
* a hard-to-guess checksum to further authentication data.
|
||||
*/
|
||||
|
||||
retval = old_data->retval;
|
||||
if (retval == PAM_SUCCESS) {
|
||||
char envticket[sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)+32];
|
||||
|
||||
memcpy(envticket, AUTH_SESSION_TICKET_ENV_FORMAT,
|
||||
sizeof(AUTH_SESSION_TICKET_ENV_FORMAT));
|
||||
|
||||
if (! create_digest(old_data->server_cookie, old_data->secret_data,
|
||||
old_data->client_cookie,
|
||||
envticket+sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)-1
|
||||
)) {
|
||||
D(("unable to generate a digest for session ticket"));
|
||||
return PAM_ABORT;
|
||||
}
|
||||
|
||||
D(("putenv[%s]", envticket));
|
||||
retval = pam_putenv(pamh, envticket);
|
||||
memset(envticket, 0, sizeof(envticket));
|
||||
}
|
||||
|
||||
old_data = NULL;
|
||||
D(("done (%d)", retval));
|
||||
|
||||
return retval;
|
||||
}
|
7
contrib/libpam/libpamc/test/regress/Makefile
Normal file
7
contrib/libpam/libpamc/test/regress/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
CFLAGS = -g -I ../../include
|
||||
|
||||
test.libpamc: test.libpamc.o
|
||||
$(CC) -o $@ $< -L ../.. -lpamc
|
||||
|
||||
clean:
|
||||
rm -f test.libpamc test.libpamc.o
|
6
contrib/libpam/libpamc/test/regress/run_test.sh
Executable file
6
contrib/libpam/libpamc/test/regress/run_test.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LD_LIBRARY_PATH=../..
|
||||
export PAMC_AGENT_PATH="../agents"
|
||||
|
||||
./test.libpamc
|
342
contrib/libpam/libpamc/test/regress/test.libpamc.c
Normal file
342
contrib/libpam/libpamc/test/regress/test.libpamc.c
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* This is a small test program for testing libpamc against the
|
||||
* secret@here agent. It does the same as the test.secret@here perl
|
||||
* script in this directory, but via the libpamc API.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <security/pam_client.h>
|
||||
#include <ctype.h>
|
||||
|
||||
struct internal_packet {
|
||||
int length;
|
||||
int at;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
|
||||
void append_data(struct internal_packet *packet, int extra, const char *data)
|
||||
{
|
||||
if ((extra + packet->at) >= packet->length) {
|
||||
if (packet->length == 0) {
|
||||
packet->length = 1000;
|
||||
}
|
||||
/* make sure we have at least a char extra space available */
|
||||
while (packet->length <= (extra + packet->at)) {
|
||||
packet->length <<= 1;
|
||||
}
|
||||
packet->buffer = realloc(packet->buffer, packet->length);
|
||||
if (packet->buffer == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
memcpy(packet->at + packet->buffer, data, extra);
|
||||
}
|
||||
packet->at += extra;
|
||||
|
||||
/* assisting string manipulation */
|
||||
packet->buffer[packet->at] = '\0';
|
||||
}
|
||||
|
||||
void append_string(struct internal_packet *packet, const char *string,
|
||||
int with_nul)
|
||||
{
|
||||
append_data(packet, strlen(string) + (with_nul ? 1:0), string);
|
||||
}
|
||||
|
||||
char *identify_secret(char *identity)
|
||||
{
|
||||
struct internal_packet temp_packet;
|
||||
FILE *secrets;
|
||||
int length_id;
|
||||
|
||||
temp_packet.length = temp_packet.at = 0;
|
||||
temp_packet.buffer = NULL;
|
||||
|
||||
append_string(&temp_packet, "/home/", 0);
|
||||
append_string(&temp_packet, getlogin(), 0);
|
||||
append_string(&temp_packet, "/.secret@here", 1);
|
||||
|
||||
secrets = fopen(temp_packet.buffer, "r");
|
||||
if (secrets == NULL) {
|
||||
fprintf(stderr, "server: failed to open\n [%s]\n",
|
||||
temp_packet.buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
length_id = strlen(identity);
|
||||
for (;;) {
|
||||
char *secret = NULL;
|
||||
temp_packet.at = 0;
|
||||
|
||||
if (fgets(temp_packet.buffer, temp_packet.length, secrets) == NULL) {
|
||||
fclose(secrets);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (memcmp(temp_packet.buffer, identity, length_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(secrets);
|
||||
for (secret=temp_packet.buffer; *secret; ++secret) {
|
||||
if (*secret == ' ' || *secret == '\n' || *secret == '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; *secret; ++secret) {
|
||||
if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (temp_packet.buffer=secret; *temp_packet.buffer;
|
||||
++temp_packet.buffer) {
|
||||
if (*temp_packet.buffer == ' ' || *temp_packet.buffer == '\n'
|
||||
|| *temp_packet.buffer == '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*temp_packet.buffer) {
|
||||
*temp_packet.buffer = '\0';
|
||||
}
|
||||
|
||||
return secret;
|
||||
}
|
||||
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a hack, and is fundamentally insecure. All our secrets will be
|
||||
* displayed on the command line for someone doing 'ps' to see. This
|
||||
* is just for programming convenience in this instance, since this
|
||||
* program is simply a regression test. The pam_secret module should
|
||||
* not do this, but make use of md5 routines directly.
|
||||
*/
|
||||
|
||||
char *create_digest(int length, const char *raw)
|
||||
{
|
||||
struct internal_packet temp_packet;
|
||||
FILE *pipe;
|
||||
|
||||
temp_packet.length = temp_packet.at = 0;
|
||||
temp_packet.buffer = NULL;
|
||||
|
||||
append_string(&temp_packet, "echo -n '", 0);
|
||||
append_string(&temp_packet, raw, 0);
|
||||
append_string(&temp_packet, "'|/usr/bin/md5sum -", 1);
|
||||
|
||||
fprintf(stderr, "am attempting to run [%s]\n", temp_packet.buffer);
|
||||
|
||||
pipe = popen(temp_packet.buffer, "r");
|
||||
if (pipe == NULL) {
|
||||
fprintf(stderr, "server: failed to run\n [%s]\n", temp_packet.buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
temp_packet.at = 0;
|
||||
append_data(&temp_packet, 32, NULL);
|
||||
|
||||
if (fgets(temp_packet.buffer, 33, pipe) == NULL) {
|
||||
fprintf(stderr, "server: failed to read digest\n");
|
||||
exit(1);
|
||||
}
|
||||
if (strlen(temp_packet.buffer) != 32) {
|
||||
fprintf(stderr, "server: digest was not 32 chars?? [%s]\n",
|
||||
temp_packet.buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fclose(pipe);
|
||||
|
||||
return temp_packet.buffer;
|
||||
}
|
||||
|
||||
void packet_to_prompt(pamc_bp_t *prompt_p, __u8 control,
|
||||
struct internal_packet *packet)
|
||||
{
|
||||
PAM_BP_RENEW(prompt_p, control, packet->at);
|
||||
PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer);
|
||||
packet->at = 0;
|
||||
}
|
||||
|
||||
void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet)
|
||||
{
|
||||
int data_length;
|
||||
|
||||
data_length = PAM_BP_LENGTH(prompt);
|
||||
packet->at = 0;
|
||||
append_data(packet, data_length, NULL);
|
||||
|
||||
PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer);
|
||||
|
||||
fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n",
|
||||
data_length,
|
||||
PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt),
|
||||
PAM_BP_RDATA(prompt));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pamc_handle_t pch;
|
||||
pamc_bp_t prompt = NULL;
|
||||
struct internal_packet packet_data, *packet;
|
||||
char *temp_string, *secret, *user, *a_cookie, *seqid, *digest;
|
||||
const char *cookie = "123451234512345";
|
||||
int retval;
|
||||
|
||||
packet = &packet_data;
|
||||
packet->length = 0;
|
||||
packet->at = 0;
|
||||
packet->buffer = NULL;
|
||||
|
||||
pch = pamc_start();
|
||||
if (pch == NULL) {
|
||||
fprintf(stderr, "server: unable to get a handle from libpamc\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
temp_string = getlogin();
|
||||
if (temp_string == NULL) {
|
||||
fprintf(stderr, "server: who are you?\n");
|
||||
exit(1);
|
||||
}
|
||||
#define DOMAIN "@local.host"
|
||||
user = malloc(1+strlen(temp_string)+strlen(DOMAIN));
|
||||
if (user == NULL) {
|
||||
fprintf(stderr, "server: out of memory for user id\n");
|
||||
exit(1);
|
||||
}
|
||||
sprintf(user, "%s%s", temp_string, DOMAIN);
|
||||
|
||||
append_string(packet, "secret@here/", 0);
|
||||
append_string(packet, user, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, cookie, 0);
|
||||
packet_to_prompt(&prompt, PAM_BPC_SELECT, packet);
|
||||
|
||||
/* get the library to accept the first packet (which should load
|
||||
the secret@here agent) */
|
||||
|
||||
retval = pamc_converse(pch, &prompt);
|
||||
fprintf(stderr, "server: after conversation\n");
|
||||
if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) {
|
||||
fprintf(stderr, "server: prompt had unexpected control type: %u\n",
|
||||
PAM_BP_RCONTROL(prompt));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "server: got a prompt back\n");
|
||||
|
||||
prompt_to_packet(prompt, packet);
|
||||
|
||||
temp_string = strtok(packet->buffer, "|");
|
||||
if (temp_string == NULL) {
|
||||
fprintf(stderr, "server: prompt does not contain anything");
|
||||
exit(1);
|
||||
}
|
||||
seqid = strdup(temp_string);
|
||||
if (seqid == NULL) {
|
||||
fprintf(stderr, "server: unable to store sequence id\n");
|
||||
}
|
||||
|
||||
temp_string = strtok(NULL, "|");
|
||||
if (temp_string == NULL) {
|
||||
fprintf(stderr, "server: no cookie from agent\n");
|
||||
exit(1);
|
||||
}
|
||||
a_cookie = strdup(temp_string);
|
||||
if (a_cookie == NULL) {
|
||||
fprintf(stderr, "server: no memory to store agent cookie\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie);
|
||||
secret = identify_secret(user);
|
||||
fprintf(stderr, "server: secret=%s\n", secret);
|
||||
|
||||
/* now, we construct the response */
|
||||
packet->at = 0;
|
||||
append_string(packet, a_cookie, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, cookie, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, secret, 0);
|
||||
|
||||
fprintf(stderr, "server: get digest of %s\n", packet->buffer);
|
||||
|
||||
digest = create_digest(packet->at, packet->buffer);
|
||||
|
||||
fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest);
|
||||
|
||||
packet->at = 0;
|
||||
append_string(packet, seqid, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, digest, 0);
|
||||
packet_to_prompt(&prompt, PAM_BPC_OK, packet);
|
||||
|
||||
retval = pamc_converse(pch, &prompt);
|
||||
fprintf(stderr, "server: after 2nd conversation\n");
|
||||
if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) {
|
||||
fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n",
|
||||
PAM_BP_RCONTROL(prompt));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
prompt_to_packet(prompt, packet);
|
||||
PAM_BP_RENEW(&prompt, 0, 0);
|
||||
|
||||
temp_string = strtok(packet->buffer, "|");
|
||||
if (temp_string == NULL) {
|
||||
fprintf(stderr, "no digest from agent\n");
|
||||
exit(1);
|
||||
}
|
||||
temp_string = strdup(temp_string);
|
||||
|
||||
packet->at = 0;
|
||||
append_string(packet, secret, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, cookie, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, a_cookie, 0);
|
||||
|
||||
fprintf(stderr, "server: get digest of %s\n", packet->buffer);
|
||||
|
||||
digest = create_digest(packet->at, packet->buffer);
|
||||
|
||||
fprintf(stderr, "server: digest=%s\n", digest);
|
||||
|
||||
if (strcmp(digest, temp_string)) {
|
||||
fprintf(stderr, "server: agent doesn't know the secret\n");
|
||||
fprintf(stderr, "server: agent says: [%s]\n"
|
||||
"server: server says: [%s]\n", temp_string, digest);
|
||||
exit(1);
|
||||
} else {
|
||||
fprintf(stderr, "server: agent seems to know the secret\n");
|
||||
|
||||
packet->at = 0;
|
||||
append_string(packet, cookie, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, secret, 0);
|
||||
append_string(packet, "|", 0);
|
||||
append_string(packet, a_cookie, 0);
|
||||
|
||||
digest = create_digest(packet->at, packet->buffer);
|
||||
|
||||
fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n",
|
||||
digest);
|
||||
}
|
||||
|
||||
|
||||
retval = pamc_end(&pch);
|
||||
|
||||
fprintf(stderr, "server: agent(s) were %shappy to terminate\n",
|
||||
retval == PAM_BPC_TRUE ? "":"un");
|
||||
|
||||
exit(!retval);
|
||||
}
|
152
contrib/libpam/libpamc/test/regress/test.secret@here
Executable file
152
contrib/libpam/libpamc/test/regress/test.secret@here
Executable file
@ -0,0 +1,152 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
##
|
||||
## this is a test script for regressing changes to the secret@here PAM
|
||||
## agent
|
||||
##
|
||||
|
||||
$^W = 1;
|
||||
use strict;
|
||||
use IPC::Open2;
|
||||
|
||||
$| = 1;
|
||||
|
||||
my $whoami = `/usr/bin/whoami`; chomp $whoami;
|
||||
my $cookie = "12345";
|
||||
my $user_domain = "$whoami\@local.host";
|
||||
|
||||
my $pid = open2(\*Reader, \*Writer, "../agents/secret\@here blah")
|
||||
or die "failed to load secret\@here agent";
|
||||
|
||||
unless (-f (getpwuid($<))[7]."/.secret\@here") {
|
||||
print STDERR "server: ". "no " .(getpwuid($<))[7]. "/.secret\@here file\n";
|
||||
die "no config file";
|
||||
}
|
||||
|
||||
WriteBinaryPrompt(\*Writer, 0x02, "secret\@here/$user_domain|$cookie");
|
||||
|
||||
my ($control, $data) = ReadBinaryPrompt(\*Reader);
|
||||
|
||||
print STDERR "server: ". "reply: control=$control, data=$data\n";
|
||||
if ($control != 1) {
|
||||
die "expected 1 (OK) for the first agent reply; got $control";
|
||||
}
|
||||
my ($seqid, $a_cookie) = split '\|', $data;
|
||||
|
||||
# server needs to convince agent that it knows the secret before
|
||||
# agent will give a valid response
|
||||
my $secret = IdentifyLocalSecret($user_domain);
|
||||
my $digest = CreateDigest($a_cookie."|".$cookie."|".$secret);
|
||||
|
||||
print STDERR "server: ". "digest = $digest\n";
|
||||
WriteBinaryPrompt(\*Writer, 0x01, "$seqid|$digest");
|
||||
|
||||
# The agent will authenticate us and then reply with its
|
||||
# authenticating digest. we check that before we're done.
|
||||
|
||||
($control, $data) = ReadBinaryPrompt(\*Reader);
|
||||
if ($control != 0x03) {
|
||||
die "server: agent did not reply with a 'done' prompt ($control)\n";
|
||||
}
|
||||
|
||||
unless ($data eq CreateDigest($secret."|".$cookie."|".$a_cookie)) {
|
||||
die "server: agent is not authenticated\n";
|
||||
}
|
||||
|
||||
print STDERR "server: agent appears to know secret\n";
|
||||
|
||||
my $session_authenticated_ticket
|
||||
= CreateDigest($cookie."|".$secret."|".$a_cookie);
|
||||
|
||||
print STDERR "server: should putenv("
|
||||
."\"AUTH_SESSION_TICKET=$session_authenticated_ticket\")\n";
|
||||
|
||||
exit 0;
|
||||
|
||||
sub CreateDigest ($) {
|
||||
my ($data) = @_;
|
||||
|
||||
my $pid = open2(\*MD5out, \*MD5in, "/usr/bin/md5sum -")
|
||||
or die "you'll need /usr/bin/md5sum installed";
|
||||
|
||||
my $oldfd = select MD5in; $|=1; select $oldfd;
|
||||
print MD5in "$data";
|
||||
close MD5in;
|
||||
my $reply = <MD5out>;
|
||||
($reply) = split /\s/, $reply;
|
||||
print STDERR "server: ". "md5 said: <$reply>\n";
|
||||
close MD5out;
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
sub ReadBinaryPrompt ($) {
|
||||
my ($fd) = @_;
|
||||
|
||||
my $buffer = " ";
|
||||
my $count = read($fd, $buffer, 5);
|
||||
if ($count == 0) {
|
||||
# no more packets to read
|
||||
return (0, "");
|
||||
}
|
||||
|
||||
if ($count != 5) {
|
||||
# broken packet header
|
||||
return (-1, "");
|
||||
}
|
||||
|
||||
my ($length, $control) = unpack("N C", $buffer);
|
||||
if ($length < 5) {
|
||||
# broken packet length
|
||||
return (-1, "");
|
||||
}
|
||||
|
||||
my $data = "";
|
||||
$length -= 5;
|
||||
while ($count = read($fd, $buffer, $length)) {
|
||||
$data .= $buffer;
|
||||
if ($count != $length) {
|
||||
$length -= $count;
|
||||
next;
|
||||
}
|
||||
|
||||
print STDERR "server: ". "data is [$data]\n";
|
||||
|
||||
return ($control, $data);
|
||||
}
|
||||
|
||||
# broken packet data
|
||||
return (-1, "");
|
||||
}
|
||||
|
||||
sub WriteBinaryPrompt ($$$) {
|
||||
my ($fd, $control, $data) = @_;
|
||||
|
||||
my $length = 5 + length($data);
|
||||
printf STDERR "server: ". "{%d|0x%.2x|%s}\n", $length, $control, $data;
|
||||
my $bp = pack("N C a*", $length, $control, $data);
|
||||
print $fd $bp;
|
||||
|
||||
print STDERR "server: ". "control passed to agent\@here\n";
|
||||
}
|
||||
|
||||
sub IdentifyLocalSecret ($) {
|
||||
my ($identifier) = @_;
|
||||
my $secret;
|
||||
|
||||
my $whoami = `/usr/bin/whoami` ; chomp $whoami;
|
||||
if (open SECRETS, "< " .(getpwuid($<))[7]. "/.secret\@here") {
|
||||
my $line;
|
||||
while (defined ($line = <SECRETS>)) {
|
||||
my ($id, $sec) = split /[\s]/, $line;
|
||||
if ((defined $id) && ($id eq $identifier)) {
|
||||
$secret = $sec;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close SECRETS;
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
92
contrib/libpam/modules/Simple.Rules
Normal file
92
contrib/libpam/modules/Simple.Rules
Normal file
@ -0,0 +1,92 @@
|
||||
# $Id: Simple.Rules,v 1.3 2001/02/22 04:55:41 agmorgan Exp $
|
||||
#
|
||||
# For simple modules with no significant dependencies, set $(TITLE)
|
||||
# and include this file.
|
||||
#
|
||||
# There are a few ways to customize this set of rules. Namely, define
|
||||
#
|
||||
# $(MODULE_SIMPLE_EXTRACLEAN)
|
||||
# $(MODULE_SIMPLE_CLEAN)
|
||||
# $(MODULE_SIMPLE_REMOVE)
|
||||
# $(MODULE_SIMPLE_INSTALL)
|
||||
# $(MODULE_SIMPLE_EXTRALIBS) - other things to link with the module
|
||||
# $(MODULE_SIMPLE_EXTRAFILES) - other files to build (no .c suffix)
|
||||
#
|
||||
|
||||
LIBFILES = $(TITLE) $(MODULE_SIMPLE_EXTRAFILES)
|
||||
LIBSRC = $(addsuffix .c,$(LIBFILES))
|
||||
LIBOBJ = $(addsuffix .o,$(LIBFILES))
|
||||
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) $(MODULE_SIMPLE_EXTRALIBS) $(NEED_LINK_LIB_C)
|
||||
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(LIBOBJS): $(LIBSRC)
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(LIBSTATIC): $(LIBOBJS)
|
||||
$(LD) -r -o $@ $(LIBOBJS) $(MODULE_SIMPLE_EXTRALIBS)
|
||||
endif
|
||||
|
||||
install: all
|
||||
$(MKDIR) $(FAKEROOT)$(SECUREDIR)
|
||||
ifdef DYNAMIC
|
||||
$(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
|
||||
endif
|
||||
$(MODULE_SIMPLE_INSTALL)
|
||||
|
||||
remove:
|
||||
rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
|
||||
$(MODULE_SIMPLE_REMOVE)
|
||||
|
||||
clean:
|
||||
rm -f $(LIBOBJD) $(LIBOBJS) core *~
|
||||
$(MODULE_SIMPLE_CLEAN)
|
||||
rm -f *.a *.o *.so *.bak
|
||||
rm -rf dynamic static
|
||||
$(MODULE_SIMPLE_EXTRACLEAN)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
30
contrib/libpam/modules/download-all
Executable file
30
contrib/libpam/modules/download-all
Executable file
@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# $Id: download-all,v 1.1.1.1 2000/06/20 22:11:29 agmorgan Exp $
|
||||
#
|
||||
cat <<EOT
|
||||
For a number of reasons it is not practical for Linux-PAM to be
|
||||
distributed with every module out there. However, this shell script
|
||||
is intended as a convenient way for users to download modules from the
|
||||
'net in some semiautomated fashion.
|
||||
|
||||
Please feel free to send (pam-list@redhat.com) snippets of code that
|
||||
will help others to download and unpack your favorite module into the
|
||||
Linux-PAM source tree. Especially welcome are snippets of the
|
||||
following form:
|
||||
|
||||
ncftp ftp://my.ftpsite.org/pub/fluff/pam_fluff.tar.gz
|
||||
rm -fr pam_fluff
|
||||
tar zvfx pam_fluff.tar.gz
|
||||
|
||||
Cheers
|
||||
|
||||
Andrew
|
||||
morgan@linux.kernel.org
|
||||
EOT
|
||||
|
||||
# --- insert your snippets below ---
|
||||
|
||||
# --- insert your snippets above ---
|
||||
|
||||
exit 0
|
49
contrib/libpam/modules/install_conf
Executable file
49
contrib/libpam/modules/install_conf
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
FAKEROOT=$1
|
||||
CONFD=$1$2
|
||||
CONFILE=$1$3
|
||||
MODULE=$4
|
||||
CONF=$5
|
||||
|
||||
IGNORE_AGE=./.ignore_age
|
||||
QUIET_INSTALL=../../.quiet_install
|
||||
|
||||
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 $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
|
15
contrib/libpam/modules/pam_issue/Makefile
Normal file
15
contrib/libpam/modules/pam_issue/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan 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!).
|
||||
#
|
||||
# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27
|
||||
#
|
||||
|
||||
include ../../Make.Rules
|
||||
|
||||
TITLE=pam_issue
|
||||
|
||||
include ../Simple.Rules
|
266
contrib/libpam/modules/pam_issue/pam_issue.c
Normal file
266
contrib/libpam/modules/pam_issue/pam_issue.c
Normal file
@ -0,0 +1,266 @@
|
||||
/* pam_issue module - a simple /etc/issue parser to set PAM_USER_PROMPT
|
||||
*
|
||||
* Copyright 1999 by Ben Collins <bcollins@debian.org>
|
||||
*
|
||||
* Needs to be called before any other auth modules so we can setup the
|
||||
* user prompt before it's first used. Allows one argument option, which
|
||||
* is the full path to a file to be used for issue (uses /etc/issue as a
|
||||
* default) such as "issue=/etc/issue.telnet".
|
||||
*
|
||||
* We can also parse escapes within the the issue file (enabled by
|
||||
* default, but can be disabled with the "noesc" option). It's the exact
|
||||
* same parsing as util-linux's agetty program performs.
|
||||
*
|
||||
* Released under the GNU LGPL version 2 or later
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <utmp.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
#define PAM_SM_AUTH
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
|
||||
static int _user_prompt_set = 0;
|
||||
|
||||
char *do_prompt (FILE *);
|
||||
|
||||
/* --- 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;
|
||||
FILE *fd;
|
||||
int parse_esc = 1;
|
||||
char *prompt_tmp = NULL, *cur_prompt = NULL;
|
||||
struct stat st;
|
||||
char *issue_file = NULL;
|
||||
|
||||
/* If we've already set the prompt, don't set it again */
|
||||
if(_user_prompt_set)
|
||||
return PAM_IGNORE;
|
||||
else
|
||||
/* we set this here so if we fail below, we wont get further
|
||||
than this next time around (only one real failure) */
|
||||
_user_prompt_set = 1;
|
||||
|
||||
for ( ; argc-- > 0 ; ++argv ) {
|
||||
if (!strncmp(*argv,"issue=",6)) {
|
||||
issue_file = (char *) strdup(6+*argv);
|
||||
if (issue_file != NULL) {
|
||||
D(("set issue_file to: %s", issue_file));
|
||||
} else {
|
||||
D(("failed to strdup issue_file - ignored"));
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
} else if (!strcmp(*argv,"noesc")) {
|
||||
parse_esc = 0;
|
||||
D(("turning off escape parsing by request"));
|
||||
} else
|
||||
D(("unknown option passed: %s", *argv));
|
||||
}
|
||||
|
||||
if (issue_file == NULL)
|
||||
issue_file = strdup("/etc/issue");
|
||||
|
||||
if ((fd = fopen(issue_file, "r")) != NULL) {
|
||||
int tot_size = 0;
|
||||
|
||||
if (stat(issue_file, &st) < 0)
|
||||
return PAM_IGNORE;
|
||||
|
||||
retval = pam_get_item(pamh, PAM_USER_PROMPT, (const void **) &cur_prompt);
|
||||
if (retval != PAM_SUCCESS)
|
||||
return PAM_IGNORE;
|
||||
|
||||
/* first read in the issue file */
|
||||
|
||||
if (parse_esc)
|
||||
prompt_tmp = do_prompt(fd);
|
||||
else {
|
||||
int count = 0;
|
||||
prompt_tmp = malloc(st.st_size + 1);
|
||||
if (prompt_tmp == NULL) return PAM_IGNORE;
|
||||
memset (prompt_tmp, '\0', st.st_size + 1);
|
||||
count = fread(prompt_tmp, sizeof(char *), st.st_size, fd);
|
||||
prompt_tmp[st.st_size] = '\0';
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
|
||||
tot_size = strlen(prompt_tmp) + strlen(cur_prompt) + 1;
|
||||
|
||||
/*
|
||||
* alloc some extra space for the original prompt
|
||||
* and postpend it to the buffer
|
||||
*/
|
||||
prompt_tmp = realloc(prompt_tmp, tot_size);
|
||||
strcpy(prompt_tmp+strlen(prompt_tmp), cur_prompt);
|
||||
|
||||
prompt_tmp[tot_size] = '\0';
|
||||
|
||||
retval = pam_set_item(pamh, PAM_USER_PROMPT, (const char *) prompt_tmp);
|
||||
|
||||
free(issue_file);
|
||||
free(prompt_tmp);
|
||||
} else {
|
||||
D(("could not open issue_file: %s", issue_file));
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
|
||||
const char **argv)
|
||||
{
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
char *do_prompt(FILE *fd)
|
||||
{
|
||||
int c, size = 1024;
|
||||
char *issue = (char *)malloc(size);
|
||||
char buf[1024];
|
||||
struct utsname uts;
|
||||
|
||||
if (issue == NULL || fd == NULL)
|
||||
return NULL;
|
||||
|
||||
issue[0] = '\0'; /* zero this, for strcat to work on first buf */
|
||||
(void) uname(&uts);
|
||||
|
||||
while ((c = getc(fd)) != EOF) {
|
||||
if (c == '\\') {
|
||||
c = getc(fd);
|
||||
switch (c) {
|
||||
case 's':
|
||||
snprintf (buf, 1024, "%s", uts.sysname);
|
||||
break;
|
||||
case 'n':
|
||||
snprintf (buf, 1024, "%s", uts.nodename);
|
||||
break;
|
||||
case 'r':
|
||||
snprintf (buf, 1024, "%s", uts.release);
|
||||
break;
|
||||
case 'v':
|
||||
snprintf (buf, 1024, "%s", uts.version);
|
||||
break;
|
||||
case 'm':
|
||||
snprintf (buf, 1024, "%s", uts.machine);
|
||||
break;
|
||||
case 'o':
|
||||
{
|
||||
char domainname[256];
|
||||
|
||||
getdomainname(domainname, sizeof(domainname));
|
||||
domainname[sizeof(domainname)-1] = '\0';
|
||||
snprintf (buf, 1024, "%s", domainname);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 't':
|
||||
{
|
||||
const char *weekday[] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu",
|
||||
"Fri", "Sat" };
|
||||
const char *month[] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May",
|
||||
"Jun", "Jul", "Aug", "Sep", "Oct",
|
||||
"Nov", "Dec" };
|
||||
time_t now;
|
||||
struct tm *tm;
|
||||
|
||||
(void) time (&now);
|
||||
tm = localtime(&now);
|
||||
|
||||
if (c == 'd')
|
||||
snprintf (buf, 1024, "%s %s %d %d",
|
||||
weekday[tm->tm_wday], month[tm->tm_mon],
|
||||
tm->tm_mday,
|
||||
tm->tm_year + 1900);
|
||||
else
|
||||
snprintf (buf, 1024, "%02d:%02d:%02d",
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
char *ttyn = ttyname(1);
|
||||
if (!strncmp(ttyn, "/dev/", 5))
|
||||
ttyn += 5;
|
||||
snprintf (buf, 1024, "%s", ttyn);
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
{
|
||||
int users = 0;
|
||||
struct utmp *ut;
|
||||
setutent();
|
||||
while ((ut = getutent()))
|
||||
if (ut->ut_type == USER_PROCESS)
|
||||
users++;
|
||||
endutent();
|
||||
printf ("%d ", users);
|
||||
if (c == 'U')
|
||||
snprintf (buf, 1024, "%s", (users == 1) ?
|
||||
" user" : " users");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
buf[0] = c; buf[1] = '\0';
|
||||
}
|
||||
if ((strlen(issue) + strlen(buf)) < size + 1) {
|
||||
size += strlen(buf) + 1;
|
||||
issue = (char *) realloc (issue, size);
|
||||
}
|
||||
strcat(issue, buf);
|
||||
} else {
|
||||
buf[0] = c; buf[1] = '\0';
|
||||
if ((strlen(issue) + strlen(buf)) < size + 1) {
|
||||
size += strlen(buf) + 1;
|
||||
issue = (char *) realloc (issue, size);
|
||||
}
|
||||
strcat(issue, buf);
|
||||
}
|
||||
}
|
||||
return issue;
|
||||
}
|
||||
|
||||
#ifdef PAM_STATIC
|
||||
|
||||
/* static module data */
|
||||
|
||||
struct pam_module _pam_issue_modstruct = {
|
||||
"pam_issue",
|
||||
pam_sm_authenticate,
|
||||
pam_sm_setcred,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* end of module definition */
|
17
contrib/libpam/modules/pam_mail/README
Normal file
17
contrib/libpam/modules/pam_mail/README
Normal file
@ -0,0 +1,17 @@
|
||||
This is the README for pam_mail
|
||||
-------------------------------
|
||||
|
||||
This PAM module tells the User that he has new/unread email.
|
||||
|
||||
Options for:
|
||||
auth: for authentication it provides pam_authenticate() and
|
||||
pam_setcred() hooks.
|
||||
|
||||
"debug" write more information to syslog
|
||||
"dir=maildir" users mailbox is maildir/<login>
|
||||
"hash=count" mail directory hash depth
|
||||
"close" print message also on logout
|
||||
"nopen" print message not on login
|
||||
"noenv" don't set the MAIL environment variable
|
||||
"empty" also print message if user has no mail
|
||||
|
15
contrib/libpam/modules/pam_mkhomedir/Makefile
Normal file
15
contrib/libpam/modules/pam_mkhomedir/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.3 2000/11/19 23:54:04 agmorgan 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!).
|
||||
#
|
||||
# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27
|
||||
#
|
||||
|
||||
include ../../Make.Rules
|
||||
|
||||
TITLE=pam_mkhomedir
|
||||
|
||||
include ../Simple.Rules
|
370
contrib/libpam/modules/pam_mkhomedir/pam_mkhomedir.c
Normal file
370
contrib/libpam/modules/pam_mkhomedir/pam_mkhomedir.c
Normal file
@ -0,0 +1,370 @@
|
||||
/* PAM Make Home Dir module
|
||||
|
||||
This module will create a users home directory if it does not exist
|
||||
when the session begins. This allows users to be present in central
|
||||
database (such as nis, kerb or ldap) without using a distributed
|
||||
file system or pre-creating a large number of directories.
|
||||
|
||||
Here is a sample /etc/pam.d/login file for Debian GNU/Linux
|
||||
2.1:
|
||||
|
||||
auth requisite pam_securetty.so
|
||||
auth sufficient pam_ldap.so
|
||||
auth required pam_pwdb.so
|
||||
auth optional pam_group.so
|
||||
auth optional pam_mail.so
|
||||
account requisite pam_time.so
|
||||
account sufficient pam_ldap.so
|
||||
account required pam_pwdb.so
|
||||
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
|
||||
session required pam_pwdb.so
|
||||
session optional pam_lastlog.so
|
||||
password required pam_pwdb.so
|
||||
|
||||
Released under the GNU LGPL version 2 or later
|
||||
Originally written by Jason Gunthorpe <jgg@debian.org> Feb 1999
|
||||
Structure taken from pam_lastlogin by Andrew Morgan
|
||||
<morgan@parc.power.net> 1996
|
||||
*/
|
||||
|
||||
/* I want snprintf dammit */
|
||||
#define _GNU_SOURCE 1
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.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_SESSION
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
/* argument parsing */
|
||||
#define MKHOMEDIR_DEBUG 020 /* keep quiet about things */
|
||||
#define MKHOMEDIR_QUIET 040 /* keep quiet about things */
|
||||
|
||||
static unsigned int UMask = 0022;
|
||||
static char SkelDir[BUFSIZ] = "/etc/skel";
|
||||
|
||||
/* some syslogging */
|
||||
static void _log_err(int err, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
openlog("PAM-mkhomedir", LOG_CONS|LOG_PID, LOG_AUTH);
|
||||
vsyslog(err, format, args);
|
||||
va_end(args);
|
||||
closelog();
|
||||
}
|
||||
|
||||
static int _pam_parse(int flags, int argc, const char **argv)
|
||||
{
|
||||
int ctrl = 0;
|
||||
|
||||
/* does the appliction require quiet? */
|
||||
if ((flags & PAM_SILENT) == PAM_SILENT)
|
||||
ctrl |= MKHOMEDIR_QUIET;
|
||||
|
||||
/* step through arguments */
|
||||
for (; argc-- > 0; ++argv)
|
||||
{
|
||||
if (!strcmp(*argv, "silent"))
|
||||
{
|
||||
ctrl |= MKHOMEDIR_QUIET;
|
||||
}
|
||||
else if (!strncmp(*argv,"umask=",6))
|
||||
UMask = strtol(*argv+6,0,0);
|
||||
else if (!strncmp(*argv,"skel=",5))
|
||||
strcpy(SkelDir,*argv+5);
|
||||
else
|
||||
{
|
||||
_log_err(LOG_ERR, "unknown option; %s", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
D(("ctrl = %o", ctrl));
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
/* This common function is used to send a message to the applications
|
||||
conversion function. Our only use is to ask the application to print
|
||||
an informative message that we are creating a home directory */
|
||||
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 & MKHOMEDIR_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 */
|
||||
}
|
||||
|
||||
/* Ask the application to display a short text string for us. */
|
||||
static int make_remark(pam_handle_t * pamh, int ctrl, const char *remark)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if ((ctrl & MKHOMEDIR_QUIET) != MKHOMEDIR_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;
|
||||
}
|
||||
|
||||
/* Do the actual work of creating a home dir */
|
||||
static int create_homedir(pam_handle_t * pamh, int ctrl,
|
||||
const struct passwd *pwd)
|
||||
{
|
||||
char *remark;
|
||||
DIR *D;
|
||||
struct dirent *Dir;
|
||||
|
||||
/* Some scratch space */
|
||||
remark = malloc(BUFSIZ);
|
||||
if (remark == NULL)
|
||||
{
|
||||
D(("no memory for last login remark"));
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
/* Mention what is happening, if the notification fails that is OK */
|
||||
if (snprintf(remark,BUFSIZ,"Creating home directory '%s'.",
|
||||
pwd->pw_dir) == -1)
|
||||
return PAM_PERM_DENIED;
|
||||
|
||||
make_remark(pamh, ctrl, remark);
|
||||
|
||||
/* Crete the home directory */
|
||||
if (mkdir(pwd->pw_dir,0700) != 0)
|
||||
{
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to create home directory %s",pwd->pw_dir);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
if (chmod(pwd->pw_dir,0777 & (~UMask)) != 0 ||
|
||||
chown(pwd->pw_dir,pwd->pw_uid,pwd->pw_gid) != 0)
|
||||
{
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to chance perms on home directory %s",pwd->pw_dir);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
/* See if we need to copy the skel dir over. */
|
||||
if (SkelDir[0] == 0)
|
||||
{
|
||||
free(remark);
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
/* Scan the directory */
|
||||
D = opendir(SkelDir);
|
||||
if (D == 0)
|
||||
{
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to read directory %s",SkelDir);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
for (Dir = readdir(D); Dir != 0; Dir = readdir(D))
|
||||
{
|
||||
int SrcFd;
|
||||
int DestFd;
|
||||
int Res;
|
||||
struct stat St;
|
||||
|
||||
/* Skip some files.. */
|
||||
if (strcmp(Dir->d_name,".") == 0 ||
|
||||
strcmp(Dir->d_name,"..") == 0)
|
||||
continue;
|
||||
|
||||
/* Check if it is a directory */
|
||||
snprintf(remark,BUFSIZ,"%s/%s",SkelDir,Dir->d_name);
|
||||
if (stat(remark,&St) != 0)
|
||||
continue;
|
||||
if (S_ISDIR(St.st_mode))
|
||||
{
|
||||
snprintf(remark,BUFSIZ,"%s/%s",pwd->pw_dir,Dir->d_name);
|
||||
if (mkdir(remark,(St.st_mode | 0222) & (~UMask)) != 0 ||
|
||||
chmod(remark,(St.st_mode | 0222) & (~UMask)) != 0 ||
|
||||
chown(remark,pwd->pw_uid,pwd->pw_gid) != 0)
|
||||
{
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to change perms on copy %s",remark);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Open the source file */
|
||||
if ((SrcFd = open(remark,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0)
|
||||
{
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to open src file %s",remark);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
stat(remark,&St);
|
||||
|
||||
/* Open the dest file */
|
||||
snprintf(remark,BUFSIZ,"%s/%s",pwd->pw_dir,Dir->d_name);
|
||||
if ((DestFd = open(remark,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0)
|
||||
{
|
||||
close(SrcFd);
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to open dest file %s",remark);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
/* Set the proper ownership and permissions for the module. We make
|
||||
the file a+w and then mask it with the set mask. This preseves
|
||||
execute bits */
|
||||
if (fchmod(DestFd,(St.st_mode | 0222) & (~UMask)) != 0 ||
|
||||
fchown(DestFd,pwd->pw_uid,pwd->pw_gid) != 0)
|
||||
{
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to chang perms on copy %s",remark);
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
/* Copy the file */
|
||||
do
|
||||
{
|
||||
Res = read(SrcFd,remark,BUFSIZ);
|
||||
if (Res < 0 || write(DestFd,remark,Res) != Res)
|
||||
{
|
||||
close(SrcFd);
|
||||
close(DestFd);
|
||||
free(remark);
|
||||
_log_err(LOG_DEBUG, "unable to perform IO");
|
||||
return PAM_PERM_DENIED;
|
||||
}
|
||||
}
|
||||
while (Res != 0);
|
||||
close(SrcFd);
|
||||
close(DestFd);
|
||||
}
|
||||
|
||||
free(remark);
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
/* --- 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;
|
||||
struct stat St;
|
||||
|
||||
/* Parse the flag values */
|
||||
ctrl = _pam_parse(flags, argc, argv);
|
||||
|
||||
/* Determine the user name so we can get the home directory */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Get the password entry */
|
||||
pwd = getpwnam(user);
|
||||
if (pwd == NULL)
|
||||
{
|
||||
D(("couldn't identify user %s", user));
|
||||
return PAM_CRED_INSUFFICIENT;
|
||||
}
|
||||
|
||||
/* Stat the home directory, if something exists then we assume it is
|
||||
correct and return a success*/
|
||||
if (stat(pwd->pw_dir,&St) == 0)
|
||||
return PAM_SUCCESS;
|
||||
|
||||
return create_homedir(pamh,ctrl,pwd);
|
||||
}
|
||||
|
||||
/* Ignore */
|
||||
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_mkhomedir_modstruct =
|
||||
{
|
||||
"pam_mkhomedir",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
pam_sm_open_session,
|
||||
pam_sm_close_session,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
15
contrib/libpam/modules/pam_motd/Makefile
Normal file
15
contrib/libpam/modules/pam_motd/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan 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!).
|
||||
#
|
||||
# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27
|
||||
#
|
||||
|
||||
include ../../Make.Rules
|
||||
|
||||
TITLE=pam_motd
|
||||
|
||||
include ../Simple.Rules
|
119
contrib/libpam/modules/pam_motd/pam_motd.c
Normal file
119
contrib/libpam/modules/pam_motd/pam_motd.c
Normal file
@ -0,0 +1,119 @@
|
||||
/* pam_motd module */
|
||||
|
||||
/*
|
||||
* Modified for pam_motd by Ben Collins <bcollins@debian.org>
|
||||
*
|
||||
* Based off of:
|
||||
* $Id: pam_motd.c,v 1.1.1.1 2000/06/20 22:11:46 agmorgan Exp $
|
||||
*
|
||||
* Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.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_SESSION
|
||||
#define DEFAULT_MOTD "/etc/motd"
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
|
||||
/* --- session management functions (only) --- */
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
|
||||
const char **argv)
|
||||
{
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
|
||||
const char **argv)
|
||||
{
|
||||
int retval = PAM_IGNORE;
|
||||
int fd;
|
||||
char *mtmp=NULL, *motd_path=NULL;
|
||||
struct pam_conv *conversation;
|
||||
struct pam_message message;
|
||||
struct pam_message *pmessage = &message;
|
||||
struct pam_response *resp = NULL;
|
||||
struct stat st;
|
||||
|
||||
if (flags & PAM_SILENT) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
for (; argc-- > 0; ++argv) {
|
||||
if (!strncmp(*argv,"motd=",5)) {
|
||||
motd_path = (char *) strdup(5+*argv);
|
||||
if (motd_path != NULL) {
|
||||
D(("set motd path: %s", motd_path));
|
||||
} else {
|
||||
D(("failed to duplicate motd path - ignored"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (motd_path == NULL)
|
||||
motd_path = DEFAULT_MOTD;
|
||||
|
||||
message.msg_style = PAM_TEXT_INFO;
|
||||
|
||||
if ((fd = open(motd_path, O_RDONLY, 0)) >= 0) {
|
||||
/* fill in message buffer with contents of motd */
|
||||
if ((fstat(fd, &st) < 0) || !st.st_size)
|
||||
return retval;
|
||||
message.msg = mtmp = malloc(st.st_size+1);
|
||||
/* if malloc failed... */
|
||||
if (!message.msg) return retval;
|
||||
read(fd, mtmp, st.st_size);
|
||||
if (mtmp[st.st_size-1] == '\n')
|
||||
mtmp[st.st_size-1] = '\0';
|
||||
else
|
||||
mtmp[st.st_size] = '\0';
|
||||
close(fd);
|
||||
/* Use conversation function to give user contents of motd */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PAM_STATIC
|
||||
|
||||
/* static module data */
|
||||
|
||||
struct pam_module _pam_motd_modstruct = {
|
||||
"pam_motd",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
pam_sm_open_session,
|
||||
pam_sm_close_session,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* end of module definition */
|
55
contrib/libpam/modules/pam_tally/faillog.h
Normal file
55
contrib/libpam/modules/pam_tally/faillog.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* faillog.h - login failure logging file format
|
||||
*
|
||||
* $Id: faillog.h,v 1.1.1.1 2000/06/20 22:11:59 agmorgan Exp $
|
||||
*
|
||||
* The login failure file is maintained by login(1) and faillog(8)
|
||||
* Each record in the file represents a separate UID and the file
|
||||
* is indexed in that fashion.
|
||||
*/
|
||||
|
||||
#ifndef _FAILLOG_H
|
||||
#define _FAILLOG_H
|
||||
|
||||
struct faillog {
|
||||
short fail_cnt; /* failures since last success */
|
||||
short fail_max; /* failures before turning account off */
|
||||
char fail_line[12]; /* last failure occured here */
|
||||
time_t fail_time; /* last failure occured then */
|
||||
/*
|
||||
* If nonzero, the account will be re-enabled if there are no
|
||||
* failures for fail_locktime seconds since last failure.
|
||||
*/
|
||||
long fail_locktime;
|
||||
};
|
||||
|
||||
#endif
|
7
contrib/libpam/modules/pam_tally/pam_tally_app.c
Normal file
7
contrib/libpam/modules/pam_tally/pam_tally_app.c
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
# This seemed like such a good idea at the time. :)
|
||||
*/
|
||||
|
||||
#define MAIN
|
||||
#include "pam_tally.c"
|
||||
|
119
contrib/libpam/modules/pam_unix/bigcrypt.c
Normal file
119
contrib/libpam/modules/pam_unix/bigcrypt.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
char *crypt(const char *key, const char *salt);
|
||||
char *bigcrypt(const char *key, const char *salt);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
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;
|
||||
}
|
117
contrib/libpam/modules/pam_unix/lckpwdf.-c
Normal file
117
contrib/libpam/modules/pam_unix/lckpwdf.-c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 */
|
256
contrib/libpam/modules/pam_unix/md5.c
Normal file
256
contrib/libpam/modules/pam_unix/md5.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* $Id: md5.c,v 1.1.1.1 2000/06/20 22:12:03 agmorgan 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "md5.h"
|
||||
|
||||
#ifndef HIGHFIRST
|
||||
#define byteReverse(buf, len) /* Nothing */
|
||||
#else
|
||||
static void byteReverse(unsigned char *buf, unsigned longs);
|
||||
|
||||
#ifndef ASM_MD5
|
||||
/*
|
||||
* Note: this code is harmless on little-endian machines.
|
||||
*/
|
||||
static 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 MD5Name(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 MD5Name(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);
|
||||
MD5Name(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);
|
||||
MD5Name(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 MD5Name(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);
|
||||
MD5Name(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];
|
||||
|
||||
MD5Name(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 MD5Name(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
|
31
contrib/libpam/modules/pam_unix/md5.h
Normal file
31
contrib/libpam/modules/pam_unix/md5.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
typedef unsigned int uint32;
|
||||
|
||||
struct MD5Context {
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
|
||||
void GoodMD5Init(struct MD5Context *);
|
||||
void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned);
|
||||
void GoodMD5Final(unsigned char digest[16], struct MD5Context *);
|
||||
void GoodMD5Transform(uint32 buf[4], uint32 const in[16]);
|
||||
void BrokenMD5Init(struct MD5Context *);
|
||||
void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned);
|
||||
void BrokenMD5Final(unsigned char digest[16], struct MD5Context *);
|
||||
void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]);
|
||||
|
||||
char *Goodcrypt_md5(const char *pw, const char *salt);
|
||||
char *Brokencrypt_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 */
|
149
contrib/libpam/modules/pam_unix/md5_crypt.c
Normal file
149
contrib/libpam/modules/pam_unix/md5_crypt.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* $Id: md5_crypt.c,v 1.1.1.1 2000/06/20 22:12:03 agmorgan 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
|
||||
*
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* UNIX password
|
||||
*
|
||||
* Use MD5 for what it is best at...
|
||||
*/
|
||||
|
||||
char *MD5Name(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;
|
||||
|
||||
MD5Name(MD5Init)(&ctx);
|
||||
|
||||
/* The password first, since that is what is most unknown */
|
||||
MD5Name(MD5Update)(&ctx,(unsigned const char *)pw,strlen(pw));
|
||||
|
||||
/* Then our magic string */
|
||||
MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic));
|
||||
|
||||
/* Then the raw salt */
|
||||
MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl);
|
||||
|
||||
/* Then just as many characters of the MD5(pw,salt,pw) */
|
||||
MD5Name(MD5Init)(&ctx1);
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
|
||||
MD5Name(MD5Final)(final,&ctx1);
|
||||
for (pl = strlen(pw); pl > 0; pl -= 16)
|
||||
MD5Name(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)
|
||||
MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1);
|
||||
else
|
||||
MD5Name(MD5Update)(&ctx, (unsigned const char *)pw+j, 1);
|
||||
|
||||
/* Now make the output string */
|
||||
strcpy(passwd, magic);
|
||||
strncat(passwd, sp, sl);
|
||||
strcat(passwd, "$");
|
||||
|
||||
MD5Name(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++) {
|
||||
MD5Name(MD5Init)(&ctx1);
|
||||
if (i & 1)
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
|
||||
else
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
|
||||
|
||||
if (i % 3)
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
|
||||
|
||||
if (i % 7)
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
|
||||
|
||||
if (i & 1)
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
|
||||
else
|
||||
MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
|
||||
MD5Name(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;
|
||||
}
|
144
contrib/libpam/modules/pam_unix/support.h
Normal file
144
contrib/libpam/modules/pam_unix/support.h
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* $Id: support.h,v 1.3 2000/12/20 05:15:05 vorlon Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PAM_UNIX_SUPPORT_H
|
||||
#define _PAM_UNIX_SUPPORT_H
|
||||
|
||||
|
||||
/*
|
||||
* 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_DEBUG 15 /* send more info to syslog(3) */
|
||||
#define UNIX_NODELAY 16 /* admin does not want a fail-delay */
|
||||
#define UNIX_NIS 17 /* wish to use NIS for pwd */
|
||||
#define UNIX_BIGCRYPT 18 /* use DEC-C2 crypt()^x function */
|
||||
#define UNIX_LIKE_AUTH 19 /* need to auth for setcred to work */
|
||||
#define UNIX_REMEMBER_PASSWD 20 /* Remember N previous passwords */
|
||||
/* -------------- */
|
||||
#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_, 010000},
|
||||
/* UNIX_MD5_PASS */ {"md5", _ALL_ON_^(0400000), 020000},
|
||||
/* UNIX__NULLOK */ {"nullok", _ALL_ON_^(01000), 0},
|
||||
/* UNIX_DEBUG */ {"debug", _ALL_ON_, 040000},
|
||||
/* UNIX_NODELAY */ {"nodelay", _ALL_ON_, 0100000},
|
||||
/* UNIX_NIS */ {"nis", _ALL_ON_^(010000), 0200000},
|
||||
/* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000},
|
||||
/* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000},
|
||||
/* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000},
|
||||
};
|
||||
|
||||
#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
|
||||
|
||||
|
||||
/* use this to free strings. ESPECIALLY password strings */
|
||||
|
||||
#define _pam_delete(xx) \
|
||||
{ \
|
||||
_pam_overwrite(xx); \
|
||||
_pam_drop(xx); \
|
||||
}
|
||||
|
||||
extern char *PAM_getlogin(void);
|
||||
extern void _log_err(int err, pam_handle_t *pamh, const char *format,...);
|
||||
extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl
|
||||
,int type, const char *text);
|
||||
extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int argc,
|
||||
const char **argv);
|
||||
extern int _unix_blankpasswd(unsigned int ctrl, const char *name);
|
||||
extern int _unix_verify_password(pam_handle_t * pamh, const char *name
|
||||
,const char *p, unsigned int ctrl);
|
||||
extern 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);
|
||||
|
||||
#endif /* _PAM_UNIX_SUPPORT_H */
|
||||
|
314
contrib/libpam/modules/pam_unix/unix_chkpwd.c
Normal file
314
contrib/libpam/modules/pam_unix/unix_chkpwd.c
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* $Id: unix_chkpwd.c,v 1.3 2001/02/11 06:33:53 agmorgan 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' 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <security/_pam_aconf.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <shadow.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define MAXPASS 200 /* the maximum length of a password */
|
||||
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
extern char *crypt(const char *key, const char *salt);
|
||||
extern char *bigcrypt(const char *key, const char *salt);
|
||||
|
||||
#define UNIX_PASSED 0
|
||||
#define UNIX_FAILED 1
|
||||
|
||||
/* syslogging function for errors and other information */
|
||||
|
||||
static void _log_err(int err, const char *format,...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
|
||||
vsyslog(err, format, args);
|
||||
va_end(args);
|
||||
closelog();
|
||||
}
|
||||
|
||||
static void su_sighandler(int sig)
|
||||
{
|
||||
if (sig > 0) {
|
||||
_log_err(LOG_NOTICE, "caught signal %d.", sig);
|
||||
exit(sig);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_signals(void)
|
||||
{
|
||||
struct sigaction action; /* posix signal structure */
|
||||
|
||||
/*
|
||||
* Setup signal handlers
|
||||
*/
|
||||
(void) memset((void *) &action, 0, sizeof(action));
|
||||
action.sa_handler = su_sighandler;
|
||||
action.sa_flags = SA_RESETHAND;
|
||||
(void) sigaction(SIGILL, &action, NULL);
|
||||
(void) sigaction(SIGTRAP, &action, NULL);
|
||||
(void) sigaction(SIGBUS, &action, NULL);
|
||||
(void) sigaction(SIGSEGV, &action, NULL);
|
||||
action.sa_handler = SIG_IGN;
|
||||
action.sa_flags = 0;
|
||||
(void) sigaction(SIGTERM, &action, NULL);
|
||||
(void) sigaction(SIGHUP, &action, NULL);
|
||||
(void) sigaction(SIGINT, &action, NULL);
|
||||
(void) sigaction(SIGQUIT, &action, NULL);
|
||||
}
|
||||
|
||||
static int _unix_verify_password(const char *name, const char *p, int opt)
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
struct spwd *spwdent = NULL;
|
||||
char *salt = NULL;
|
||||
char *pp = NULL;
|
||||
int retval = UNIX_FAILED;
|
||||
|
||||
/* UNIX passwords area */
|
||||
setpwent();
|
||||
pwd = getpwnam(name); /* Get password file entry... */
|
||||
endpwent();
|
||||
if (pwd != NULL) {
|
||||
if (strcmp(pwd->pw_passwd, "x") == 0) {
|
||||
/*
|
||||
* ...and shadow password file entry for this user,
|
||||
* if shadowing is enabled
|
||||
*/
|
||||
setspent();
|
||||
spwdent = getspnam(name);
|
||||
endspent();
|
||||
if (spwdent != NULL)
|
||||
salt = x_strdup(spwdent->sp_pwdp);
|
||||
else
|
||||
pwd = NULL;
|
||||
} else {
|
||||
if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */
|
||||
uid_t save_uid;
|
||||
|
||||
save_uid = geteuid();
|
||||
seteuid(pwd->pw_uid);
|
||||
spwdent = getspnam(name);
|
||||
seteuid(save_uid);
|
||||
|
||||
salt = x_strdup(spwdent->sp_pwdp);
|
||||
} else {
|
||||
salt = x_strdup(pwd->pw_passwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pwd == NULL || salt == NULL) {
|
||||
_log_err(LOG_ALERT, "check pass; user unknown");
|
||||
p = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (strlen(salt) == 0)
|
||||
return (opt == 0) ? UNIX_FAILED : UNIX_PASSED;
|
||||
|
||||
/* the moment of truth -- do we agree with the password? */
|
||||
retval = UNIX_FAILED;
|
||||
if (!strncmp(salt, "$1$", 3)) {
|
||||
pp = Goodcrypt_md5(p, salt);
|
||||
if (strcmp(pp, salt) == 0) {
|
||||
retval = UNIX_PASSED;
|
||||
} else {
|
||||
pp = Brokencrypt_md5(p, salt);
|
||||
if (strcmp(pp, salt) == 0)
|
||||
retval = UNIX_PASSED;
|
||||
}
|
||||
} else {
|
||||
pp = bigcrypt(p, salt);
|
||||
if (strcmp(pp, salt) == 0) {
|
||||
retval = UNIX_PASSED;
|
||||
}
|
||||
}
|
||||
p = NULL; /* no longer needed here */
|
||||
|
||||
/* clean up */
|
||||
{
|
||||
char *tp = pp;
|
||||
if (pp != NULL) {
|
||||
while (tp && *tp)
|
||||
*tp++ = '\0';
|
||||
}
|
||||
pp = tp = NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static char *getuidname(uid_t uid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
static char username[32];
|
||||
|
||||
pw = getpwuid(uid);
|
||||
if (pw == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(username, 0, 32);
|
||||
strncpy(username, pw->pw_name, 32);
|
||||
username[31] = '\0';
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char pass[MAXPASS + 1];
|
||||
char option[8];
|
||||
int npass, opt;
|
||||
int force_failure = 0;
|
||||
int retval = UNIX_FAILED;
|
||||
char *user;
|
||||
|
||||
/*
|
||||
* Catch or ignore as many signal as possible.
|
||||
*/
|
||||
setup_signals();
|
||||
|
||||
/*
|
||||
* 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 Unix helper binary [UID=%d]"
|
||||
,getuid());
|
||||
fprintf(stderr
|
||||
,"This binary is not designed for running in this way\n"
|
||||
"-- the system administrator has been informed\n");
|
||||
sleep(10); /* this should discourage/annoy the user */
|
||||
return UNIX_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* determine the current user's name is
|
||||
*/
|
||||
user = getuidname(getuid());
|
||||
if (argc == 2) {
|
||||
/* if the caller specifies the username, verify that user
|
||||
matches it */
|
||||
if (strcmp(user, argv[1])) {
|
||||
force_failure = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* read the nollok/nonull option */
|
||||
|
||||
npass = read(STDIN_FILENO, option, 8);
|
||||
|
||||
if (npass < 0) {
|
||||
_log_err(LOG_DEBUG, "no option supplied");
|
||||
return UNIX_FAILED;
|
||||
} else {
|
||||
option[7] = '\0';
|
||||
if (strncmp(option, "nullok", 8) == 0)
|
||||
opt = 1;
|
||||
else
|
||||
opt = 0;
|
||||
}
|
||||
|
||||
/* read the password from stdin (a pipe from the pam_unix module) */
|
||||
|
||||
npass = read(STDIN_FILENO, pass, MAXPASS);
|
||||
|
||||
if (npass < 0) { /* is it a valid password? */
|
||||
|
||||
_log_err(LOG_DEBUG, "no password supplied");
|
||||
|
||||
} else if (npass >= MAXPASS) {
|
||||
|
||||
_log_err(LOG_DEBUG, "password too long");
|
||||
|
||||
} else {
|
||||
if (npass == 0) {
|
||||
/* the password is NULL */
|
||||
|
||||
retval = _unix_verify_password(user, NULL, opt);
|
||||
|
||||
} else {
|
||||
/* does pass agree with the official one? */
|
||||
|
||||
pass[npass] = '\0'; /* NUL terminate */
|
||||
retval = _unix_verify_password(user, pass, opt);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
memset(pass, '\0', MAXPASS); /* clear memory of the password */
|
||||
|
||||
/* return pass or fail */
|
||||
|
||||
if ((retval != UNIX_PASSED) || force_failure) {
|
||||
return UNIX_FAILED;
|
||||
} else {
|
||||
return UNIX_PASSED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
51
contrib/libpam/modules/pam_unix/yppasswd.h
Normal file
51
contrib/libpam/modules/pam_unix/yppasswd.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* yppasswdd
|
||||
* Copyright 1994, 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
|
||||
*
|
||||
* This program is covered by the GNU General Public License, version 2.
|
||||
* It is provided in the hope that it is useful. However, the author
|
||||
* disclaims ALL WARRANTIES, expressed or implied. See the GPL for details.
|
||||
*
|
||||
* This file was generated automatically by rpcgen from yppasswd.x, and
|
||||
* editied manually.
|
||||
*/
|
||||
|
||||
#ifndef _YPPASSWD_H_
|
||||
#define _YPPASSWD_H_
|
||||
|
||||
#define YPPASSWDPROG ((u_long)100009)
|
||||
#define YPPASSWDVERS ((u_long)1)
|
||||
#define YPPASSWDPROC_UPDATE ((u_long)1)
|
||||
|
||||
/*
|
||||
* The password struct passed by the update call. I renamed it to
|
||||
* xpasswd to avoid a type clash with the one defined in <pwd.h>.
|
||||
*/
|
||||
#ifndef __sgi
|
||||
typedef struct xpasswd {
|
||||
char *pw_name;
|
||||
char *pw_passwd;
|
||||
int pw_uid;
|
||||
int pw_gid;
|
||||
char *pw_gecos;
|
||||
char *pw_dir;
|
||||
char *pw_shell;
|
||||
} xpasswd;
|
||||
|
||||
#else
|
||||
#include <pwd.h>
|
||||
typedef struct xpasswd xpasswd;
|
||||
#endif
|
||||
|
||||
/* The updated password information, plus the old password.
|
||||
*/
|
||||
typedef struct yppasswd {
|
||||
char *oldpass;
|
||||
xpasswd newpw;
|
||||
} yppasswd;
|
||||
|
||||
/* XDR encoding/decoding routines */
|
||||
bool_t xdr_xpasswd(XDR * xdrs, xpasswd * objp);
|
||||
bool_t xdr_yppasswd(XDR * xdrs, yppasswd * objp);
|
||||
|
||||
#endif /* _YPPASSWD_H_ */
|
38
contrib/libpam/modules/pam_unix/yppasswd_xdr.c
Normal file
38
contrib/libpam/modules/pam_unix/yppasswd_xdr.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* yppasswdd
|
||||
* Copyright 1994, 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
|
||||
*
|
||||
* This program is covered by the GNU General Public License, version 2.
|
||||
* It is provided in the hope that it is useful. However, the author
|
||||
* disclaims ALL WARRANTIES, expressed or implied. See the GPL for details.
|
||||
*
|
||||
* This file was generated automatically by rpcgen from yppasswd.x, and
|
||||
* editied manually.
|
||||
*/
|
||||
|
||||
#include <security/_pam_aconf.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpcsvc/yp_prot.h>
|
||||
#include <rpcsvc/ypclnt.h>
|
||||
#include "yppasswd.h"
|
||||
|
||||
bool_t
|
||||
xdr_xpasswd(XDR * xdrs, xpasswd * objp)
|
||||
{
|
||||
return xdr_string(xdrs, &objp->pw_name, ~0)
|
||||
&& xdr_string(xdrs, &objp->pw_passwd, ~0)
|
||||
&& xdr_int(xdrs, &objp->pw_uid)
|
||||
&& xdr_int(xdrs, &objp->pw_gid)
|
||||
&& xdr_string(xdrs, &objp->pw_gecos, ~0)
|
||||
&& xdr_string(xdrs, &objp->pw_dir, ~0)
|
||||
&& xdr_string(xdrs, &objp->pw_shell, ~0);
|
||||
}
|
||||
|
||||
|
||||
bool_t
|
||||
xdr_yppasswd(XDR * xdrs, yppasswd * objp)
|
||||
{
|
||||
return xdr_string(xdrs, &objp->oldpass, ~0)
|
||||
&& xdr_xpasswd(xdrs, &objp->newpw);
|
||||
}
|
35
contrib/libpam/modules/pam_userdb/Makefile
Normal file
35
contrib/libpam/modules/pam_userdb/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
#
|
||||
# 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!).
|
||||
|
||||
# $Id: Makefile,v 1.4 2001/02/18 03:03:31 agmorgan Exp $
|
||||
# Created by Cristian Gafton <gafton@redhat.com>
|
||||
|
||||
include ../../Make.Rules
|
||||
|
||||
TITLE=pam_userdb
|
||||
|
||||
ifeq ($(HAVE_NDBM_H),yes)
|
||||
WHICH_DB=ndbm
|
||||
MODULE_SIMPLE_EXTRALIBS = -lndbm
|
||||
else
|
||||
ifeq ($(HAVE_LIBDB),yes)
|
||||
WHICH_DB=db
|
||||
MODULE_SIMPLE_EXTRALIBS = -ldb
|
||||
else
|
||||
WHICH_DB=none
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(WHICH_DB),none)
|
||||
|
||||
include ../dont_makefile
|
||||
|
||||
else
|
||||
|
||||
MODULE_SIMPLE_EXTRAFILES = conv
|
||||
|
||||
include ../Simple.Rules
|
||||
|
||||
endif
|
30
contrib/libpam/modules/pam_userdb/README
Normal file
30
contrib/libpam/modules/pam_userdb/README
Normal file
@ -0,0 +1,30 @@
|
||||
pam_userdb:
|
||||
Look up users in a .db database and verify their password against
|
||||
what is contained in that database.
|
||||
|
||||
RECOGNIZED ARGUMENTS:
|
||||
debug write a message to syslog indicating success or
|
||||
failure.
|
||||
|
||||
db=[path] use the [path] database for performing lookup. There
|
||||
is no default; the module will return PAM_IGNORE if
|
||||
no database is provided.
|
||||
|
||||
icase make the password verification to be case insensitive
|
||||
(ie when working with registration numbers and such)
|
||||
|
||||
dump dump all the entries in the database to the log (eek,
|
||||
don't do this by default!)
|
||||
|
||||
MODULE SERVICES PROVIDED:
|
||||
auth _authetication and _setcred (blank)
|
||||
|
||||
EXAMPLE USE:
|
||||
auth sufficient pam_userdb.so icase db=/tmp/dbtest.db
|
||||
|
||||
AUTHOR:
|
||||
Cristian Gafton <gafton@redhat.com>
|
||||
|
||||
|
||||
|
||||
$Id: README,v 1.1.1.1 2000/06/20 22:12:09 agmorgan Exp $
|
125
contrib/libpam/modules/pam_userdb/conv.c
Normal file
125
contrib/libpam/modules/pam_userdb/conv.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Conversation related functions
|
||||
*/
|
||||
|
||||
/* $Id */
|
||||
/* Copyright at the end of the file */
|
||||
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
#include "pam_userdb.h"
|
||||
|
||||
/*
|
||||
* dummy conversation function sending exactly one prompt
|
||||
* and expecting exactly one response from the other party
|
||||
*/
|
||||
static int converse(pam_handle_t *pamh,
|
||||
struct pam_message **message,
|
||||
struct pam_response **response)
|
||||
{
|
||||
int retval;
|
||||
const struct pam_conv *conv;
|
||||
|
||||
retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
|
||||
if (retval == PAM_SUCCESS)
|
||||
retval = conv->conv(1, (const struct pam_message **)message,
|
||||
response, conv->appdata_ptr);
|
||||
|
||||
return retval; /* propagate error status */
|
||||
}
|
||||
|
||||
|
||||
static char *_pam_delete(register char *xx)
|
||||
{
|
||||
_pam_overwrite(xx);
|
||||
_pam_drop(xx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a conversation function to obtain the user's password
|
||||
*/
|
||||
int conversation(pam_handle_t *pamh)
|
||||
{
|
||||
struct pam_message msg[2],*pmsg[2];
|
||||
struct pam_response *resp;
|
||||
int retval;
|
||||
char * token = NULL;
|
||||
|
||||
pmsg[0] = &msg[0];
|
||||
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
|
||||
msg[0].msg = "Password: ";
|
||||
|
||||
/* so call the conversation expecting i responses */
|
||||
resp = NULL;
|
||||
retval = converse(pamh, pmsg, &resp);
|
||||
|
||||
if (resp != NULL) {
|
||||
const char * item;
|
||||
/* interpret the response */
|
||||
if (retval == PAM_SUCCESS) { /* a good conversation */
|
||||
token = x_strdup(resp[0].resp);
|
||||
if (token == NULL) {
|
||||
return PAM_AUTHTOK_RECOVER_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the auth token */
|
||||
retval = pam_set_item(pamh, PAM_AUTHTOK, token);
|
||||
token = _pam_delete(token); /* clean it up */
|
||||
if ( (retval != PAM_SUCCESS) ||
|
||||
(retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&item))
|
||||
!= PAM_SUCCESS ) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
_pam_drop_reply(resp, 1);
|
||||
} else {
|
||||
retval = (retval == PAM_SUCCESS)
|
||||
? PAM_AUTHTOK_RECOVER_ERR:retval ;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999
|
||||
* 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.
|
||||
*/
|
23
contrib/libpam/modules/pam_userdb/create.pl
Normal file
23
contrib/libpam/modules/pam_userdb/create.pl
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
# this program creates a database in ARGV[1] from pairs given on
|
||||
# stdandard input
|
||||
#
|
||||
# $Id: create.pl,v 1.1.1.1 2000/06/20 22:12:09 agmorgan Exp $
|
||||
|
||||
use DB_File;
|
||||
|
||||
my $database = $ARGV[0];
|
||||
die "Use: check,pl <database>\n" unless ($database);
|
||||
print "Using database: $database\n";
|
||||
|
||||
my %lusers = ();
|
||||
|
||||
tie %lusers, 'DB_File', $database, O_RDWR|O_CREAT, 0644, $DB_HASH ;
|
||||
while (<STDIN>) {
|
||||
my ($user, $pass) = split;
|
||||
|
||||
$lusers{$user} = $pass;
|
||||
}
|
||||
untie %lusers;
|
||||
|
||||
|
304
contrib/libpam/modules/pam_userdb/pam_userdb.c
Normal file
304
contrib/libpam/modules/pam_userdb/pam_userdb.c
Normal file
@ -0,0 +1,304 @@
|
||||
/* pam_userdb module */
|
||||
|
||||
/*
|
||||
* $Id: pam_userdb.c,v 1.4 2000/12/04 15:02:16 baggins Exp $
|
||||
* Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
|
||||
* See the end of the file for Copyright Information
|
||||
*/
|
||||
|
||||
#include <security/_pam_aconf.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "pam_userdb.h"
|
||||
|
||||
#ifdef HAVE_NDBM_H
|
||||
# include <ndbm.h>
|
||||
#else
|
||||
# ifdef HAVE_DB_H
|
||||
# define DB_DBM_HSEARCH 1 /* use the dbm interface */
|
||||
# include <db.h>
|
||||
# else
|
||||
# error "failed to find a libdb or equivalent"
|
||||
# endif
|
||||
#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
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
|
||||
/* some syslogging */
|
||||
|
||||
static void _pam_log(int err, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
|
||||
vsyslog(err, format, args);
|
||||
va_end(args);
|
||||
closelog();
|
||||
}
|
||||
|
||||
char * database = NULL;
|
||||
static int ctrl = 0;
|
||||
|
||||
static int _pam_parse(int argc, const char **argv)
|
||||
{
|
||||
/* step through arguments */
|
||||
for (ctrl = 0; argc-- > 0; ++argv) {
|
||||
|
||||
/* generic options */
|
||||
|
||||
if (!strcmp(*argv,"debug"))
|
||||
ctrl |= PAM_DEBUG_ARG;
|
||||
else if (!strcasecmp(*argv, "icase"))
|
||||
ctrl |= PAM_ICASE_ARG;
|
||||
else if (!strcasecmp(*argv, "dump"))
|
||||
ctrl |= PAM_DUMP_ARG;
|
||||
else if (!strncasecmp(*argv,"db=", 3)) {
|
||||
database = strdup((*argv) + 3);
|
||||
if (database == NULL)
|
||||
_pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"",
|
||||
*argv);
|
||||
} else {
|
||||
_pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Looks up an user name in a database and checks the password
|
||||
*
|
||||
* return values:
|
||||
* 1 = User not found
|
||||
* 0 = OK
|
||||
* -1 = Password incorrect
|
||||
* -2 = System error
|
||||
*/
|
||||
static int user_lookup(const char *user, const char *pass)
|
||||
{
|
||||
DBM *dbm;
|
||||
datum key, data;
|
||||
|
||||
/* Open the DB file. */
|
||||
dbm = dbm_open(database, O_RDONLY, 0644);
|
||||
if (dbm == NULL) {
|
||||
_pam_log(LOG_ERR, "user_lookup: could not open database `%s'",
|
||||
database);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ctrl &PAM_DUMP_ARG) {
|
||||
_pam_log(LOG_INFO, "Database dump:");
|
||||
for (key = dbm_firstkey(dbm); key.dptr != NULL;
|
||||
key = dbm_nextkey(dbm)) {
|
||||
data = dbm_fetch(dbm, key);
|
||||
_pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'",
|
||||
key.dsize, key.dptr, data.dsize, data.dptr);
|
||||
}
|
||||
}
|
||||
/* do some more init work */
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
memset(&data, 0, sizeof(data));
|
||||
key.dptr = x_strdup(user);
|
||||
key.dsize = strlen(user);
|
||||
user = NULL;
|
||||
|
||||
if (key.dptr) {
|
||||
data = dbm_fetch(dbm, key);
|
||||
memset(key.dptr, 0, key.dsize);
|
||||
free(key.dptr);
|
||||
}
|
||||
|
||||
if (ctrl & PAM_DEBUG_ARG) {
|
||||
_pam_log(LOG_INFO, "password in database is [%p]`%s', len is %d",
|
||||
data.dptr, (char *) data.dptr, data.dsize);
|
||||
}
|
||||
|
||||
if (data.dptr != NULL) {
|
||||
int compare = 0;
|
||||
/* bingo, got it */
|
||||
if (ctrl & PAM_ICASE_ARG)
|
||||
compare = strncasecmp(pass, data.dptr, data.dsize);
|
||||
else
|
||||
compare = strncmp(pass, data.dptr, data.dsize);
|
||||
dbm_close(dbm);
|
||||
if (compare == 0)
|
||||
return 0; /* match */
|
||||
else
|
||||
return -1; /* wrong */
|
||||
} else {
|
||||
if (ctrl & PAM_DEBUG_ARG) {
|
||||
_pam_log(LOG_INFO, "error returned by dbm_fetch: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
dbm_close(dbm);
|
||||
/* probably we should check dbm_error() here */
|
||||
return 1; /* not found */
|
||||
}
|
||||
|
||||
/* NOT REACHED */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* --- authentication management functions (only) --- */
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
const char *username;
|
||||
const char *password;
|
||||
int retval = PAM_AUTH_ERR;
|
||||
|
||||
/* parse arguments */
|
||||
ctrl = _pam_parse(argc, argv);
|
||||
|
||||
/* Get the username */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Converse just to be sure we have the password */
|
||||
retval = conversation(pamh);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
_pam_log(LOG_ERR, "could not obtain password for `%s'",
|
||||
username);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Get the password */
|
||||
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
_pam_log(LOG_ERR, "Could not retrive user's password");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
|
||||
username, password);
|
||||
|
||||
/* Now use the username to look up password in the database file */
|
||||
retval = user_lookup(username, password);
|
||||
switch (retval) {
|
||||
case -2:
|
||||
/* some sort of system error. The log was already printed */
|
||||
return PAM_SERVICE_ERR;
|
||||
case -1:
|
||||
/* incorrect password */
|
||||
_pam_log(LOG_WARNING,
|
||||
"user `%s' denied access (incorrect password)",
|
||||
username);
|
||||
return PAM_AUTH_ERR;
|
||||
case 1:
|
||||
/* the user does not exist in the database */
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_NOTICE, "user `%s' not found in the database",
|
||||
username);
|
||||
return PAM_USER_UNKNOWN;
|
||||
case 0:
|
||||
/* Otherwise, the authentication looked good */
|
||||
_pam_log(LOG_NOTICE, "user '%s' granted acces", username);
|
||||
return PAM_SUCCESS;
|
||||
default:
|
||||
/* we don't know anything about this return value */
|
||||
_pam_log(LOG_ERR,
|
||||
"internal module error (retval = %d, user = `%s'",
|
||||
retval, username);
|
||||
return PAM_SERVICE_ERR;
|
||||
}
|
||||
|
||||
/* should not be reached */
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_setcred(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PAM_STATIC
|
||||
|
||||
/* static module data */
|
||||
|
||||
struct pam_module _pam_userdb_modstruct = {
|
||||
"pam_userdb",
|
||||
pam_sm_authenticate,
|
||||
pam_sm_setcred,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999
|
||||
* 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.
|
||||
*/
|
61
contrib/libpam/modules/pam_userdb/pam_userdb.h
Normal file
61
contrib/libpam/modules/pam_userdb/pam_userdb.h
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
#ifndef _PAM_USERSDB_H
|
||||
#define _PAM_USERSDB_H
|
||||
/* $Id: pam_userdb.h,v 1.1.1.1 2000/06/20 22:12:09 agmorgan Exp $ */
|
||||
|
||||
/* Header files */
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
/* argument parsing */
|
||||
#define PAM_DEBUG_ARG 0x0001
|
||||
#define PAM_ICASE_ARG 0x0002
|
||||
#define PAM_DUMP_ARG 0x0004
|
||||
|
||||
/* Useful macros */
|
||||
#define x_strdup(s) ( (s) ? strdup(s):NULL )
|
||||
|
||||
/* The name of the module we are compiling */
|
||||
#ifndef MODULE_NAME
|
||||
#define MODULE_NAME "pam_userdb"
|
||||
#endif /* MODULE_NAME */
|
||||
|
||||
/* function prototypes */
|
||||
int conversation(pam_handle_t *);
|
||||
|
||||
#endif /* _PAM_USERSDB_H */
|
||||
|
||||
/*
|
||||
* Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999
|
||||
* 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.
|
||||
*/
|
Loading…
Reference in New Issue
Block a user