summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile86
-rw-r--r--README30
-rw-r--r--pam_pwdfile.c326
3 files changed, 442 insertions, 0 deletions
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 <cpbotha@ieee.org>
+$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 <cpbotha@ieee.org>
+ *
+ * $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 <security/pam_appl.h>
+#endif /* LINUX */
+
+#define PAM_SM_AUTH
+#include <security/pam_modules.h>
+
+#include <syslog.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _XOPEN_SOURCE
+#include <unistd.h>
+
+/* 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