summaryrefslogtreecommitdiff
path: root/modules/pam_userdb
diff options
context:
space:
mode:
authorThorsten Kukuk <kukuk@thkukuk.de>2004-09-28 13:48:45 +0000
committerThorsten Kukuk <kukuk@thkukuk.de>2004-09-28 13:48:45 +0000
commit6fb01537462a326a139f0c2d975145b26cd54bbe (patch)
tree5cc76f47e9687823164fa214fb801ce0f37a0766 /modules/pam_userdb
parent328d7328e5b4ea8d60164ce874bada2f4f58a201 (diff)
Relevant BUGIDs:
Purpose of commit: Commit summary: --------------- bugfix: * Merge patches from Red Hat (Bug 477000 and other - kukuk) * Fix pam_rhosts option parsing (Bug 922648 - kukuk)
Diffstat (limited to 'modules/pam_userdb')
-rw-r--r--modules/pam_userdb/README29
-rw-r--r--modules/pam_userdb/conv.c2
-rw-r--r--modules/pam_userdb/create.pl2
-rw-r--r--modules/pam_userdb/pam_userdb.c258
-rw-r--r--modules/pam_userdb/pam_userdb.h3
5 files changed, 226 insertions, 68 deletions
diff --git a/modules/pam_userdb/README b/modules/pam_userdb/README
index 9fa6519d..fc56cfa0 100644
--- a/modules/pam_userdb/README
+++ b/modules/pam_userdb/README
@@ -1,6 +1,7 @@
pam_userdb:
Look up users in a .db database and verify their password against
- what is contained in that database.
+ what is contained in that database. The database will have been
+ created using db_load.
RECOGNIZED ARGUMENTS:
debug write a message to syslog indicating success or
@@ -8,7 +9,9 @@ RECOGNIZED ARGUMENTS:
db=[path] use the [path] database for performing lookup. There
is no default; the module will return PAM_IGNORE if
- no database is provided.
+ no database is provided. Some versions of DB will
+ automatically append ".db" to whatever pathname you
+ supply here.
crypt=[mode] indicates whether encrypted or plaintext passwords
are stored in the database. If [mode] is "crypt",
@@ -24,8 +27,28 @@ RECOGNIZED ARGUMENTS:
dump dump all the entries in the database to the log (eek,
don't do this by default!)
+ use_authtok use the authentication token previously obtained by
+ another module that did the conversation with the
+ application. If this token can not be obtained then
+ the module will try to converse again. This option can
+ be used for stacking different modules that need to
+ deal with the authentication tokens.
+
+ unknown_ok do not return error when checking for a user that is
+ not in the database. This can be used to stack more
+ than one pam_userdb module that will check a
+ username/password pair in more than a database.
+
+ key_only the username and password are concatenated together
+ in the database hash as 'username-password' with a
+ random value. if the concatenation of the username and
+ password with a dash in the middle returns any result,
+ the user is valid. this is useful in cases where
+ the username may not be unique but the username and
+ password pair are.
+
MODULE SERVICES PROVIDED:
- auth _authetication and _setcred (blank)
+ auth _authentication and _setcred (blank)
EXAMPLE USE:
auth sufficient pam_userdb.so icase db=/tmp/dbtest.db
diff --git a/modules/pam_userdb/conv.c b/modules/pam_userdb/conv.c
index 0f13d03a..de5d12f2 100644
--- a/modules/pam_userdb/conv.c
+++ b/modules/pam_userdb/conv.c
@@ -5,8 +5,6 @@
/* $Id */
/* Copyright at the end of the file */
-#define _BSD_SOURCE
-
#include <stdlib.h>
#include <string.h>
diff --git a/modules/pam_userdb/create.pl b/modules/pam_userdb/create.pl
index 046b55f0..224204b7 100644
--- a/modules/pam_userdb/create.pl
+++ b/modules/pam_userdb/create.pl
@@ -7,7 +7,7 @@
use DB_File;
my $database = $ARGV[0];
-die "Use: check,pl <database>\n" unless ($database);
+die "Use: create.pl <database>\n" unless ($database);
print "Using database: $database\n";
my %lusers = ();
diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c
index 30f1e578..a0a5b8b5 100644
--- a/modules/pam_userdb/pam_userdb.c
+++ b/modules/pam_userdb/pam_userdb.c
@@ -1,5 +1,5 @@
/* pam_userdb module */
-
+
/*
* $Id$
* Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
@@ -8,6 +8,7 @@
#include <security/_pam_aconf.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -56,39 +57,53 @@ static void _pam_log(int err, const char *format, ...)
closelog();
}
-char * database = NULL;
-char * cryptmode = NULL;
-static int ctrl = 0;
-
-static int _pam_parse(int argc, const char **argv)
+static int
+_pam_parse (int argc, const char **argv,
+ char **database, char **cryptmode)
{
- /* 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 if (!strncasecmp(*argv,"crypt=", 6)) {
- cryptmode = strdup((*argv) + 6);
- if (cryptmode == NULL)
- _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"",
- *argv);
- } else {
- _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
- }
- }
+ int ctrl;
+
+ *database = NULL;
+ *cryptmode = NULL;
+
+ /* 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 (!strcasecmp(*argv, "unknown_ok"))
+ ctrl |= PAM_UNKNOWN_OK_ARG;
+ else if (!strcasecmp(*argv, "key_only"))
+ ctrl |= PAM_KEY_ONLY_ARG;
+ else if (!strncasecmp(*argv,"db=", 3))
+ {
+ *database = strdup((*argv) + 3);
+ if ((*database == NULL) || (strlen (*database) == 0))
+ _pam_log(LOG_ERR,
+ "pam_parse: could not parse argument \"%s\"",
+ *argv);
+ }
+ else if (!strncasecmp(*argv,"crypt=", 6))
+ {
+ *cryptmode = strdup((*argv) + 6);
+ if ((*cryptmode == NULL) || (strlen (*cryptmode) == 0))
+ _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;
+ return ctrl;
}
@@ -101,7 +116,9 @@ static int _pam_parse(int argc, const char **argv)
* -1 = Password incorrect
* -2 = System error
*/
-static int user_lookup(const char *user, const char *pass)
+static int
+user_lookup (const char *database, const char *cryptmode,
+ const char *user, const char *pass, int ctrl)
{
DBM *dbm;
datum key, data;
@@ -114,7 +131,8 @@ static int user_lookup(const char *user, const char *pass)
return -2;
}
- if (ctrl &PAM_DUMP_ARG) {
+ /* dump out the database contents for debugging */
+ if (ctrl & PAM_DUMP_ARG) {
_pam_log(LOG_INFO, "Database dump:");
for (key = dbm_firstkey(dbm); key.dptr != NULL;
key = dbm_nextkey(dbm)) {
@@ -122,14 +140,19 @@ static int user_lookup(const char *user, const char *pass)
_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 */
+ }
+ /* 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 (ctrl & PAM_KEY_ONLY_ARG) {
+ key.dptr = malloc(strlen(user) + 1 + strlen(pass) + 1);
+ sprintf(key.dptr, "%s-%s", user, pass);
+ key.dsize = strlen(key.dptr);
+ } else {
+ key.dptr = x_strdup(user);
+ key.dsize = strlen(user);
+ }
if (key.dptr) {
data = dbm_fetch(dbm, key);
@@ -144,7 +167,13 @@ static int user_lookup(const char *user, const char *pass)
if (data.dptr != NULL) {
int compare = 0;
-
+
+ if (ctrl & PAM_KEY_ONLY_ARG)
+ {
+ dbm_close (dbm);
+ return 0; /* found it, data contents don't matter */
+ }
+
if (strncasecmp(cryptmode, "crypt", 5) == 0) {
/* crypt(3) password storage */
@@ -166,7 +195,7 @@ static int user_lookup(const char *user, const char *pass)
compare = strncasecmp (data.dptr, cryptpw, data.dsize);
} else {
compare = -2;
- if (ctrl & PAM_DEBUG_ARG) {
+ if (ctrl & PAM_DEBUG_ARG) {
_pam_log(LOG_INFO, "crypt() returned NULL");
}
};
@@ -174,20 +203,20 @@ static int user_lookup(const char *user, const char *pass)
};
} else {
-
+
/* Unknown password encryption method -
* default to plaintext password storage
*/
if (strlen(pass) != data.dsize) {
- compare = 1;
+ compare = 1; /* wrong password len -> wrong password */
} else if (ctrl & PAM_ICASE_ARG) {
compare = strncasecmp(data.dptr, pass, data.dsize);
} else {
compare = strncmp(data.dptr, pass, data.dsize);
}
- if (strncasecmp(cryptmode, "none", 4) && ctrl & PAM_DEBUG_ARG) {
+ if (strncasecmp(cryptmode, "none", 4) && ctrl & PAM_DEBUG_ARG) {
_pam_log(LOG_INFO, "invalid value for crypt parameter: %s",
cryptmode);
_pam_log(LOG_INFO, "defaulting to plaintext password mode");
@@ -201,13 +230,58 @@ static int user_lookup(const char *user, const char *pass)
else
return -1; /* wrong */
} else {
- if (ctrl & PAM_DEBUG_ARG) {
+ int saw_user = 0;
+
+ 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 */
+
+ if ((ctrl & PAM_KEY_ONLY_ARG) == 0) {
+ dbm_close(dbm);
+ return 1; /* not key_only, so no entry => no entry for the user */
+ }
+
+ /* now handle the key_only case */
+ for (key = dbm_firstkey(dbm);
+ key.dptr != NULL;
+ key = dbm_nextkey(dbm)) {
+ int compare;
+ /* first compare the user portion (case sensitive) */
+ compare = strncmp(key.dptr, user, strlen(user));
+ if (compare == 0) {
+ /* assume failure */
+ compare = -1;
+ /* if we have the divider where we expect it to be... */
+ if (key.dptr[strlen(user)] == '-') {
+ saw_user = 1;
+ if (key.dsize == strlen(user) + 1 + strlen(pass)) {
+ if (ctrl & PAM_ICASE_ARG) {
+ /* compare the password portion (case insensitive)*/
+ compare = strncasecmp(key.dptr + strlen(user) + 1,
+ pass,
+ strlen(pass));
+ } else {
+ /* compare the password portion (case sensitive) */
+ compare = strncmp(key.dptr + strlen(user) + 1,
+ pass,
+ strlen(pass));
+ }
+ }
+ }
+ if (compare == 0) {
+ dbm_close(dbm);
+ return 0; /* match */
+ }
+ }
+ }
+ dbm_close(dbm);
+ if (saw_user)
+ return -1; /* saw the user, but password mismatch */
+ else
+ return 1; /* not found */
}
/* NOT REACHED */
@@ -222,10 +296,17 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
{
const char *username;
const char *password;
- int retval = PAM_AUTH_ERR;
-
+ char *database = NULL;
+ char *cryptmode = NULL;
+ int retval = PAM_AUTH_ERR, ctrl;
+
/* parse arguments */
- ctrl = _pam_parse(argc, argv);
+ ctrl = _pam_parse(argc, argv, &database, &cryptmode);
+ if ((database == NULL) || (strlen(database) == 0)) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"can not get the database name");
+ return PAM_SERVICE_ERR;
+ }
/* Get the username */
retval = pam_get_user(pamh, &username, NULL);
@@ -234,32 +315,47 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
_pam_log(LOG_DEBUG,"can not get the username");
return PAM_SERVICE_ERR;
}
-
- /* Converse just to be sure we have the password */
+
+ /* Converse just to be sure we have a password */
retval = conversation(pamh);
if (retval != PAM_SUCCESS) {
_pam_log(LOG_ERR, "could not obtain password for `%s'",
username);
- return -2;
+ return PAM_CONV_ERR;
+ }
+
+ /* Check if we got a password. The docs say that if we didn't have one,
+ * and use_authtok was specified as an argument, that we converse with the
+ * user anyway, so check for one and handle a failure for that case. If
+ * use_authtok wasn't specified, then we've already asked once and needn't
+ * do so again. */
+ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
+ if ((retval != PAM_SUCCESS) && ((ctrl & PAM_USE_AUTHTOK_ARG) != 0)) {
+ retval = conversation(pamh);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "could not obtain password for `%s'",
+ username);
+ return PAM_CONV_ERR;
+ }
}
-
+
/* 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");
+ _pam_log(LOG_ERR, "Could not retrieve 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);
+ retval = user_lookup(database, cryptmode, username, password, ctrl);
switch (retval) {
case -2:
/* some sort of system error. The log was already printed */
- return PAM_SERVICE_ERR;
+ return PAM_SERVICE_ERR;
case -1:
/* incorrect password */
_pam_log(LOG_WARNING,
@@ -296,9 +392,47 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags,
}
PAM_EXTERN
-int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
- int argc, const char **argv)
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
+ const char *username;
+ char *database = NULL;
+ char *cryptmode = NULL;
+ int retval = PAM_AUTH_ERR, ctrl;
+
+ /* parse arguments */
+ ctrl = _pam_parse(argc, argv, &database, &cryptmode);
+
+ /* 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;
+ }
+
+ /* Now use the username to look up password in the database file */
+ retval = user_lookup(database, cryptmode, username, "", ctrl);
+ switch (retval) {
+ case -2:
+ /* some sort of system error. The log was already printed */
+ return PAM_SERVICE_ERR;
+ case -1:
+ /* incorrect password, but we don't care */
+ /* FALL THROUGH */
+ case 0:
+ /* authentication succeeded. dumbest password ever. */
+ return PAM_SUCCESS;
+ case 1:
+ /* the user does not exist in the database */
+ return PAM_USER_UNKNOWN;
+ 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;
+ }
+
return PAM_SUCCESS;
}
@@ -311,7 +445,7 @@ struct pam_module _pam_userdb_modstruct = {
"pam_userdb",
pam_sm_authenticate,
pam_sm_setcred,
- NULL,
+ pam_sm_acct_mgmt,
NULL,
NULL,
NULL,
diff --git a/modules/pam_userdb/pam_userdb.h b/modules/pam_userdb/pam_userdb.h
index 911a7622..a371fa9f 100644
--- a/modules/pam_userdb/pam_userdb.h
+++ b/modules/pam_userdb/pam_userdb.h
@@ -10,6 +10,9 @@
#define PAM_DEBUG_ARG 0x0001
#define PAM_ICASE_ARG 0x0002
#define PAM_DUMP_ARG 0x0004
+#define PAM_USE_AUTHTOK_ARG 0x0008
+#define PAM_UNKNOWN_OK_ARG 0x0010
+#define PAM_KEY_ONLY_ARG 0x0020
/* Useful macros */
#define x_strdup(s) ( (s) ? strdup(s):NULL )