From 60d8c9e5a38161624cb7f620b012e85c3b7fb378 Mon Sep 17 00:00:00 2001 From: Charl Botha Date: Thu, 5 Aug 1999 13:09:07 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r2, which included commits to RCS files with non-trunk default branches. --- Makefile | 86 ++++++++++++++++ README | 30 ++++++ pam_pwdfile.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 pam_pwdfile.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..735458d --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +# $Id: Makefile,v 1.1.1.1 1999-08-05 13:09:07 cpbotha 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!). +# + +TITLE=pam_pwdfile + +# + +LIBSRC = $(TITLE).c +LIBOBJ = $(TITLE).o +LDLIBS = -lcrypt +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + + +ifdef DYNAMIC +LIBSHARED = $(TITLE).so +endif + +ifdef STATIC +LIBSTATIC = lib$(TITLE).o +endif + +####################### don't edit below ####################### + +dummy: + + @echo "**** This is not a top-level Makefile " + exit + +all: dirs $(LIBSHARED) $(LIBSTATIC) register + +dirs: +ifdef DYNAMIC + $(MKDIR) ./dynamic +endif +ifdef STATIC + $(MKDIR) ./static +endif + +register: +ifdef STATIC + ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) +endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) $(LDLIBS) +endif + +ifdef STATIC +$(LIBOBJS): $(LIBSRC) + +$(LIBSTATIC): $(LIBOBJS) + $(LD) -r -o $@ $(LIBOBJS) $(LDLIBS) +endif + +install: all + $(MKDIR) $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so + +clean: + rm -f $(LIBOBJD) $(LIBOBJS) core *~ + +extraclean: clean + rm -f *.a *.o *.so *.bak dynamic/* static/* + +.c.o: + $(CC) $(CFLAGS) -c $< + diff --git a/README b/README new file mode 100644 index 0000000..4934098 --- /dev/null +++ b/README @@ -0,0 +1,30 @@ +README for pam_pwdfile PAM module - Charl P. Botha +$Id: README,v 1.1.1.1 1999-08-05 13:09:07 cpbotha Exp $ +--------------------------------------------------------------------------- + +Let's say that this is version 0.1 of pam_pwdfile. + +This pam module can be used for the authentication service only, in cases +where one wants to use a different set of passwords than those in the main +system password database. E.g. in our case we have an imap server running, +and prefer to keep the imap passwords different from the system passwords +for security reasons. + +The /etc/pam.d/imap looks like this: +#%PAM-1.0 +auth required /lib/security/pam_pwdfile.so pwdfile /etc/imap.passwd +account required /lib/security/pam_pwdb.so + +At the moment the only parameters that pam_pwdfile.so parses for is +"pwdfile", followed by the name of the ASCII password database, as in the +above example. + +The ASCII password file is simply a list of lines, each looking like this: +username:crypted_passwd[13] + +Note that we still expect users to have accounts in the usual place, as we +make use of the pam_pwdb.so module for the account service. This module is +just so that one can have multiple sets of passwords for different services, +e.g. with our /etc/imap.passwd. + +These files have been created for inclusion into the PAM source tree. diff --git a/pam_pwdfile.c b/pam_pwdfile.c new file mode 100644 index 0000000..cd5c828 --- /dev/null +++ b/pam_pwdfile.c @@ -0,0 +1,326 @@ +/* pam_pwdfile.c copyright 1999 by Charl P. Botha + * + * $Id: pam_pwdfile.c,v 1.1.1.1 1999-08-05 13:09:07 cpbotha Exp $ + * + * pam authentication module that can be pointed at any username/crypted + * text file so that pam using application can use an alternate set of + * passwords than specified in system password database + * + * Copyright (c) Charl P. Botha, 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. + */ + +#ifndef LINUX +#include +#endif /* LINUX */ + +#define PAM_SM_AUTH +#include + +#include +#include +#include +#include +#include + +#define _XOPEN_SOURCE +#include + +/* unistd.h does not declare this as it should */ +extern char *crypt(const char *key, const char *salt); + +#define PWDF_PARAM "pwdfile" +#define PWDFN_LEN 256 +#define CRYPTEDPWD_LEN 13 + +#ifdef DEBUG +# define D(a) a; +#else +# define D(a) {} +#endif + +/* prototypes */ +int converse(pam_handle_t *, int, struct pam_message **, struct pam_response **); +int _set_auth_tok(pam_handle_t *, int, int, const char **); + +/* logging function ripped from pam_listfile.c */ +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("pam_pwdfile", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* this function ripped from pam_unix/support.c */ +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; +} + +/* this function ripped from pam_unix/support.c */ +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; +} + + +/* puts the crypted password corresponding to user "name" in password, + * from a file with lines consisting of: name:crypted_password + * if unsucessful, returns 0 + */ +static int fgetpwnam(FILE *stream, const char *name, char *password) { + char tempLine[256], *tpointer, *curname, *curpass, *fgr; + int loopdone, pwdfound; + + /* go to beginning of file */ + rewind(stream); + /* some control variables */ + loopdone = pwdfound = 0; + /* iterate through lines in file, until end of file */ + do { + /* get the current line */ + fgr = fgets(tempLine,256,stream); + /* if it's valid, go on */ + if ( fgr != NULL) { + /* first get the username out */ + tpointer = tempLine; + curname = strsep(&tpointer,":"); + /* check to see if it's the right one */ + if (strcmp(curname,name)==0) { + /* at least we know our loop is done */ + loopdone = 1; + /* get the password and put it in its place */ + curpass = strsep(&tpointer,":"); + if (curpass != NULL) { + strncpy(password,curpass,CRYPTEDPWD_LEN+1); + pwdfound = 1; + } /* if (curpass... */ + } /* if (strcmp(curname... */ + } /* if (tempLine... */ + } while (fgr != NULL); + return pwdfound; +} + +/* expected hook for auth service */ +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char **argv) { + int retval, pcnt, pwdfilename_found, loopdone; + const char *name; + char *password; + char pwdfilename[PWDFN_LEN]; + char salt[3], crypted_password[CRYPTEDPWD_LEN+1]; + FILE *pwdfile; + + /* we require the pwdfile switch and argument to be present, else we don't work */ + /* pcnt is the parameter counter variable for iterating through argv + * loopdone is an extra loop control variable */ + pcnt = loopdone = pwdfilename_found = 0; + do { + /* see if the current parameter looks like "pwdfile" */ + if (strcmp(argv[pcnt],PWDF_PARAM)==0) { + /* if argv is long enough, grab the subsequent parameter */ + if (pcnt+1 < argc) { + /* make sure we can't overflow */ + strncpy(pwdfilename,argv[pcnt+1],PWDFN_LEN); + /* indicate that we've found it */ + pwdfilename_found = 1; + } + /* whether we actually found the name or not, this loop is done, + * as we have found the pwdfile switch itself */ + loopdone = 1; + } + } while (!loopdone && pcnt++ < argc); + + /* for some or other reason, the password file wasn't specified */ + if (!pwdfilename_found) { + _pam_log(LOG_ERR,"password file name not specified"); + return PAM_AUTHINFO_UNAVAIL; + } + + /* DEBUG */ + D(_pam_log(LOG_ERR, "password filename extracted")); + + /* now try to open the password file */ + if ((pwdfile=fopen(pwdfilename,"r"))==NULL) { + _pam_log(LOG_ERR,"couldn't open password file %s",pwdfilename); + return PAM_AUTHINFO_UNAVAIL; + } + + /* get user name */ + if ((retval = pam_get_user(pamh,&name,"login: ")) != PAM_SUCCESS) { + _pam_log(LOG_ERR, "username not found"); + fclose(pwdfile); + return retval; + } + + /* DEBUG */ + D(_pam_log(LOG_ERR,"username is %s", name)); + + /* get password - code from pam_unix_auth.c */ + pam_get_item(pamh, PAM_AUTHTOK, (void *)&password); + if (!password) { + retval = _set_auth_tok(pamh, flags, argc, argv); + if (retval!=PAM_SUCCESS) { + fclose(pwdfile); + return retval; + } + } + pam_get_item(pamh, PAM_AUTHTOK, (void *)&password); + + if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) { + _pam_log(LOG_ERR, "auth token not found"); + fclose(pwdfile); + return retval; + } + + /* DEBUG */ + D(_pam_log(LOG_ERR,"got password from user", password)); + + /* now crypt password and compare to the user entry in the password file */ + /* first make sure password is long enough -- may I do this? */ + if (strlen(password)<2 || password==NULL) { + _pam_log(LOG_ERR,"password too short or NULL"); + fclose(pwdfile); + return PAM_AUTH_ERR; + } + + /* get the crypted password corresponding to this user */ + if (!fgetpwnam(pwdfile, name, crypted_password)) { + _pam_log(LOG_ERR,"password file corrupt"); + fclose(pwdfile); + return PAM_AUTHINFO_UNAVAIL; + } + + /* DEBUG */ + D(_pam_log(LOG_ERR,"got crypted password == %s", crypted_password)); + + /* extract the salt */ + salt[0] = crypted_password[0]; salt[1] = crypted_password[1]; salt[2] = '\0'; + + /* DEBUG */ + D(_pam_log(LOG_ERR,"user password crypted is %s", crypt(password,salt))); + + /* if things don't match up, complain */ + crypted_password[CRYPTEDPWD_LEN] = '\0'; + if (strcmp(crypt(password,salt),crypted_password)!=0) { + _pam_log(LOG_ERR,"wrong password for user %s",name); + fclose(pwdfile); + return PAM_AUTH_ERR; + } + + /* DEBUG */ + D(_pam_log(LOG_ERR,"passwords match")); + + /* we've gotten here, i.e. authentication was sucessful! */ + fclose(pwdfile); + return PAM_SUCCESS; +} + +/* another expected hook */ +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC +struct pam_module _pam_listfile_modstruct = { + "pam_pwdfile", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; +#endif -- cgit v1.2.3