freebsd-dev/contrib/libpam/modules/pam_userdb/pam_userdb.c
2001-05-03 09:36:08 +00:00

305 lines
8.2 KiB
C

/* pam_userdb module */
/*
* $Id: pam_userdb.c,v 1.4 2000/12/04 15:02:16 baggins Exp $
* Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
* See the end of the file for Copyright Information
*/
#include <security/_pam_aconf.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "pam_userdb.h"
#ifdef HAVE_NDBM_H
# include <ndbm.h>
#else
# ifdef HAVE_DB_H
# define DB_DBM_HSEARCH 1 /* use the dbm interface */
# include <db.h>
# 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 <security/pam_modules.h>
/* 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 <gafton@redhat.com>, 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.
*/