/* pam_userdb module */ /* * $Id$ * Written by Cristian Gafton 1996/09/10 * See the end of the file for Copyright Information */ #include #include #include #include #include #include #include #include #include #include #include "pam_userdb.h" #ifdef HAVE_NDBM_H # include #else # ifdef HAVE_DB_H # define DB_DBM_HSEARCH 1 /* use the dbm interface */ # include # else # error "failed to find a libdb or equivalent" # endif #endif /* * here, we make a definition for the externally accessible function * in this file (this definition is required for static a module * but strongly encouraged generally) it is used to instruct the * modules include file to define the function prototypes. */ #define PAM_SM_AUTH #define PAM_SM_ACCOUNT #include /* some syslogging */ static void _pam_log(int err, const char *format, ...) { va_list args; va_start(args, format); openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); vsyslog(err, format, args); va_end(args); closelog(); } char * database = NULL; static int ctrl = 0; static int _pam_parse(int argc, const char **argv) { /* step through arguments */ for (ctrl = 0; argc-- > 0; ++argv) { /* generic options */ if (!strcmp(*argv,"debug")) ctrl |= PAM_DEBUG_ARG; else if (!strcasecmp(*argv, "icase")) ctrl |= PAM_ICASE_ARG; else if (!strcasecmp(*argv, "dump")) ctrl |= PAM_DUMP_ARG; else if (!strncasecmp(*argv,"db=", 3)) { database = strdup((*argv) + 3); if (database == NULL) _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"", *argv); } else { _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); } } return ctrl; } /* * Looks up an user name in a database and checks the password * * return values: * 1 = User not found * 0 = OK * -1 = Password incorrect * -2 = System error */ static int user_lookup(const char *user, const char *pass) { DBM *dbm; datum key, data; /* Open the DB file. */ dbm = dbm_open(database, O_RDONLY, 0644); if (dbm == NULL) { _pam_log(LOG_ERR, "user_lookup: could not open database `%s'", database); return -2; } if (ctrl &PAM_DUMP_ARG) { _pam_log(LOG_INFO, "Database dump:"); for (key = dbm_firstkey(dbm); key.dptr != NULL; key = dbm_nextkey(dbm)) { data = dbm_fetch(dbm, key); _pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'", key.dsize, key.dptr, data.dsize, data.dptr); } } /* do some more init work */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.dptr = x_strdup(user); key.dsize = strlen(user); user = NULL; if (key.dptr) { data = dbm_fetch(dbm, key); memset(key.dptr, 0, key.dsize); free(key.dptr); } if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_INFO, "password in database is [%p]`%s', len is %d", data.dptr, (char *) data.dptr, data.dsize); } if (data.dptr != NULL) { int compare = 0; /* bingo, got it */ if (ctrl & PAM_ICASE_ARG) compare = strncasecmp(pass, data.dptr, data.dsize); else compare = strncmp(pass, data.dptr, data.dsize); dbm_close(dbm); if (compare == 0) return 0; /* match */ else return -1; /* wrong */ } else { if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_INFO, "error returned by dbm_fetch: %s", strerror(errno)); } dbm_close(dbm); /* probably we should check dbm_error() here */ return 1; /* not found */ } /* NOT REACHED */ return -2; } /* --- authentication management functions (only) --- */ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *username; const char *password; int retval = PAM_AUTH_ERR; /* parse arguments */ ctrl = _pam_parse(argc, argv); /* Get the username */ retval = pam_get_user(pamh, &username, NULL); if ((retval != PAM_SUCCESS) || (!username)) { if (ctrl & PAM_DEBUG_ARG) _pam_log(LOG_DEBUG,"can not get the username"); return PAM_SERVICE_ERR; } /* Converse just to be sure we have the password */ retval = conversation(pamh); if (retval != PAM_SUCCESS) { _pam_log(LOG_ERR, "could not obtain password for `%s'", username); return -2; } /* Get the password */ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); if (retval != PAM_SUCCESS) { _pam_log(LOG_ERR, "Could not retrive user's password"); return -2; } if (ctrl & PAM_DEBUG_ARG) _pam_log(LOG_INFO, "Verify user `%s' with password `%s'", username, password); /* Now use the username to look up password in the database file */ retval = user_lookup(username, password); switch (retval) { case -2: /* some sort of system error. The log was already printed */ return PAM_SERVICE_ERR; case -1: /* incorrect password */ _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username); return PAM_AUTH_ERR; case 1: /* the user does not exist in the database */ if (ctrl & PAM_DEBUG_ARG) _pam_log(LOG_NOTICE, "user `%s' not found in the database", username); return PAM_USER_UNKNOWN; case 0: /* Otherwise, the authentication looked good */ _pam_log(LOG_NOTICE, "user '%s' granted acces", username); return PAM_SUCCESS; default: /* we don't know anything about this return value */ _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'", retval, username); return PAM_SERVICE_ERR; } /* should not be reached */ return PAM_IGNORE; } PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_SUCCESS; } PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_SUCCESS; } #ifdef PAM_STATIC /* static module data */ struct pam_module _pam_userdb_modstruct = { "pam_userdb", pam_sm_authenticate, pam_sm_setcred, NULL, NULL, NULL, NULL, }; #endif /* * Copyright (c) Cristian Gafton , 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. */