diff options
author | jdp <jdp@FreeBSD.org> | 1998-11-18 01:16:21 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1998-11-18 01:16:21 +0000 |
commit | f06b122f95ed96a1a451b0939f85cdb39cd631e0 (patch) | |
tree | 34d7fe17cf8b2fe7fe61c7fe8ce3a5574bbfa23a /contrib/libpam/modules/pam_unix | |
download | FreeBSD-src-f06b122f95ed96a1a451b0939f85cdb39cd631e0.zip FreeBSD-src-f06b122f95ed96a1a451b0939f85cdb39cd631e0.tar.gz |
Initial import of virgin Linux-PAM 0.65, slightly stripped down.
Diffstat (limited to 'contrib/libpam/modules/pam_unix')
-rw-r--r-- | contrib/libpam/modules/pam_unix/CHANGELOG | 6 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/Makefile | 155 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/README | 39 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/pam_unix_acct.c | 117 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/pam_unix_auth.c | 307 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/pam_unix_passwd.c | 813 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/pam_unix_sess.c | 181 | ||||
-rw-r--r-- | contrib/libpam/modules/pam_unix/support.c | 152 |
8 files changed, 1770 insertions, 0 deletions
diff --git a/contrib/libpam/modules/pam_unix/CHANGELOG b/contrib/libpam/modules/pam_unix/CHANGELOG new file mode 100644 index 0000000..37e4c85 --- /dev/null +++ b/contrib/libpam/modules/pam_unix/CHANGELOG @@ -0,0 +1,6 @@ +$Id: CHANGELOG,v 1.1 1996/11/09 19:42:41 morgan Exp $ + +$Log: CHANGELOG,v $ +Revision 1.1 1996/11/09 19:42:41 morgan +Initial revision + diff --git a/contrib/libpam/modules/pam_unix/Makefile b/contrib/libpam/modules/pam_unix/Makefile new file mode 100644 index 0000000..ad1f47f --- /dev/null +++ b/contrib/libpam/modules/pam_unix/Makefile @@ -0,0 +1,155 @@ +# $Header$ +# +# This Makefile controls a build process of the pam_unix modules +# for Linux-PAM. You should not modify this Makefile. +# +# $Log$ +# Revision 1.1.1.2 1998/06/03 03:43:56 adam +# Import from archive +# +# Revision 1.3 1998/05/31 23:48:13 adam +# Link crypt library as necessary. +# +# Revision 1.3 1997/04/05 06:20:58 morgan +# fakeroot and also lockpwdf is in libc now +# +# Revision 1.2 1996/11/10 20:18:59 morgan +# cross platform support +# +# Revision 1.1 1996/11/09 19:44:16 morgan +# Initial revision +# +# + +######################################################################## +# some options... uncomment to take effect +######################################################################## + +# do you want shadow? +USE_SHADOW=-D"HAVE_SHADOW_H" + +# do you want cracklib? +ifeq ($(HAVE_CRACKLIB),yes) +USE_CRACKLIB=-D"USE_CRACKLIB" +endif + +# do you want to use lckpwdf? +USE_LCKPWDF=-D"USE_LCKPWDF" + +# do you need to include the locking functions in the source? +#NEED_LCKPWDF=-D"NEED_LCKPWDF" + +######################################################################## + +CFLAGS += $(USE_SHADOW) $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) + +ifdef DYNAMIC +LIBSESSSH = pam_unix_session.so +LIBAUTHSH = pam_unix_auth.so +LIBPASSWDSH = pam_unix_passwd.so +LIBACCOUNT = pam_unix_acct.so +endif + +ifdef STATIC +LIBSTATIC = libpam_unix.o +endif + +ifdef USE_CRACKLIB +CRACKLIB = -lcrack +endif + +LIBAUTHOBJ = pam_unix_auth.o support.o +LIBAUTHSRC = pam_unix_auth.c support.c +LIBSESSOBJ = pam_unix_sess.o +LIBSESSSRC = pam_unix_sess.c +LIBPASSWDSRC = pam_unix_passwd.c +LIBPASSWDOBJ = pam_unix_passwd.o +LIBACCOUNTSRC = pam_unix_acct.c +LIBACCOUNTOBJ = pam_unix_acct.o +LIBOBJ = $(LIBAUTHOBJ) $(LIBSESSOBJ) $(LIBPASSWDOBJ) $(LIBACCOUNTOBJ) +LIBSRC = $(LIBAUTHSRC) $(LIBSESSSRC) $(LIBPASSWDSRC) $(LIBACCOUNTSRC) + +LIBSHARED = $(LIBSESSSH) $(LIBAUTHSH) $(LIBPASSWDSH) $(LIBACCOUNT) + +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) -c $< -o $@ + +static/%.o: %.c + $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) -c $< -o $@ + + +########################### don't edit below ####################### + +dummy: + + @echo "**** This is not a top-level Makefile " + exit + +info: + @echo + @echo "*** Building pam-unix(alpha) module of the framework..." + @echo + +all: dirs info $(LIBSHARED) $(LIBSTATIC) register + +dirs: +ifdef DYNAMIC + mkdir -p ./dynamic +endif +ifdef STATIC + mkdir -p ./static +endif + +register: +ifdef STATIC + ( cd .. ; \ + ./register_static pam_unix_auth pam_unix/$(LIBSTATIC) ; \ + ./register_static pam_unix_acct "" ; \ + ) +endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBAUTHSH): $(LIBAUTHSRC) $(LIBOBJD) + $(LD_D) -o $@ $(addprefix dynamic/,$(LIBAUTHOBJ)) -lcrypt + +$(LIBSESSSH): $(LIBSESSSRC) $(LIBOBJD) + $(LD_D) -o $@ $(addprefix dynamic/,$(LIBSESSOBJ)) + +$(LIBPASSWDSH): $(LIBPASSWDSRC) $(LIBOBJD) + $(LD_D) -o $@ $(addprefix dynamic/,$(LIBPASSWDOBJ)) $(CRACKLIB) -lcrypt + +$(LIBACCOUNT): $(LIBACCOUNTSRC) $(LIBOBJD) + $(LD_D) -o $@ $(addprefix dynamic/,$(LIBACCOUNTOBJ)) +endif + + +ifdef STATIC +$(LIBOBJS): $(LIBSRC) + +$(LIBSTATIC): $(LIBOBJS) + $(LD) -r -o $@ $(LIBOBJS) +endif + +install: all + mkdir -p $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + install -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + +remove: + cd $(FAKEROOT)$(SECUREDIR) && rm -f $(LIBSHARED) + +clean: + rm -f $(LIBOBJD) $(LIBOBJS) a.out core *~ + +extraclean: clean + rm -f *.a *.out *.o *.so *.bak + +.c.o: + $(CC) -c $(CFLAGS) $< + diff --git a/contrib/libpam/modules/pam_unix/README b/contrib/libpam/modules/pam_unix/README new file mode 100644 index 0000000..082e996 --- /dev/null +++ b/contrib/libpam/modules/pam_unix/README @@ -0,0 +1,39 @@ +This is the README for pam_unix in Linux-PAM-0.53. +-------------------------------------------------- + +pam_unix comes as four separate modules: + +pam_unix_auth: authentication module providing + pam_authenticate() and pam_setcred() hooks + + NO options are recognized. Credential facilities are trivial + (function simply returns) + +pam_unix_sess: session module, providing session logging + + "debug" and "trace" arguments are accepted, which indicate the + logging-level for syslog. + + "debug" -> LOG_DEBUG [ also default ] + "trace" -> LOG_AUTHPRIV + +pam_unix_acct: account management, providing shadow account + managment features, password aging etc.. + + NO options are recognized. Account managment trivial without + shadow active. + +pam_unix_passwd: password updating facilities providing + cracklib password strength checking facilities. + + if compiled, the default behavior is to check passwords + strictly using CrackLib. This behavior can be turned off + with the argument + + "strict=false" + + invalid arguments are logged to syslog. + +------------------------------ +- Andrew 1996/11/9 +------------------------------ diff --git a/contrib/libpam/modules/pam_unix/pam_unix_acct.c b/contrib/libpam/modules/pam_unix/pam_unix_acct.c new file mode 100644 index 0000000..5c0546a --- /dev/null +++ b/contrib/libpam/modules/pam_unix/pam_unix_acct.c @@ -0,0 +1,117 @@ +/* + * Copyright Elliot Lee, 1996. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* pam_unix_acct.c module, different track */ + +#ifdef linux +# define _GNU_SOURCE +# include <features.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#define __USE_MISC +#include <pwd.h> +#include <sys/types.h> +#include <syslog.h> +#include <unistd.h> +#ifdef HAVE_SHADOW_H +#include <shadow.h> +#endif +#include <time.h> + +#define PAM_SM_ACCOUNT + +#ifndef LINUX +# include <security/pam_appl.h> +#endif + +#define _PAM_EXTERN_FUNCTIONS +#include <security/pam_modules.h> + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ +#ifdef HAVE_SHADOW_H + const char *uname; + int retval; + time_t curdays; + struct spwd *spent; + struct passwd *pwent; + + setpwent(); + setspent(); + retval = pam_get_item(pamh,PAM_USER,(const void **)&uname); + if(retval != PAM_SUCCESS || uname == NULL) { + return PAM_SUCCESS; /* Couldn't get username, just ignore this + (i.e. they don't have any expiry info available */ + } + pwent = getpwnam(uname); + if(!pwent) + return PAM_USER_UNKNOWN; + if(strcmp(pwent->pw_passwd,"x")) + return PAM_SUCCESS; /* They aren't using shadow passwords & expiry + info */ + spent = getspnam(uname); + if(!spent) + return PAM_SUCCESS; /* Couldn't get username from shadow, just ignore this + (i.e. they don't have any expiry info available */ + curdays = time(NULL)/(60*60*24); + if((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact)) + && (spent->sp_max != -1) && (spent->sp_inact != -1)) + return PAM_ACCT_EXPIRED; + if((curdays > spent->sp_expire) && (spent->sp_expire != -1)) + return PAM_ACCT_EXPIRED; + endspent(); + endpwent(); +#endif + return PAM_SUCCESS; +} + + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_unix_acct_modstruct = { + "pam_unix_acct", + NULL, + NULL, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL, +}; +#endif diff --git a/contrib/libpam/modules/pam_unix/pam_unix_auth.c b/contrib/libpam/modules/pam_unix/pam_unix_auth.c new file mode 100644 index 0000000..95f13d0 --- /dev/null +++ b/contrib/libpam/modules/pam_unix/pam_unix_auth.c @@ -0,0 +1,307 @@ +/* $Header: /home/morgan/pam/Linux-PAM-0.59/modules/pam_unix/RCS/pam_unix_auth.c,v 1.1 1996/11/09 19:44:35 morgan Exp morgan $ */ + +/* + * Copyright Alexander O. Yuriev, 1996. All rights reserved. + * NIS+ support by Thorsten Kukuk <kukuk@weber.uni-paderborn.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $Log: pam_unix_auth.c,v $ + * + * Revision 1.9 1996/05/26 04:13:04 morgan + * added static support + * + * Revision 1.8 1996/05/21 03:51:58 morgan + * added "const" to rcsid[] definition + * + * Revision 1.7 1996/04/19 03:25:57 alex + * minor corrections. + * + * Revision 1.6 1996/04/17 01:05:05 alex + * _pam_auth_unix() cleaned up - non-authentication code is made into funcs + * and mostly moved out to support.c. + * + * Revision 1.5 1996/04/16 21:12:46 alex + * unix authentication works on Bach again. This is a tranitional stage. + * I really don't like that _pam_unix_auth() grew into a monster that does + * prompts etc etc. They should go into other functions. + * + * Revision 1.4 1996/04/07 08:06:12 morgan + * tidied up a little + * + * Revision 1.3 1996/04/07 07:34:07 morgan + * added conversation support. Now the module is capable of obtaining a + * username and a password all by itself. + * + * Revision 1.2 1996/03/29 02:31:19 morgan + * Marek Michalkiewicz's small patches for shadow support. + * + * Revision 1.1 1996/03/09 09:10:57 morgan + * Initial revision + * + */ + +#ifdef linux +# define _GNU_SOURCE +# include <features.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#define __USE_BSD +#include <unistd.h> +#include <pwd.h> +#include <sys/types.h> + +#ifndef NDEBUG + +#include <syslog.h> + +#endif /* NDEBUG */ + +#ifdef HAVE_SHADOW_H + +#include <shadow.h> + +#endif /* HAVE_SHADOW_H */ + +#ifndef LINUX + +#include <security/pam_appl.h> + +#endif /* LINUX */ + +#define _PAM_EXTERN_FUNCTIONS +#include <security/pam_modules.h> + +static const char rcsid[] = "$Id: pam_unix_auth.c,v 1.1 1996/11/09 19:44:35 morgan Exp morgan $ pam_unix authentication functions. alex@bach.cis.temple.edu"; + +/* Define function phototypes */ + +extern char *crypt(const char *key, const char *salt); /* This should have + been in unistd.h + but it is not */ +extern int converse( pam_handle_t *pamh, + int nargs, + struct pam_message **message, + struct pam_response **response ); + +extern int _set_auth_tok( pam_handle_t *pamh, + int flags, int argc, + const char **argv ); + +static int _pam_auth_unix( pam_handle_t *pamh, + int flags, int argc, + const char **argv ); + +static int _pam_set_credentials_unix ( pam_handle_t *pamh, + int flags, + int argc, + const char ** argv ) ; + + +/* Fun starts here :) + * + * _pam_auth_unix() actually performs UNIX/shadow authentication + * + * First, if shadow support is available, attempt to perform + * authentication using shadow passwords. If shadow is not + * available, or user does not have a shadow password, fallback + * onto a normal UNIX authentication + */ + +static int _pam_auth_unix( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) +{ + int retval; + struct passwd *pw; + const char *name; + char *p, *pp; + const char *salt; + +#ifdef HAVE_SHADOW_H + + struct spwd *sp; + +#endif + + /* get the user'name' */ + + if ( (retval = pam_get_user( pamh, &name, "login: ") ) != PAM_SUCCESS ) + return retval; + + /* + * at some point we will have to make this module pay + * attention to arguments, like 'pam_first_pass' etc... + */ + + pw = getpwnam ( name ); + + /* For NIS+, root cannot get password for lesser user */ + if (pw) { + uid_t save_euid, save_uid; + + save_uid = getuid (); + save_euid = geteuid(); + if (setreuid (0,pw->pw_uid) >= 0) { + pw = getpwnam ( name ); + setreuid (save_uid,save_euid); + } + } + + if ( pw && (!pw->pw_passwd || pw->pw_passwd[0] == '\0') && + !(flags & PAM_DISALLOW_NULL_AUTHTOK)) { + return PAM_SUCCESS; + } + pam_get_item( pamh, PAM_AUTHTOK, (void*) &p ); + + if ( !p ) + { + retval = _set_auth_tok( pamh, flags, argc, argv ); + if ( retval != PAM_SUCCESS ) + return retval; + } + + /* + We have to call pam_get_item() again because value of p should + change + */ + + pam_get_item( pamh, PAM_AUTHTOK, (void*) &p ); + + + if (pw) + { + +#ifdef HAVE_SHADOW_H + + /* + * Support for shadow passwords on Linux and SVR4-based + * systems. Shadow passwords are optional on Linux - if + * there is no shadow password, use the non-shadow one. + */ + + sp = getspnam( name ); + if (sp && (!strcmp(pw->pw_passwd,"x"))) + { + /* TODO: check if password has expired etc. */ + salt = sp->sp_pwdp; + } + else +#endif + salt = pw->pw_passwd; + } + else + return PAM_USER_UNKNOWN; + + /* The 'always-encrypt' method does not make sense in PAM + because the framework requires return of a different + error code for non-existant users -- alex */ + + if ( ( !pw->pw_passwd ) && ( !p ) ) + if ( flags && PAM_DISALLOW_NULL_AUTHTOK ) + return PAM_SUCCESS; + else + return PAM_AUTH_ERR; + + pp = crypt(p, salt); + + if ( strcmp( pp, salt ) == 0 ) + return PAM_SUCCESS; + + return PAM_AUTH_ERR; +} + +/* + * The only thing _pam_set_credentials_unix() does is initialization of + * UNIX group IDs. + * + * Well, everybody but me on linux-pam is convinced that it should not + * initialize group IDs, so I am not doing it but don't say that I haven't + * warned you. -- AOY + */ + +static int _pam_set_credentials_unix ( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) + +{ /* FIX ME: incorrect error code */ + + return PAM_SUCCESS; /* This is a wrong result code. From what I + remember from reafing one of the guides + there's an error-level saying 'N/A func' + -- AOY + */ +} + +/* + * PAM framework looks for these entry-points to pass control to the + * authentication module. + */ + +PAM_EXTERN +int pam_sm_authenticate( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) +{ + return _pam_auth_unix( pamh, flags, argc, argv ); +} + +PAM_EXTERN +int pam_sm_setcred( pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return _pam_set_credentials_unix ( pamh, flags, argc, argv ) ; +} + + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_unix_auth_modstruct = { + "pam_unix_auth", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; +#endif diff --git a/contrib/libpam/modules/pam_unix/pam_unix_passwd.c b/contrib/libpam/modules/pam_unix/pam_unix_passwd.c new file mode 100644 index 0000000..de1345e --- /dev/null +++ b/contrib/libpam/modules/pam_unix/pam_unix_passwd.c @@ -0,0 +1,813 @@ + +/* Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. + Copyright (C) 1996. */ + +/* + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + How it works: + Gets in username (has to be done) from the calling program + Does authentication of user (only if we are not running as root) + Gets new password/checks for sanity + Sets it. + */ + +#define PAM_SM_PASSWORD + +/* #define DEBUG 1 */ + +#include <stdio.h> +#include <sys/time.h> +#define _BSD_SOURCE +#define _SVID_SOURCE +#include <errno.h> +#define __USE_BSD +#define _BSD_SOURCE +#include <pwd.h> +#include <sys/types.h> + +/* why not defined? */ +void setpwent(void); +void endpwent(void); +int chmod(const char *path, mode_t mode); +struct passwd *fgetpwent(FILE *stream); +int putpwent(const struct passwd *p, FILE *stream); + +#include <unistd.h> +char *crypt(const char *key, const char *salt); +#ifdef USE_CRACKLIB +#include <crack.h> +#endif +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <stdarg.h> +#include <malloc.h> +#include <security/_pam_macros.h> + +#ifndef LINUX /* AGM added this as of 0.2 */ +#include <security/pam_appl.h> +#endif /* ditto */ +#include <security/pam_modules.h> +#ifdef HAVE_SHADOW_H +#include <shadow.h> +#endif + +#define MAX_PASSWD_TRIES 3 +#define OLD_PASSWORD_PROMPT "Password: " +#define NEW_PASSWORD_PROMPT "New password: " +#define AGAIN_PASSWORD_PROMPT "New password (again): " +#define PW_TMPFILE "/etc/npasswd" +#define SH_TMPFILE "/etc/nshadow" +#define CRACKLIB_DICTS "/usr/lib/cracklib_dict" + +/* Various flags for the getpass routine to send back in... */ +#define PPW_EXPIRED 1 +#define PPW_EXPIRING 2 +#define PPW_WILLEXPIRE 4 +#define PPW_NOSUCHUSER 8 +#define PPW_SHADOW 16 +#define PPW_TOOEARLY 32 +#define PPW_ERROR 64 + +#ifndef DO_TEST +#define STATIC static +#else +#define STATIC +#endif +/* Sets a password for the specified user to the specified password + Returns flags PPW_*, or'd. */ +STATIC int _do_setpass(char *forwho, char *towhat, int flags); +/* Gets a password for the specified user + Returns flags PPW_*, or'd. */ +STATIC int _do_getpass(char *forwho, char **theirpass); +/* Checks whether the password entered is same as listed in the database + 'entered' should not be crypt()'d or anything (it should be as the + user entered it...), 'listed' should be as it is listed in the + password database file */ +STATIC int _do_checkpass(const char *entered, char *listed); + +/* sends a one-way message to the user, either error or info... */ +STATIC int conv_sendmsg(struct pam_conv *aconv, const char *message, int style); +/* sends a message and returns the results of the conversation */ +STATIC int conv_getitem(struct pam_conv *aconv, char *message, int style, + char **result); + +PAM_EXTERN +int pam_sm_chauthtok( pam_handle_t *pamh, + int flags, + int argc, + const char **argv); + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-unix_passwd", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +#ifdef NEED_LCKPWDF +/* This is a hack, but until libc and glibc both include this function + * by default (libc only includes it if nys is not being used, at the + * moment, and glibc doesn't appear to have it at all) we need to have + * it here, too. :-( + * + * This should not become an official part of PAM. + * + * BEGIN_HACK +*/ + +/* + * lckpwdf.c -- prevent simultaneous updates of password files + * + * Before modifying any of the password files, call lckpwdf(). It may block + * for up to 15 seconds trying to get the lock. Return value is 0 on success + * or -1 on failure. When you are done, call ulckpwdf() to release the lock. + * The lock is also released automatically when the process exits. Only one + * process at a time may hold the lock. + * + * These functions are supposed to be conformant with AT&T SVID Issue 3. + * + * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, + * public domain. + */ + +#include <fcntl.h> +#include <signal.h> + +#define LOCKFILE "/etc/.pwd.lock" +#define TIMEOUT 15 + +static int lockfd = -1; + +static int +set_close_on_exec(int fd) +{ + int flags = fcntl(fd, F_GETFD, 0); + if (flags == -1) + return -1; + flags |= FD_CLOEXEC; + return fcntl(fd, F_SETFD, flags); +} + +static int +do_lock(int fd) +{ + struct flock fl; + + memset(&fl, 0, sizeof fl); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + return fcntl(fd, F_SETLKW, &fl); +} + +static void +alarm_catch(int sig) +{ +/* does nothing, but fcntl F_SETLKW will fail with EINTR */ +} + +static int lckpwdf(void) +{ + struct sigaction act, oldact; + sigset_t set, oldset; + + if (lockfd != -1) + return -1; + + lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600); + if (lockfd == -1) + return -1; + if (set_close_on_exec(lockfd) == -1) + goto cleanup_fd; + + memset(&act, 0, sizeof act); + act.sa_handler = alarm_catch; + act.sa_flags = 0; + sigfillset(&act.sa_mask); + if (sigaction(SIGALRM, &act, &oldact) == -1) + goto cleanup_fd; + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1) + goto cleanup_sig; + + alarm(TIMEOUT); + if (do_lock(lockfd) == -1) + goto cleanup_alarm; + alarm(0); + sigprocmask(SIG_SETMASK, &oldset, NULL); + sigaction(SIGALRM, &oldact, NULL); + return 0; + +cleanup_alarm: + alarm(0); + sigprocmask(SIG_SETMASK, &oldset, NULL); +cleanup_sig: + sigaction(SIGALRM, &oldact, NULL); +cleanup_fd: + close(lockfd); + lockfd = -1; + return -1; +} + +static int +ulckpwdf(void) +{ + unlink(LOCKFILE); + if (lockfd == -1) + return -1; + + if (close(lockfd) == -1) { + lockfd = -1; + return -1; + } + lockfd = -1; + return 0; +} +/* END_HACK */ +#endif + +#define PAM_FAIL_CHECK if(retval != PAM_SUCCESS) { return retval; } + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + char *usrname, *curpass, *newpass; /* pointers to the username, + current password, and new password */ + + struct pam_conv *appconv; /* conversation with the app */ + struct pam_message msg, *pmsg; /* Misc for conversations */ + struct pam_response *resp; + + int retval=0; /* Gets the return values for all our function calls */ + unsigned int pflags=0; /* Holds the flags from our getpass & setpass + functions */ + + const char *cmiscptr; /* Utility variables, used for different purposes at + different times */ + char *miscptr; /* Utility variables, used for different purposes at + different times */ + unsigned int miscint; + int fascist = 1; /* Be fascist by default. If compiled with cracklib, + call cracklib. Otherwise just check length... */ + + char argbuf[256],argval[256]; + int i; + + + retval = pam_get_item(pamh,PAM_CONV,(const void **) &appconv); + PAM_FAIL_CHECK; + + retval = pam_get_item(pamh,PAM_USER,(const void **) &usrname); + PAM_FAIL_CHECK; + if(flags & PAM_PRELIM_CHECK) { + pflags = _do_getpass(usrname,&miscptr); + if(pflags & PPW_NOSUCHUSER) + return PAM_USER_UNKNOWN; + else if(pflags & ~(PPW_SHADOW|PPW_EXPIRING|PPW_WILLEXPIRE)) + return PAM_AUTHTOK_ERR; + else + return PAM_SUCCESS; + } /* else... */ +#ifdef DEBUG + fprintf(stderr,"Got username of %s\n",usrname); +#endif + if((usrname == NULL) || (strlen(usrname) < 1)) { + /* The app is supposed to get us the username! */ + retval = PAM_USER_UNKNOWN; + PAM_FAIL_CHECK; + } + + for(i=0; i < argc; i++) { + { + char *tmp = x_strdup(argv[i]); + strncpy(argbuf,strtok(tmp ,"="),255); + strncpy(argval,strtok(NULL,"="),255); + free(tmp); + } + + /* For PC functionality use "strict" -- historically "fascist" */ + if(!strcmp(argbuf,"strict") || !strcmp(argbuf, "fascist")) + + if(!strcmp(argval,"true")) + fascist = 1; + else if(!strcmp(argval,"false")) + fascist = 0; + else + return PAM_SERVICE_ERR; + else { + _pam_log(LOG_ERR,"Unknown option: %s",argbuf); + return PAM_SERVICE_ERR; + } + } + + + /* Now we have all the initial information we need from the app to + set things up (we assume that getting the username succeeded...) */ + retval = pam_get_item(pamh,PAM_OLDAUTHTOK,(const void **) &curpass); + PAM_FAIL_CHECK; + if(getuid()) { /* If this is being run by root, we don't need to get their + old password. + note */ + /* If we haven't been given a password yet, prompt for one... */ + miscint=0; + while((curpass == NULL) && (miscint++ < MAX_PASSWD_TRIES)) { + pflags = _do_getpass(usrname,&miscptr); + if(pflags & PPW_NOSUCHUSER) + return PAM_USER_UNKNOWN; /* If the user that was passed in doesn't + exist, say so and exit (app passes in + username) */ + + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msg.msg = OLD_PASSWORD_PROMPT; + resp = NULL; + + retval = appconv->conv(1, (const struct pam_message **) &pmsg, + &resp, appconv->appdata_ptr); + + PAM_FAIL_CHECK; + curpass = resp->resp; + free (resp); + if(_do_checkpass(curpass?curpass:"",miscptr)) { + int abortme = 0; + + /* password is incorrect... */ + if (curpass && curpass[0] == '\0') { + /* ...and it was zero-length; user wishes to abort change */ + abortme = 1; + } + if (curpass) { free (curpass); } + curpass = NULL; + if (abortme) { + conv_sendmsg(appconv,"Password change aborted.",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + } + } + + if(curpass == NULL) + return PAM_AUTH_ERR; /* They didn't seem to enter the right password + for three tries - error */ + pam_set_item(pamh, PAM_OLDAUTHTOK, (void *)curpass); + } else { +#ifdef DEBUG + fprintf(stderr,"I am ROOT!\n"); +#endif + pflags = _do_getpass(usrname,&curpass); + if(curpass == NULL) + curpass = x_strdup(""); + } + if(pflags & PPW_TOOEARLY) { + conv_sendmsg(appconv,"You must wait longer to change your password", + PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + if(pflags & PPW_WILLEXPIRE) + conv_sendmsg(appconv,"Your password is about to expire",PAM_TEXT_INFO); + else if(pflags & PPW_EXPIRED) + return PAM_ACCT_EXPIRED; /* If their account has expired, we can't auth + them to change their password */ + if(!(pflags & PPW_EXPIRING) && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) + return PAM_SUCCESS; + /* If we haven't been given a password yet, prompt for one... */ + miscint=0; + pam_get_item(pamh,PAM_AUTHTOK,(const void **)&newpass); + cmiscptr = NULL; + while((newpass == NULL) && (miscint++ < MAX_PASSWD_TRIES)) { + + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msg.msg = NEW_PASSWORD_PROMPT; + resp = NULL; + + retval = appconv->conv(1, (const struct pam_message **) &pmsg, + &resp, appconv->appdata_ptr); + + PAM_FAIL_CHECK; + newpass = resp->resp; + free (resp); + +#ifdef DEBUG + if(newpass) + fprintf(stderr,"Got password of %s\n",newpass); + else + fprintf(stderr,"No new password...\n"); +#endif + if (newpass[0] == '\0') { free (newpass); newpass = (char *) 0; } + cmiscptr=NULL; + if(newpass) { +#ifdef USE_CRACKLIB + if(fascist && getuid()) + cmiscptr = FascistCheck(newpass,CRACKLIB_DICTS); +#else + if(fascist && getuid() && strlen(newpass) < 6) + cmiscptr = "You must choose a longer password"; +#endif + if(curpass) + if(!strcmp(curpass,newpass)) { + cmiscptr="You must choose a new password."; + newpass=NULL; + } + } else { + /* We want to abort the password change */ + conv_sendmsg(appconv,"Password change aborted",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + if(!cmiscptr) { + /* We ask them to enter their password again... */ + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msg.msg = AGAIN_PASSWORD_PROMPT; + resp = NULL; + + retval = appconv->conv(1, (const struct pam_message **) &pmsg, + &resp, appconv->appdata_ptr); + + PAM_FAIL_CHECK; + miscptr = resp->resp; + free (resp); + if (miscptr[0] == '\0') { free (miscptr); miscptr = (char *) 0; } + if(!miscptr) { /* Aborting password change... */ + conv_sendmsg(appconv,"Password change aborted",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } + if(!strcmp(newpass,miscptr)) { + miscptr=NULL; + break; + } + conv_sendmsg(appconv,"You must enter the same password twice.", + PAM_ERROR_MSG); + miscptr=NULL; + newpass=NULL; + } + else { + conv_sendmsg(appconv,cmiscptr,PAM_ERROR_MSG); + newpass = NULL; + } + } + if(cmiscptr) { + /* conv_sendmsg(appconv,cmiscptr,PAM_ERROR_MSG); */ + return PAM_AUTHTOK_ERR; + } else if(newpass == NULL) + return PAM_AUTHTOK_ERR; /* They didn't seem to enter the right password + for three tries - error */ +#ifdef DEBUG + printf("Changing password for sure!\n"); +#endif + /* From now on, we are bound and determined to get their password + changed :-) */ + pam_set_item(pamh, PAM_AUTHTOK, (void *)newpass); + retval = _do_setpass(usrname,newpass,pflags); +#ifdef DEBUG + fprintf(stderr,"retval was %d\n",retval); +#endif + if(retval & ~PPW_SHADOW) { + conv_sendmsg(appconv,"Error: Password NOT changed",PAM_ERROR_MSG); + return PAM_AUTHTOK_ERR; + } else { + conv_sendmsg(appconv,"Password changed",PAM_TEXT_INFO); + return PAM_SUCCESS; + } +} + +/* _do_checkpass() returns 0 on success, non-0 on failure */ +STATIC int _do_checkpass(const char *entered, char *listed) +{ + char salt[3]; + if ((strlen(listed) == 0) &&(strlen(entered) == 0)) { + /* no password in database; no password entered */ + return (0); + } + salt[0]=listed[0]; salt[1]=listed[1]; salt[2]='\0'; + return strcmp(crypt(entered,salt),listed); +} + +STATIC char mksalt(int seed) { + int num = seed % 64; + + if (num < 26) + return 'a' + num; + else if (num < 52) + return 'A' + (num - 26); + else if (num < 62) + return '0' + (num - 52); + else if (num == 63) + return '.'; + else + return '/'; +} + +STATIC int _do_setpass(char *forwho, char *towhat,int flags) +{ + struct passwd *pwd=NULL, *tmpent=NULL; + FILE *pwfile,*opwfile; + char thesalt[3]; + int retval=0; + struct timeval time1; + int err = 0; +#ifdef HAVE_SHADOW_H + struct spwd *spwdent=NULL, *stmpent=NULL; +#endif + if(flags & PPW_SHADOW) { retval |= PPW_SHADOW; } + gettimeofday(&time1, NULL); + srand(time1.tv_usec); + thesalt[0]=mksalt(rand()); + thesalt[1]=mksalt(rand()); + thesalt[2]='\0'; + + /* lock the entire password subsystem */ +#ifdef USE_LCKPWDF + lckpwdf(); +#endif + setpwent(); + pwd = getpwnam(forwho); +#ifdef DEBUG + printf("Got %p, for %s (salt %s)\n",pwd, + forwho,thesalt); +#endif + if(pwd == NULL) + return PPW_NOSUCHUSER; + endpwent(); + +#ifdef HAVE_SHADOW_H + if(flags & PPW_SHADOW) { + spwdent = getspnam(forwho); + if(spwdent == NULL) + return PPW_NOSUCHUSER; + spwdent->sp_pwdp = towhat; + spwdent->sp_lstchg = time(NULL)/(60*60*24); + pwfile = fopen(SH_TMPFILE,"w"); + opwfile = fopen("/etc/shadow","r"); + if(pwfile == NULL || opwfile == NULL) + return PPW_ERROR; + chown(SH_TMPFILE,0,0); + chmod(SH_TMPFILE,0600); + stmpent=fgetspent(opwfile); + while(stmpent) { + if(!strcmp(stmpent->sp_namp,forwho)) { + stmpent->sp_pwdp = crypt(towhat,thesalt); + stmpent->sp_lstchg = time(NULL)/(60*60*24); +#ifdef DEBUG + fprintf(stderr,"Set password %s for %s\n",stmpent->sp_pwdp, + forwho); +#endif + } + if (putspent(stmpent,pwfile)) { + fprintf(stderr, "error writing entry to shadow file: %s\n", + strerror(errno)); + err = 1; + retval = PPW_ERROR; + break; + } + stmpent=fgetspent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + fprintf(stderr, "error writing entries to shadow file: %s\n", + strerror(errno)); + retval = PPW_ERROR; + err = 1; + } + + if (!err) + rename(SH_TMPFILE,"/etc/shadow"); + else + unlink(SH_TMPFILE); + } else { + pwd->pw_passwd = towhat; + pwfile = fopen(PW_TMPFILE,"w"); + opwfile = fopen("/etc/passwd","r"); + if(pwfile == NULL || opwfile == NULL) + return PPW_ERROR; + chown(PW_TMPFILE,0,0); + chmod(PW_TMPFILE,0644); + tmpent=fgetpwent(opwfile); + while(tmpent) { + if(!strcmp(tmpent->pw_name,forwho)) { + tmpent->pw_passwd = crypt(towhat,thesalt); + } + if (putpwent(tmpent,pwfile)) { + fprintf(stderr, "error writing entry to password file: %s\n", + strerror(errno)); + err = 1; + retval = PPW_ERROR; + break; + } + tmpent=fgetpwent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + fprintf(stderr, "error writing entries to password file: %s\n", + strerror(errno)); + retval = PPW_ERROR; + err = 1; + } + + if (!err) + rename(PW_TMPFILE,"/etc/passwd"); + else + unlink(PW_TMPFILE); + } +#else + pwd->pw_passwd = towhat; + pwfile = fopen(PW_TMPFILE,"w"); + opwfile = fopen("/etc/passwd","r"); + if(pwfile == NULL || opwfile == NULL) + return PPW_ERROR; + chown(PW_TMPFILE,0,0); + chmod(PW_TMPFILE,0644); + tmpent=fgetpwent(opwfile); + while(tmpent) { + if(!strcmp(tmpent->pw_name,forwho)) { + tmpent->pw_passwd = crypt(towhat,thesalt); + } + if (putpwent(tmpent,pwfile)) { + fprintf(stderr, "error writing entry to shadow file: %s\n", + strerror(errno)); + err = 1; + retval = PPW_ERROR; + break; + } + tmpent=fgetpwent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + fprintf(stderr, "error writing entries to password file: %s\n", + strerror(errno)); + retval = PPW_ERROR; + err = 1; + } + + if (!err) + rename(PW_TMPFILE,"/etc/passwd"); + else + unlink(PW_TMPFILE); +#endif + /* unlock the entire password subsystem */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; +} + +STATIC int _do_getpass(char *forwho, char **theirpass) +{ + struct passwd *pwd=NULL; /* Password and shadow password */ +#ifdef HAVE_SHADOW_H + struct spwd *spwdent=NULL; /* file entries for the user */ + time_t curdays; +#endif + int retval=0; + /* UNIX passwords area */ + setpwent(); + pwd = getpwnam(forwho); /* Get password file entry... */ + endpwent(); + if(pwd == NULL) + return PPW_NOSUCHUSER; /* We don't need to do the rest... */ +#ifdef HAVE_SHADOW_H + if(!strcmp(pwd->pw_passwd,"x")) { + /* ...and shadow password file entry for this user, if shadowing + is enabled */ + retval |= PPW_SHADOW; + setspent(); + spwdent = getspnam(forwho); + endspent(); + if(spwdent == NULL) + return PPW_NOSUCHUSER; + *theirpass = x_strdup(spwdent->sp_pwdp); + + /* We have the user's information, now let's check if their account + has expired (60 * 60 * 24 = number of seconds in a day) */ + + /* Get the current number of days since 1970 */ + curdays = time(NULL)/(60*60*24); + if((curdays < (spwdent->sp_lstchg + spwdent->sp_min)) + && (spwdent->sp_min != -1)) + retval |= PPW_TOOEARLY; + else if((curdays + > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact)) + && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1)) + /* Their password change has been put off too long, + OR their account has just plain expired */ + retval |= PPW_EXPIRED; + else if((curdays > (spwdent->sp_lstchg + spwdent->sp_max)) + && (spwdent->sp_max != -1)) + /* Their passwd needs to be changed */ + retval |= PPW_EXPIRING; + else if((curdays > (spwdent->sp_lstchg + + spwdent->sp_max - spwdent->sp_warn)) + && (spwdent->sp_max != -1) && (spwdent->sp_warn != -1)) + retval |= PPW_WILLEXPIRE; +/* if(spwdent->sp_lstchg < 0) + retval &= ~(PPW_WILLEXPIRE | PPW_EXPIRING | PPW_EXPIRED); + if(spwdent->sp_max < 0) + retval &= ~(PPW_EXPIRING | PPW_EXPIRED); */ + } else { + *theirpass = (char *)x_strdup(pwd->pw_passwd); + } + +#else + *theirpass = (char *) x_strdup(pwd->pw_passwd); +#endif + + return retval; +} + +STATIC int conv_sendmsg(struct pam_conv *aconv, const char *message, int style) +{ + struct pam_message msg,*pmsg; + struct pam_response *resp; + int retval; + + /* Get the password from the user... */ + pmsg = &msg; + + msg.msg_style = style; + msg.msg = message; + resp = NULL; + + retval = aconv->conv(1, (const struct pam_message **) &pmsg, + &resp, aconv->appdata_ptr); + if (resp) { + _pam_drop_reply(resp, 1); + } + return retval; +} + + +STATIC int conv_getitem(struct pam_conv *aconv, char *message, int style, + char **result) +{ + struct pam_message msg,*pmsg; + struct pam_response *resp; + int retval; + + D(("called.")); + + /* Get the password from the user... */ + pmsg = &msg; + msg.msg_style = style; + msg.msg = message; + resp = NULL; + + retval = aconv->conv(1, (const struct pam_message **) &pmsg, + &resp, aconv->appdata_ptr); + if(retval != PAM_SUCCESS) + return retval; + if(resp != NULL) { + *result = resp->resp; free(resp); + return PAM_SUCCESS; + } + else + return PAM_SERVICE_ERR; +} diff --git a/contrib/libpam/modules/pam_unix/pam_unix_sess.c b/contrib/libpam/modules/pam_unix/pam_unix_sess.c new file mode 100644 index 0000000..319b2ed --- /dev/null +++ b/contrib/libpam/modules/pam_unix/pam_unix_sess.c @@ -0,0 +1,181 @@ +/* + * $Header: /home/morgan/pam/Linux-PAM-0.53/modules/pam_unix/RCS/pam_unix_sess.c,v 1.1 1996/11/09 19:44:35 morgan Exp $ + */ + +/* + * Copyright Alexander O. Yuriev, 1996. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $Log: pam_unix_sess.c,v $ + * Revision 1.1 1996/11/09 19:44:35 morgan + * Initial revision + * + * Revision 1.4 1996/05/21 03:55:17 morgan + * added "const" to definition of rcsid[] + * + * Revision 1.3 1996/04/23 16:32:28 alex + * nothing really got changed. + * + * Revision 1.2 1996/04/19 03:23:33 alex + * session code implemented. account management moved into pam_unix_acct.c + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <pwd.h> + +#ifndef LINUX /* AGM added this as of 0.2 */ + + #include <security/pam_appl.h> + +#endif /* ditto */ + +#include <security/pam_modules.h> +#include <syslog.h> +#include <unistd.h> +#ifndef LOG_AUTHPRIV +#define LOG_AUTHPRIV LOG_AUTH +#endif + +static const char rcsid[] = "$Id: pam_unix_sess.c,v 1.1 1996/11/09 19:44:35 morgan Exp $ pam_unix session management. alex@bach.cis.temple.edu"; + +/* Define internal functions */ + +static int _get_log_level( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ); + +int _pam_unix_open_session( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ); + +int _pam_unix_close_session( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ); + +/* Implementation */ + +static int _get_log_level( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) +{ + int i = argc; + int log_level = LOG_DEBUG; + + while ( i-- ) + { + if ( strcmp( *argv, "debug" ) == 0 ) + log_level = LOG_DEBUG; + else if ( strcmp ( *argv, "trace" ) == 0 ) + log_level = LOG_AUTHPRIV; + argv++; + } + + return log_level; +} + +int _pam_unix_open_session( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) +{ + int log_level; + char *user_name, *service; + + + log_level = _get_log_level( pamh, flags, argc, argv ); + + pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( !user_name ) + return PAM_CONV_ERR; /* How did we get authenticated with + no username?! */ + + pam_get_item( pamh, PAM_SERVICE, (void*) &service ); + if ( !service ) + return PAM_CONV_ERR; + + syslog ( log_level, + "pam_unix authentication session started, user %s, service %s\n", + user_name, service ); + + return PAM_SUCCESS; +} + +int _pam_unix_close_session( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) +{ + int log_level; + char *user_name, *service; + + log_level = _get_log_level( pamh, flags, argc, argv ); + + pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( !user_name ) + return PAM_CONV_ERR; /* How did we get authenticated with + no username?! */ + + pam_get_item( pamh, PAM_SERVICE, (void*) &service ); + if ( !service ) + return PAM_CONV_ERR; + + syslog ( log_level, + "pam_unix authentication session finished, user %s, service %s\n", + user_name, service ); + + return PAM_SUCCESS; +} + +int pam_sm_open_session( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ) +{ + return _pam_unix_open_session( pamh, flags, argc, argv ) ; +} + +int pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + return _pam_unix_close_session( pamh, flags, argc, argv ) ; +} + diff --git a/contrib/libpam/modules/pam_unix/support.c b/contrib/libpam/modules/pam_unix/support.c new file mode 100644 index 0000000..a2fafcd --- /dev/null +++ b/contrib/libpam/modules/pam_unix/support.c @@ -0,0 +1,152 @@ +/* + * $Header: /home/morgan/pam/Linux-PAM-0.53/modules/pam_unix/RCS/support.c,v 1.1 1996/11/09 19:44:35 morgan Exp $ + */ + +/* + * Copyright Andrew Morgan, 1996. All rights reserved. + * Modified by Alexander O. Yuriev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $Log: support.c,v $ + * Revision 1.1 1996/11/09 19:44:35 morgan + * Initial revision + * + * Revision 1.1 1996/04/17 01:11:08 alex + * Initial revision + * + */ + +#include <stdlib.h> /* define NULL */ + +#ifndef LINUX + + #include <security/pam_appl.h> + +#endif /* LINUX */ + +#include <security/pam_modules.h> + + +#ifndef NDEBUG + + #include <syslog.h> + +#endif /* NDEBUG */ + + +/* Phototype declarations */ + +int converse( pam_handle_t *pamh, + int nargs, + struct pam_message **message, + struct pam_response **response ); + +int _set_auth_tok( pam_handle_t *pamh, + int flags, + int argc, + const char **argv ); + +/* Implementation */ + +int converse( pam_handle_t *pamh, + int nargs, + struct pam_message **message, + struct pam_response **response ) + +{ + int retval; + struct pam_conv *conv; + + retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; + if ( retval == PAM_SUCCESS ) + { + retval = conv->conv( nargs, + ( const struct pam_message ** ) message, + response, + conv->appdata_ptr ); + } + return retval; +} + +/***************************************************************************/ +/* prompt user for a using conversation calls */ +/***************************************************************************/ + +int _set_auth_tok( pam_handle_t *pamh, + int flags, int argc, + const char **argv ) +{ + int retval; + char *p; + + struct pam_message msg[1],*pmsg[1]; + struct pam_response *resp; + + /* set up conversation call */ + + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = "Password: "; + resp = NULL; + + if ( ( retval = converse( pamh, 1 , pmsg, &resp ) ) != PAM_SUCCESS ) + return retval; + + if ( resp ) + { + if ( ( flags & PAM_DISALLOW_NULL_AUTHTOK ) && + resp[0].resp == NULL ) + { + free( resp ); + return PAM_AUTH_ERR; + } + + p = resp[ 0 ].resp; + + /* This could be a memory leak. If resp[0].resp + is malloc()ed, then it has to be free()ed! + -- alex + */ + + resp[ 0 ].resp = NULL; + + } + else + return PAM_CONV_ERR; + + free( resp ); + pam_set_item( pamh, PAM_AUTHTOK, p ); + return PAM_SUCCESS; +} |