305 lines
8.2 KiB
C
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.
|
|
*/
|