summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--_pam_aconf.h.in4
-rwxr-xr-xconfigure25
-rw-r--r--configure.in16
-rw-r--r--libpam/pam_handlers.c39
-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
11 files changed, 343 insertions, 40 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 82b9ab91..e72e4db9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -119,6 +119,7 @@ BerliOS Bugs are marked with (BerliOS #XXXX).
* Add patches to make PAM modules reentrant (Bug 440107 - kukuk)
* Merge patches from Red Hat (Bug 477000 and other - kukuk)
* Fix pam_rhosts option parsing (Bug 922648 - kukuk)
+* Add $ISA support in config files (from Red Hat - kukuk)
0.77: Mon Sep 23 10:25:42 PDT 2002
diff --git a/_pam_aconf.h.in b/_pam_aconf.h.in
index 1b1cde95..68a39120 100644
--- a/_pam_aconf.h.in
+++ b/_pam_aconf.h.in
@@ -97,4 +97,8 @@
# include <security/pam_malloc.h>
#endif /* MEMORY_DEBUG */
+/* the path, relative to SECUREDIR, where PAMs specific to this architecture
+ * can be found */
+#undef _PAM_ISA
+
#endif /* PAM_ACONF_H */
diff --git a/configure b/configure
index 27756779..32aad3be 100755
--- a/configure
+++ b/configure
@@ -846,6 +846,7 @@ Optional Features:
--enable-libdebug specify you are building debugging libraries
--enable-fakeroot=<path to packaging directory>
--enable-securedir=<path to location of PAMs> default \$libdir/security
+ --enable-isadir=<path to arch-specific module files> default ../../\`basename \$libdir\`/security
--enable-sconfigdir=<path to module conf files> default \$sysconfdir/security
--enable-suplementedir=<path to module helper binaries> default \$sbindir
--enable-includedir=<path to include location> - where to put <security>
@@ -2795,6 +2796,22 @@ else
fi;
+# Check whether --enable-isadir or --disable-isadir was given.
+if test "${enable_isadir+set}" = set; then
+ enableval="$enable_isadir"
+ ISA=$enableval
+else
+ ISA=../../`basename $libdir`/security
+fi;
+unset mylibdirbase
+
+cat >>confdefs.h <<_ACEOF
+#define _PAM_ISA "$ISA"
+_ACEOF
+
+echo "$as_me:$LINENO: result: Defining \$ISA to \\"$ISA\\"." >&5
+echo "${ECHO_T}Defining \$ISA to \\"$ISA\\"." >&6
+
# Check whether --enable-sconfigdir or --disable-sconfigdir was given.
if test "${enable_sconfigdir+set}" = set; then
enableval="$enable_sconfigdir"
@@ -4410,13 +4427,17 @@ else
fi
+
+if test $HAVE_LIBNSL = yes ; then
+ pwdblibs="$pwdblibs -lnsl"
+fi
echo "$as_me:$LINENO: checking for pwdb_db_name in -lpwdb" >&5
echo $ECHO_N "checking for pwdb_db_name in -lpwdb... $ECHO_C" >&6
if test "${ac_cv_lib_pwdb_pwdb_db_name+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpwdb $LIBS"
+LIBS="-lpwdb $pwdblibs $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
@@ -4484,6 +4505,8 @@ else
fi
+unset pwdblibs
+
echo "$as_me:$LINENO: checking for yywrap in -lfl" >&5
echo $ECHO_N "checking for yywrap in -lfl... $ECHO_C" >&6
if test "${ac_cv_lib_fl_yywrap+set}" = set; then
diff --git a/configure.in b/configure.in
index d673e3af..ce9c310d 100644
--- a/configure.in
+++ b/configure.in
@@ -87,6 +87,14 @@ AC_ARG_ENABLE(securedir,
SECUREDIR=$enableval, SECUREDIR=$libdir/security)
AC_SUBST(SECUREDIR)
+AC_ARG_ENABLE(isadir,
+[ --enable-isadir=<path to arch-specific module files> [default ../../\`basename \$libdir\`/security]],
+ISA=$enableval,
+ISA=../../`basename $libdir`/security)
+unset mylibdirbase
+AC_DEFINE_UNQUOTED(_PAM_ISA,"$ISA",[Define to the path, relative to SECUREDIR, where PAMs specific to this architecture can be found.])
+AC_MSG_RESULT([Defining \$ISA to \"$ISA\".])
+
AC_ARG_ENABLE(sconfigdir,
[ --enable-sconfigdir=<path to module conf files> [default \$sysconfdir/security]],
SCONFIGDIR=$enableval, SCONFIGDIR=$sysconfdir/security)
@@ -212,9 +220,15 @@ AC_SUBST(HAVE_LIBFL)
AC_CHECK_LIB(nsl, yp_maplist, HAVE_LIBNSL=yes ; AC_DEFINE(HAVE_LIBNSL),
HAVE_LIBNSL=no)
AC_SUBST(HAVE_LIBNSL)
+
+if test $HAVE_LIBNSL = yes ; then
+ pwdblibs="$pwdblibs -lnsl"
+fi
AC_CHECK_LIB(pwdb, pwdb_db_name, HAVE_LIBPWDB=yes ; AC_DEFINE(HAVE_LIBPWDB),
- HAVE_LIBPWDB=no)
+ HAVE_LIBPWDB=no,$pwdblibs)
AC_SUBST(HAVE_LIBPWDB)
+unset pwdblibs
+
AC_CHECK_LIB(fl, yywrap, HAVE_LIBFLEX=yes ; AC_DEFINE(HAVE_LIBFLEX),
HAVE_LIBFLEX=no)
AC_SUBST(HAVE_LIBFLEX)
diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
index 90c0968a..75519551 100644
--- a/libpam/pam_handlers.c
+++ b/libpam/pam_handlers.c
@@ -34,6 +34,9 @@
#define BUF_SIZE 1024
#define MODULE_CHUNK 4
#define UNKNOWN_MODULE_PATH "<*unknown module path*>"
+#ifndef _PAM_ISA
+#define _PAM_ISA "."
+#endif
static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
@@ -313,7 +316,7 @@ int _pam_init_handlers(pam_handle_t *pamh)
}
D(("_pam_init_handlers: initializing"));
-
+
/* First clean the service structure */
_pam_free_handlers(pamh);
@@ -358,7 +361,7 @@ int _pam_init_handlers(pam_handle_t *pamh)
*/
{
struct stat test_d;
-
+
/* Is there a PAM_CONFIG_D directory? */
if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
char *filename;
@@ -575,7 +578,7 @@ int _pam_add_handler(pam_handle_t *pamh
#ifdef PAM_SHL
const char *_sym, *_sym2;
#endif
- char *mod_full_path=NULL;
+ char *mod_full_path=NULL, *mod_full_isa_path=NULL, *isa=NULL;
servicefn func, func2;
int success;
@@ -640,6 +643,30 @@ int _pam_add_handler(pam_handle_t *pamh
# endif /* PAM_SHL */
D(("_pam_add_handler: dlopen'ed"));
if (mod->dl_handle == NULL) {
+ if (strstr(mod_path, "$ISA")) {
+ mod_full_isa_path = malloc(strlen(mod_path) + strlen(_PAM_ISA) + 1);
+ if (mod_full_isa_path == NULL) {
+ D(("_pam_handler: couldn't get memory for mod_path"));
+ _pam_system_log(LOG_ERR, "no memory for module path");
+ success = PAM_ABORT;
+ } else {
+ strcpy(mod_full_isa_path, mod_path);
+ isa = strstr(mod_full_isa_path, "$ISA");
+ if (isa) {
+ memmove(isa + strlen(_PAM_ISA), isa + 4, strlen(isa + 4) + 1);
+ memmove(isa, _PAM_ISA, strlen(_PAM_ISA));
+ }
+ mod->dl_handle =
+# ifdef PAM_SHL
+ shl_load(mod_full_isa_path, BIND_IMMEDIATE, 0L);
+# else /* PAM_SHL */
+ dlopen(mod_full_isa_path, RTLD_NOW);
+# endif /* PAM_SHL */
+ _pam_drop(mod_full_isa_path);
+ }
+ }
+ }
+ if (mod->dl_handle == NULL) {
D(("_pam_add_handler: dlopen(%s) failed", mod_path));
_pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path);
# ifndef PAM_SHL
@@ -782,7 +809,7 @@ int _pam_add_handler(pam_handle_t *pamh
}
/* now identify this module's functions - for non-faulty modules */
-
+
#ifdef PAM_DYNAMIC
if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
# ifdef PAM_SHL
@@ -909,7 +936,7 @@ int _pam_free_handlers(pam_handle_t *pamh)
}
/* Free all the handlers */
-
+
_pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
_pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
_pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
@@ -949,7 +976,7 @@ void _pam_start_handlers(pam_handle_t *pamh)
pamh->handlers.module = NULL;
/* initialize the .conf and .other entries */
-
+
pamh->handlers.conf.authenticate = NULL;
pamh->handlers.conf.setcred = NULL;
pamh->handlers.conf.acct_mgmt = NULL;
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);
}
}