From ea488580c42e8918445a945484de3c8a5addc761 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Tue, 20 Jun 2000 22:10:38 +0000 Subject: Initial revision --- modules/pam_userdb/.cvsignore | 1 + modules/pam_userdb/Makefile | 81 +++++++++++ modules/pam_userdb/README | 30 ++++ modules/pam_userdb/conv.c | 125 ++++++++++++++++ modules/pam_userdb/create.pl | 23 +++ modules/pam_userdb/libdbfound.sh | 15 ++ modules/pam_userdb/pam_userdb.c | 302 +++++++++++++++++++++++++++++++++++++++ modules/pam_userdb/pam_userdb.h | 61 ++++++++ 8 files changed, 638 insertions(+) create mode 100644 modules/pam_userdb/.cvsignore create mode 100644 modules/pam_userdb/Makefile create mode 100644 modules/pam_userdb/README create mode 100644 modules/pam_userdb/conv.c create mode 100644 modules/pam_userdb/create.pl create mode 100755 modules/pam_userdb/libdbfound.sh create mode 100644 modules/pam_userdb/pam_userdb.c create mode 100644 modules/pam_userdb/pam_userdb.h (limited to 'modules/pam_userdb') diff --git a/modules/pam_userdb/.cvsignore b/modules/pam_userdb/.cvsignore new file mode 100644 index 00000000..380a834a --- /dev/null +++ b/modules/pam_userdb/.cvsignore @@ -0,0 +1 @@ +dynamic diff --git a/modules/pam_userdb/Makefile b/modules/pam_userdb/Makefile new file mode 100644 index 00000000..39226242 --- /dev/null +++ b/modules/pam_userdb/Makefile @@ -0,0 +1,81 @@ +# +# 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$ +# Created by Cristian Gafton + +WHICH_DB=$(shell ./libdbfound.sh) +ifeq ($(WHICH_DB),none) + +include ../dont_makefile + +else + +TITLE=pam_userdb + +LIBSRC = $(TITLE).c conv.c +LIBOBJ = $(TITLE).o conv.o +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +#LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +EXTRALS += -ldb +CFLAGS += $(WHICH_DB) + +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 + +####################### 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 DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) $(EXTRALS) +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 *~ *.so + +extraclean: clean + rm -f *.a *.o *.so *.bak dynamic/* static/* + +.c.o: + $(CC) $(CFLAGS) -c $< + +.PHONY: register + +test: + install -m 755 $(TITLE).so /tmp + +endif diff --git a/modules/pam_userdb/README b/modules/pam_userdb/README new file mode 100644 index 00000000..09d65edd --- /dev/null +++ b/modules/pam_userdb/README @@ -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 + + + +$Id$ diff --git a/modules/pam_userdb/conv.c b/modules/pam_userdb/conv.c new file mode 100644 index 00000000..0f13d03a --- /dev/null +++ b/modules/pam_userdb/conv.c @@ -0,0 +1,125 @@ +/* + * Conversation related functions + */ + +/* $Id */ +/* Copyright at the end of the file */ + +#define _BSD_SOURCE + +#include +#include + +#include +#include + +#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 , 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. + */ diff --git a/modules/pam_userdb/create.pl b/modules/pam_userdb/create.pl new file mode 100644 index 00000000..046b55f0 --- /dev/null +++ b/modules/pam_userdb/create.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# this program creates a database in ARGV[1] from pairs given on +# stdandard input +# +# $Id$ + +use DB_File; + +my $database = $ARGV[0]; +die "Use: check,pl \n" unless ($database); +print "Using database: $database\n"; + +my %lusers = (); + +tie %lusers, 'DB_File', $database, O_RDWR|O_CREAT, 0644, $DB_HASH ; +while () { + my ($user, $pass) = split; + + $lusers{$user} = $pass; +} +untie %lusers; + + diff --git a/modules/pam_userdb/libdbfound.sh b/modules/pam_userdb/libdbfound.sh new file mode 100755 index 00000000..d6a1723b --- /dev/null +++ b/modules/pam_userdb/libdbfound.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ -f "/usr/include/ndbm.h" ]; then + echo "-DUSE_NDBM_H" + exit 0 +fi + +list=`/bin/ls /lib/libdb.so.* 2> /dev/null` +if [ -n "$list" ]; then + echo "" + exit 0 +fi + +echo "none" +exit 0 diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c new file mode 100644 index 00000000..20ca5d10 --- /dev/null +++ b/modules/pam_userdb/pam_userdb.c @@ -0,0 +1,302 @@ +/* pam_userdb module */ + +/* + * $Id$ + * Written by Cristian Gafton 1996/09/10 + * See the end of the file for Copyright Information + */ + +#define _GNU_SOURCE +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pam_userdb.h" + +#ifdef USE_NDBM_H +# include +#else /* USE_NDBM_H */ +# define DB_DBM_HSEARCH 1 /* use the dbm interface */ +# include +#endif /* USE_NDBM_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_AUTH +#define PAM_SM_ACCOUNT + +#include + +/* 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_wheel_modstruct = { + MODULE_NAME, + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* + * Copyright (c) Cristian Gafton , 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. + */ diff --git a/modules/pam_userdb/pam_userdb.h b/modules/pam_userdb/pam_userdb.h new file mode 100644 index 00000000..911a7622 --- /dev/null +++ b/modules/pam_userdb/pam_userdb.h @@ -0,0 +1,61 @@ + +#ifndef _PAM_USERSDB_H +#define _PAM_USERSDB_H +/* $Id$ */ + +/* Header files */ +#include + +/* 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 , 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. + */ -- cgit v1.2.3