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:
markm 2001-05-03 09:36:08 +00:00
commit 9f524a8aad
100 changed files with 13309 additions and 1403 deletions

View File

@ -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>

View 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)

View File

@ -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)/*

View File

@ -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>

View 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

File diff suppressed because it is too large Load Diff

339
contrib/libpam/configure.in Normal file
View 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)

View 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

View 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

View 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

View 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

View File

@ -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,

View File

@ -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

View File

@ -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>

View File

@ -1 +1 @@
.so man8/pam.8
.so pam.8

View File

@ -1 +1 @@
.so man8/pam.8
.so pam.8

View File

@ -1 +1 @@
.so man3/pam_open_session.3
.so pam_open_session.3

View File

@ -1 +1 @@
.so man3/pam_start.3
.so pam_start.3

View File

@ -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

View 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 &lt;alexei@nogin.dnttm.ru&gt;
<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>

View 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 &lt;bcollins@debian.org&gt;
<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 &bsol;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. "&num;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.
-->

View 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 &lt;jgg@ualberta.ca&gt;
<tag><bf>Maintainer:</bf></tag>
Ben Collins &lt;bcollins@debian.org&gt;
<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.
-->

View 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 &lt;bcollins@debian.org&gt;
<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.
-->

View 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.
-->

View 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.
-->

View 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 &lt;gafton@redhat.com&gt;
<tag><bf>Maintainer:</bf></tag>
Author.
<tag><bf>Management groups provided:</bf></tag>
authentication
<tag><bf>Cryptographically sensitive:</bf></tag>
<tag><bf>Security rating:</bf></tag>
<tag><bf>Clean code base:</bf></tag>
<tag><bf>System dependencies:</bf></tag>
Requires 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/&lt;service&gt;</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.
-->

View File

@ -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/&dollar;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>&lt;NUL&gt;</tt> terminated character string. In the
case of <tt/PAM_CONV/, <tt/item/ points to an initialized
<tt/pam_conv/ structure (see section <ref
id="the-conversation-function" name="below">).
For all <tt/item_type/s, other than <tt/PAM_CONV/ and
<tt/PAM_FAIL_DELAY/, <tt/item/ is a pointer to a <tt>&lt;NUL&gt;</tt>
terminated character string. In the case of <tt/PAM_CONV/, <tt/item/
points to an initialized <tt/pam_conv/ structure (see section <ref
id="the-conversation-function" name="below">). 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/&lt;unset&gt;/
= 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>&lt;morgan@transmeta.com&gt;</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>

View File

@ -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>

View File

@ -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&lowbar;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>&lt;morgan@parc.power.net&gt;</tt>
Email: <tt>&lt;morgan@linux.kernel.org&gt;</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>

View 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 $ ##

View File

@ -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

View File

@ -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 */

View File

@ -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);
}

View File

@ -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.
*/

View File

@ -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>

View File

@ -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 $
*/
/*

View File

@ -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;
}

View File

@ -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;

View File

@ -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) {

View File

@ -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) {

View File

@ -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 $
*/

View File

@ -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);

View File

@ -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!? */
}

View File

@ -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--;

View File

@ -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 */
}

View File

@ -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)

View File

@ -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>

View File

@ -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);
}

View File

@ -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;

View File

@ -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
*

View File

@ -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>

View File

@ -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);
}

View File

@ -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;

View File

@ -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"

View File

@ -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
*

View File

@ -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

View File

@ -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>

View 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

View File

@ -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);
}

View 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.
-------------------------------------------------------------------------

View 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

View 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 */

View 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 */

View 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;
}

View 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;
}

View 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;
}

View 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;
}
}

View 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

View 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;
}

View 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

View File

@ -0,0 +1,6 @@
#!/bin/bash
export LD_LIBRARY_PATH=../..
export PAMC_AGENT_PATH="../agents"
./test.libpamc

View 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);
}

View 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;
}

View 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 $<

View 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

View 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

View 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

View 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 */

View 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

View 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

View 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

View 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

View 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 */

View 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

View File

@ -0,0 +1,7 @@
/*
# This seemed like such a good idea at the time. :)
*/
#define MAIN
#include "pam_tally.c"

View 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;
}

View 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 */

View 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

View 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 */

View 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;
}

View 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 */

View 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.
*/

View 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_ */

View 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);
}

View 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

View 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 $

View 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.
*/

View 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;

View 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.
*/

View 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.
*/