summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorThorsten Kukuk <kukuk@thkukuk.de>2004-10-06 13:42:36 +0000
committerThorsten Kukuk <kukuk@thkukuk.de>2004-10-06 13:42:36 +0000
commit3f42e813b61a2492f5b58d514aacf459f0799cdf (patch)
tree7d45281025891630178becc1d3b222e993832f74 /modules
parentb651aa8d81ecf3072cc52dcd0192905b686d17b1 (diff)
Relevant BUGIDs:
Purpose of commit: Commit summary: --------------- bugfix: Last part of fixes from Red Hat
Diffstat (limited to 'modules')
-rw-r--r--modules/pam_limits/pam_limits.c4
-rw-r--r--modules/pam_unix/pam_unix_acct.c5
-rw-r--r--modules/pam_unix/pam_unix_passwd.c50
-rw-r--r--modules/pam_unix/support.c194
-rw-r--r--modules/pam_unix/support.h8
-rw-r--r--modules/pam_unix/unix_chkpwd.c37
6 files changed, 266 insertions, 32 deletions
diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c
index 4354d3e1..66eae8e9 100644
--- a/modules/pam_limits/pam_limits.c
+++ b/modules/pam_limits/pam_limits.c
@@ -207,12 +207,12 @@ check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl,
continue;
}
}
- if (++count > limit) {
+ if (++count >= limit) {
break;
}
}
endutent();
- if (count > limit) {
+ if (count >= limit) {
if (name) {
_pam_log(LOG_WARNING, "Too many logins (max %d) for %s",
limit, name);
diff --git a/modules/pam_unix/pam_unix_acct.c b/modules/pam_unix/pam_unix_acct.c
index f87b13b1..2cd26792 100644
--- a/modules/pam_unix/pam_unix_acct.c
+++ b/modules/pam_unix/pam_unix_acct.c
@@ -123,11 +123,10 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
setreuid( -1, save_euid );
}
- } else if (!strcmp( pwent->pw_passwd, "x" )) {
+ } else if (_unix_shadowed (pwent))
spent = _pammodutil_getspnam (pamh, uname);
- } else {
+ else
return PAM_SUCCESS;
- }
if (!spent)
if (on(UNIX_BROKEN_SHADOW,ctrl))
diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c
index 91625c61..4e90b764 100644
--- a/modules/pam_unix/pam_unix_passwd.c
+++ b/modules/pam_unix/pam_unix_passwd.c
@@ -444,7 +444,7 @@ static int _update_passwd(pam_handle_t *pamh,
}
}
-static int _update_shadow(const char *forwho, char *towhat)
+static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
{
struct spwd *spwdent = NULL, *stmpent = NULL;
struct stat st;
@@ -516,6 +516,7 @@ static int _update_shadow(const char *forwho, char *towhat)
if (!err) {
rename(SH_TMPFILE, "/etc/shadow");
+ _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
return PAM_SUCCESS;
} else {
unlink(SH_TMPFILE);
@@ -535,7 +536,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
if (pwd == NULL)
return PAM_AUTHTOK_ERR;
- if (on(UNIX_NIS, ctrl)) {
+ if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
struct timeval timeout;
struct yppasswd yppwd;
CLIENT *clnt;
@@ -619,13 +620,18 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
}
#endif /* def USE_LCKPWDF */
- if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) {
- retval = _update_shadow(forwho, towhat);
+ if (_unix_comesfromsource (pamh, forwho, 1, 0))
+ {
+ if (on(UNIX_SHADOW, ctrl) || _unix_shadowed (pwd))
+ {
+ retval = _update_shadow (pamh, forwho, towhat);
if (retval == PAM_SUCCESS)
- retval = _update_passwd(pamh, forwho, "x");
- } else {
- retval = _update_passwd(pamh, forwho, towhat);
- }
+ if (!_unix_shadowed (pwd))
+ retval = _update_passwd (pamh, forwho, "x");
+ }
+ else
+ retval = _update_passwd (pamh, forwho, towhat);
+ }
#ifdef USE_LCKPWDF
ulckpwdf();
@@ -646,7 +652,7 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl)
if (pwd == NULL)
return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */
- if (strcmp(pwd->pw_passwd, "x") == 0) {
+ if (_unix_shadowed(pwd)) {
/* ...and shadow password file entry for this user, if shadowing
is enabled */
setspent();
@@ -738,7 +744,7 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
#else
if (strlen(pass_new) < 6)
remark = "You must choose a longer password";
- D(("lenth check [%s]", remark));
+ D(("length check [%s]", remark));
#endif
if (on(UNIX_REMEMBER_PASSWD, ctrl))
if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS)
@@ -796,6 +802,30 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
D(("Got username of %s", user));
/*
+ * Before we do anything else, check to make sure that the user's
+ * info is in one of the databases we can modify from this module,
+ * which currently is 'files' and 'nis'. We have to do this because
+ * getpwnam() doesn't tell you *where* the information it gives you
+ * came from, nor should it. That's our job.
+ */
+ if (_unix_comesfromsource(pamh, user, 1, 1) == 0) {
+ _log_err(LOG_DEBUG, pamh,
+ "user \"%s\" does not exist in /etc/passwd or NIS",
+ user);
+ return PAM_USER_UNKNOWN;
+ } else {
+ struct passwd *pwd;
+ _unix_getpwnam(pamh, user, 1, 1, &pwd);
+ if (!_unix_shadowed(pwd) &&
+ (strchr(pwd->pw_passwd, '*') != NULL)) {
+ _log_err(LOG_DEBUG, pamh,
+ "user \"%s\" does not have modifiable password",
+ user);
+ return PAM_USER_UNKNOWN;
+ }
+ }
+
+ /*
* This is not an AUTH module!
*/
if (on(UNIX__NONULL, ctrl))
diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c
index 05c51fed..5b23b8e9 100644
--- a/modules/pam_unix/support.c
+++ b/modules/pam_unix/support.c
@@ -9,6 +9,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
+#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <pwd.h>
@@ -17,6 +18,8 @@
#include <utmp.h>
#include <errno.h>
#include <signal.h>
+#include <ctype.h>
+#include <rpcsvc/ypclnt.h>
#include <security/_pam_macros.h>
#include <security/pam_modules.h>
@@ -135,10 +138,6 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc,
D(("PRELIM_CHECK"));
set(UNIX__PRELIM, ctrl);
}
- if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
- D(("DISALLOW_NULL_AUTHTOK"));
- set(UNIX__NONULL, ctrl);
- }
if (flags & PAM_SILENT) {
D(("SILENT"));
set(UNIX__QUIET, ctrl);
@@ -178,6 +177,11 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc,
++argv; /* step to next argument */
}
+ if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
+ D(("DISALLOW_NULL_AUTHTOK"));
+ set(UNIX__NONULL, ctrl);
+ }
+
/* auditing is a more sensitive version of debug */
if (on(UNIX_AUDIT, ctrl)) {
@@ -276,6 +280,165 @@ static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err)
}
/*
+ * _unix_getpwnam() searches only /etc/passwd and NIS to find user information
+ */
+static void _unix_cleanup(pam_handle_t *pamh, void *data, int error_status)
+{
+ free(data);
+}
+
+int _unix_getpwnam(pam_handle_t *pamh, const char *name,
+ int files, int nis, struct passwd **ret)
+{
+ FILE *passwd;
+ char buf[16384];
+ int matched = 0, buflen;
+ char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (!matched && files) {
+ int userlen = strlen(name);
+ passwd = fopen("/etc/passwd", "r");
+ if (passwd != NULL) {
+ while (fgets(buf, sizeof(buf), passwd) != NULL) {
+ if ((buf[userlen] == ':') &&
+ (strncmp(name, buf, userlen) == 0)) {
+ p = buf + strlen(buf) - 1;
+ while (isspace(*p) && (p >= buf)) {
+ *p-- = '\0';
+ }
+ matched = 1;
+ break;
+ }
+ }
+ fclose(passwd);
+ }
+ }
+
+ if (!matched && nis) {
+ char *userinfo = NULL, *domain = NULL;
+ int len = 0, i;
+ len = yp_get_default_domain(&domain);
+ if (len == YPERR_SUCCESS) {
+ len = yp_bind(domain);
+ }
+ if (len == YPERR_SUCCESS) {
+ i = yp_match(domain, "passwd.byname", name,
+ strlen(name), &userinfo, &len);
+ yp_unbind(domain);
+ if ((i == YPERR_SUCCESS) && (len < sizeof(buf))) {
+ strncpy(buf, userinfo, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ matched = 1;
+ }
+ }
+ }
+
+ if (matched && (ret != NULL)) {
+ *ret = NULL;
+
+ slogin = buf;
+
+ spasswd = strchr(slogin, ':');
+ if (spasswd == NULL) {
+ return matched;
+ }
+ *spasswd++ = '\0';
+
+ suid = strchr(spasswd, ':');
+ if (suid == NULL) {
+ return matched;
+ }
+ *suid++ = '\0';
+
+ sgid = strchr(suid, ':');
+ if (sgid == NULL) {
+ return matched;
+ }
+ *sgid++ = '\0';
+
+ sgecos = strchr(sgid, ':');
+ if (sgecos == NULL) {
+ return matched;
+ }
+ *sgecos++ = '\0';
+
+ shome = strchr(sgecos, ':');
+ if (shome == NULL) {
+ return matched;
+ }
+ *shome++ = '\0';
+
+ sshell = strchr(shome, ':');
+ if (sshell == NULL) {
+ return matched;
+ }
+ *sshell++ = '\0';
+
+ buflen = sizeof(struct passwd) +
+ strlen(slogin) + 1 +
+ strlen(spasswd) + 1 +
+ strlen(suid) + 1 +
+ strlen(sgid) + 1 +
+ strlen(sgecos) + 1 +
+ strlen(shome) + 1 +
+ strlen(sshell) + 1;
+ *ret = malloc(buflen);
+ if (*ret == NULL) {
+ return matched;
+ }
+ memset(*ret, '\0', buflen);
+
+ (*ret)->pw_uid = strtol(suid, &p, 0);
+ if ((strlen(sgid) == 0) || (*p != '\0')) {
+ free(*ret);
+ *ret = NULL;
+ return matched;
+ }
+
+ (*ret)->pw_gid = strtol(sgid, &p, 0);
+ if ((strlen(sgid) == 0) || (*p != '\0')) {
+ free(*ret);
+ *ret = NULL;
+ return matched;
+ }
+
+ p = ((char*)(*ret)) + sizeof(struct passwd);
+ (*ret)->pw_name = strcpy(p, slogin);
+ p += strlen(p) + 1;
+ (*ret)->pw_passwd = strcpy(p, spasswd);
+ p += strlen(p) + 1;
+ (*ret)->pw_gecos = strcpy(p, sgecos);
+ p += strlen(p) + 1;
+ (*ret)->pw_dir = strcpy(p, shome);
+ p += strlen(p) + 1;
+ (*ret)->pw_shell = strcpy(p, sshell);
+
+ snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
+
+ if (pam_set_data(pamh, buf,
+ *ret, _unix_cleanup) != PAM_SUCCESS) {
+ free(*ret);
+ *ret = NULL;
+ }
+ }
+
+ return matched;
+}
+
+/*
+ * _unix_comsefromsource() is a quick check to see if information about a given
+ * user comes from a particular source (just files and nis for now)
+ *
+ */
+int _unix_comesfromsource(pam_handle_t *pamh,
+ const char *name, int files, int nis)
+{
+ return _unix_getpwnam(pamh, name, files, nis, NULL);
+}
+
+/*
* _unix_blankpasswd() is a quick check for a blank password
*
* returns TRUE if user does not have a password
@@ -331,10 +494,10 @@ _unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name)
setreuid( save_uid, save_euid );
else {
if (setreuid( -1, 0 ) == -1)
- setreuid( save_uid, -1 );
+ setreuid( save_uid, -1 );
setreuid( -1, save_euid );
}
- } else if (strcmp(pwd->pw_passwd, "x") == 0) {
+ } else if (_unix_shadowed(pwd)) {
/*
* ...and shadow password file entry for this user,
* if shadowing is enabled
@@ -501,7 +664,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
setreuid( save_uid, -1 );
setreuid( -1, save_euid );
}
- } else if (strcmp(pwd->pw_passwd, "x") == 0) {
+ } else if (_unix_shadowed(pwd)) {
/*
* ...and shadow password file entry for this user,
* if shadowing is enabled
@@ -523,7 +686,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
}
retval = PAM_SUCCESS;
- if (pwd == NULL || salt == NULL || strlen(salt) == 1) {
+ if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) {
if (geteuid()) {
/* we are not root perhaps this is the reason? Run helper */
D(("running helper binary"));
@@ -850,6 +1013,21 @@ int _unix_read_password(pam_handle_t * pamh
return PAM_SUCCESS;
}
+int _unix_shadowed(const struct passwd *pwd)
+{
+ if (pwd != NULL) {
+ if (strcmp(pwd->pw_passwd, "x") == 0) {
+ return 1;
+ }
+ if ((pwd->pw_passwd[0] == '#') &&
+ (pwd->pw_passwd[1] == '#') &&
+ (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
/* ****************************************************************** *
* Copyright (c) Jan RÍkorajski 1999.
* Copyright (c) Andrew G. Morgan 1996-8.
diff --git a/modules/pam_unix/support.h b/modules/pam_unix/support.h
index 7219cd99..b2aa4b40 100644
--- a/modules/pam_unix/support.h
+++ b/modules/pam_unix/support.h
@@ -5,6 +5,7 @@
#ifndef _PAM_UNIX_SUPPORT_H
#define _PAM_UNIX_SUPPORT_H
+#include <pwd.h>
/*
* here is the string to inform the user that the new passwords they
@@ -133,6 +134,11 @@ extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl
,int type, const char *text);
extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int argc,
const char **argv);
+extern int _unix_getpwnam (pam_handle_t *pamh,
+ const char *name, int files, int nis,
+ struct passwd **ret);
+extern int _unix_comesfromsource (pam_handle_t *pamh,
+ const char *name, int files, int nis);
extern int _unix_blankpasswd(pam_handle_t *pamh,unsigned int ctrl,
const char *name);
extern int _unix_verify_password(pam_handle_t * pamh, const char *name
@@ -144,6 +150,6 @@ extern int _unix_read_password(pam_handle_t * pamh
,const char *prompt2
,const char *data_name
,const char **pass);
+extern int _unix_shadowed(const struct passwd *pwd);
#endif /* _PAM_UNIX_SUPPORT_H */
-
diff --git a/modules/pam_unix/unix_chkpwd.c b/modules/pam_unix/unix_chkpwd.c
index dd07960c..e65728d8 100644
--- a/modules/pam_unix/unix_chkpwd.c
+++ b/modules/pam_unix/unix_chkpwd.c
@@ -57,6 +57,24 @@ static void _log_err(int err, const char *format,...)
closelog();
}
+static int _unix_shadowed(const struct passwd *pwd)
+{
+ char hashpass[1024];
+ if (pwd != NULL) {
+ if (strcmp(pwd->pw_passwd, "x") == 0) {
+ return 1;
+ }
+ if (strlen(pwd->pw_name) < sizeof(hashpass) - 2) {
+ strcpy(hashpass, "##");
+ strcpy(hashpass + 2, pwd->pw_name);
+ if (strcmp(pwd->pw_passwd, hashpass) == 0) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
static void su_sighandler(int sig)
{
if (sig > 0) {
@@ -87,7 +105,7 @@ static void setup_signals(void)
(void) sigaction(SIGQUIT, &action, NULL);
}
-static int _unix_verify_password(const char *name, const char *p, int opt)
+static int _unix_verify_password(const char *name, const char *p, int nullok)
{
struct passwd *pwd = NULL;
struct spwd *spwdent = NULL;
@@ -101,7 +119,7 @@ static int _unix_verify_password(const char *name, const char *p, int opt)
pwd = getpwnam(name); /* Get password file entry... */
endpwent();
if (pwd != NULL) {
- if (strcmp(pwd->pw_passwd, "x") == 0) {
+ if (_unix_shadowed(pwd)) {
/*
* ...and shadow password file entry for this user,
* if shadowing is enabled
@@ -136,7 +154,10 @@ static int _unix_verify_password(const char *name, const char *p, int opt)
salt_len = strlen(salt);
if (salt_len == 0) {
- return (opt == 0) ? UNIX_FAILED : UNIX_PASSED;
+ return (nullok == 0) ? UNIX_FAILED : UNIX_PASSED;
+ }
+ if (p == NULL) {
+ return UNIX_FAILED;
}
/* the moment of truth -- do we agree with the password? */
@@ -202,7 +223,7 @@ int main(int argc, char *argv[])
{
char pass[MAXPASS + 1];
char option[8];
- int npass, opt;
+ int npass, nullok;
int force_failure = 0;
int retval = UNIX_FAILED;
char *user;
@@ -255,9 +276,9 @@ int main(int argc, char *argv[])
} else {
option[7] = '\0';
if (strncmp(option, "nullok", 8) == 0)
- opt = 1;
+ nullok = 1;
else
- opt = 0;
+ nullok = 0;
}
/* read the password from stdin (a pipe from the pam_unix module) */
@@ -276,13 +297,13 @@ int main(int argc, char *argv[])
if (npass == 0) {
/* the password is NULL */
- retval = _unix_verify_password(user, NULL, opt);
+ retval = _unix_verify_password(user, NULL, nullok);
} else {
/* does pass agree with the official one? */
pass[npass] = '\0'; /* NUL terminate */
- retval = _unix_verify_password(user, pass, opt);
+ retval = _unix_verify_password(user, pass, nullok);
}
}