aboutsummaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pam_unix
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@ubuntu.com>2019-01-03 12:47:05 -0800
committerSteve Langasek <steve.langasek@ubuntu.com>2019-01-03 12:47:05 -0800
commit4c51da22e068907adb7857d50f5109a467c94d7c (patch)
treebecf5fbae5dfcbe8896355f59042dc8eaefa7f37 /Linux-PAM/modules/pam_unix
parentefd31890b5ed496a5a00c08a262da240e66a4ddc (diff)
parentab9e8ba11f464fc083fc65a0bc695d60ebc86f3e (diff)
downloadpam-4c51da22e068907adb7857d50f5109a467c94d7c.tar.gz
pam-4c51da22e068907adb7857d50f5109a467c94d7c.tar.bz2
pam-4c51da22e068907adb7857d50f5109a467c94d7c.zip
New upstream version 0.79
Diffstat (limited to 'Linux-PAM/modules/pam_unix')
-rw-r--r--Linux-PAM/modules/pam_unix/CHANGELOG2
-rw-r--r--Linux-PAM/modules/pam_unix/Makefile38
-rw-r--r--Linux-PAM/modules/pam_unix/README2
-rw-r--r--Linux-PAM/modules/pam_unix/bigcrypt_main.c18
-rw-r--r--Linux-PAM/modules/pam_unix/md5.c2
-rw-r--r--Linux-PAM/modules/pam_unix/md5_crypt.c2
-rw-r--r--Linux-PAM/modules/pam_unix/pam_unix_acct.c53
-rw-r--r--Linux-PAM/modules/pam_unix/pam_unix_auth.c13
-rw-r--r--Linux-PAM/modules/pam_unix/pam_unix_passwd.c329
-rw-r--r--Linux-PAM/modules/pam_unix/pam_unix_sess.c21
-rw-r--r--Linux-PAM/modules/pam_unix/support.c399
-rw-r--r--Linux-PAM/modules/pam_unix/support.h21
-rw-r--r--Linux-PAM/modules/pam_unix/unix_chkpwd.c53
13 files changed, 654 insertions, 299 deletions
diff --git a/Linux-PAM/modules/pam_unix/CHANGELOG b/Linux-PAM/modules/pam_unix/CHANGELOG
index 206d30dd..509ce0a3 100644
--- a/Linux-PAM/modules/pam_unix/CHANGELOG
+++ b/Linux-PAM/modules/pam_unix/CHANGELOG
@@ -1,4 +1,4 @@
-$Id: CHANGELOG,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $
+$Id: CHANGELOG,v 1.1.1.1 2000/06/20 22:12:01 agmorgan Exp $
* Mon Aug 16 1999 Jan Rêkorajski <baggins@pld.org.pl>
- fixed reentrancy problems
diff --git a/Linux-PAM/modules/pam_unix/Makefile b/Linux-PAM/modules/pam_unix/Makefile
index 03374512..7f32e073 100644
--- a/Linux-PAM/modules/pam_unix/Makefile
+++ b/Linux-PAM/modules/pam_unix/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $
+# $Id: Makefile,v 1.8 2004/11/08 08:58:37 kukuk Exp $
#
# This Makefile controls a build process of the pam_unix modules
# for Linux-PAM. You should not modify this Makefile.
@@ -18,6 +18,19 @@ include ../../Make.Rules
#USE_CRACKLIB=-D"USE_CRACKLIB"
#endif
+ifeq ($(shell if [ -f /usr/lib/cracklib_dict.hwm ]; then echo yes ; fi),yes)
+ CRACKLIB_DICTPATH=/usr/lib/cracklib_dict
+else
+ CRACKLIB_DICTPATH=/usr/share/dict/cracklib_dict
+endif
+EXTRAS += -DCRACKLIB_DICTS=\"$(CRACKLIB_DICTPATH)\"
+
+ifeq ($(HAVE_LIBCRYPT),yes)
+ EXTRALS += -lcrypt
+endif
+ifeq ($(HAVE_LIBNSL),yes)
+ EXTRALS += -lnsl
+endif
# do you want to use lckpwdf?
ifeq ($(WITH_LCKPWDF),yes)
USE_LCKPWDF=-D"USE_LCKPWDF"
@@ -37,12 +50,19 @@ endif
CHKPWD=unix_chkpwd
+BIGCRYPT=bigcrypt
+
EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\"
+LINK_PAMMODUTILS = -L../pammodutil -lpammodutil
+INCLUDE_PAMMODUTILS = -I../pammodutil/include
+
########################################################################
-CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS)
-LDLIBS = $(EXTRALS)
+CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) \
+ $(INCLUDE_PAMMODUTILS)
+
+LDLIBS = $(EXTRALS) $(LINK_PAMMODUTILS)
ifdef USE_CRACKLIB
CRACKLIB = -lcrack
@@ -69,7 +89,8 @@ endif
########################### don't edit below #######################
-all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register
+all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) $(BIGCRYPT) \
+ register
dynamic/%.o : %.c
$(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
@@ -107,7 +128,7 @@ ifdef DYNAMIC
$(LIBOBJD): $(LIBSRC)
$(LIBSHARED): $(LIBOBJD)
- $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT)
+ $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) $(NEED_LINK_LIB_C) -L../../libpam -lpam
endif
ifdef STATIC
@@ -120,7 +141,10 @@ endif
$(CHKPWD): unix_chkpwd.o md5_good.o md5_broken.o \
md5_crypt_good.o md5_crypt_broken.o \
bigcrypt.o
- $(CC) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT)
+ $(CC) $(CFLAGS) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT)
+
+$(BIGCRYPT): bigcrypt_main.o bigcrypt.o
+ $(CC) -o $(BIGCRYPT) $^ $(LDLIBS) $(LIBCRYPT)
unix_chkpwd.o: unix_chkpwd.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
@@ -158,7 +182,7 @@ remove:
rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD)
clean:
- rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) *.o *.so core
+ rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) $(BIGCRYPT) *.o *.so core
rm -f *~ *.a *.out *.bak
rm -rf dynamic static
diff --git a/Linux-PAM/modules/pam_unix/README b/Linux-PAM/modules/pam_unix/README
index d6b1f395..afeee3da 100644
--- a/Linux-PAM/modules/pam_unix/README
+++ b/Linux-PAM/modules/pam_unix/README
@@ -31,5 +31,7 @@ The following options are recognized:
nis - use NIS RPC for setting new password
remember=X - remember X old passwords, they are kept in
/etc/security/opasswd in MD5 crypted form
+ broken_shadow - ignore errors reading shadow information for
+ users in the account management module
invalid arguments are logged to syslog.
diff --git a/Linux-PAM/modules/pam_unix/bigcrypt_main.c b/Linux-PAM/modules/pam_unix/bigcrypt_main.c
new file mode 100644
index 00000000..70819072
--- /dev/null
+++ b/Linux-PAM/modules/pam_unix/bigcrypt_main.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <string.h>
+
+extern const char *bigcrypt(const char *password, const char *salt);
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s password salt\n",
+ strchr(argv[0], '/') ?
+ (strchr(argv[0], '/') + 1) :
+ argv[0]);
+ return 0;
+ }
+ fprintf(stdout, "%s\n", bigcrypt(argv[1], argv[2]));
+ return 0;
+}
diff --git a/Linux-PAM/modules/pam_unix/md5.c b/Linux-PAM/modules/pam_unix/md5.c
index 3fb50137..7ee9ed00 100644
--- a/Linux-PAM/modules/pam_unix/md5.c
+++ b/Linux-PAM/modules/pam_unix/md5.c
@@ -1,5 +1,5 @@
/*
- * $Id: md5.c,v 1.1.1.1 2001/04/29 04:17:37 hartmans Exp $
+ * $Id: md5.c,v 1.1.1.1 2000/06/20 22:12:03 agmorgan Exp $
*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
diff --git a/Linux-PAM/modules/pam_unix/md5_crypt.c b/Linux-PAM/modules/pam_unix/md5_crypt.c
index 8ae84588..8b7bc66b 100644
--- a/Linux-PAM/modules/pam_unix/md5_crypt.c
+++ b/Linux-PAM/modules/pam_unix/md5_crypt.c
@@ -1,5 +1,5 @@
/*
- * $Id: md5_crypt.c,v 1.1.1.2 2002/09/15 20:09:01 hartmans Exp $
+ * $Id: md5_crypt.c,v 1.2 2001/07/10 20:24:16 vorlon Exp $
*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
diff --git a/Linux-PAM/modules/pam_unix/pam_unix_acct.c b/Linux-PAM/modules/pam_unix/pam_unix_acct.c
index 178b6037..02e07ba6 100644
--- a/Linux-PAM/modules/pam_unix/pam_unix_acct.c
+++ b/Linux-PAM/modules/pam_unix/pam_unix_acct.c
@@ -53,6 +53,7 @@
#define PAM_SM_ACCOUNT
#include <security/pam_modules.h>
+#include <security/_pam_modutil.h>
#ifndef LINUX_PAM
#include <security/pam_appl.h>
@@ -89,7 +90,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
return PAM_USER_UNKNOWN;
}
- pwent = getpwnam(uname);
+ pwent = _pammodutil_getpwnam(pamh, uname);
if (!pwent) {
_log_err(LOG_ALERT, pamh
,"could not identify user (from getpwnam(%s))"
@@ -113,7 +114,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
return PAM_CRED_INSUFFICIENT;
}
}
- spent = getspnam( uname );
+ spent = _pammodutil_getspnam (pamh, uname);
if (save_uid == pwent->pw_uid)
setreuid( save_uid, save_euid );
else {
@@ -122,19 +123,21 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
setreuid( -1, save_euid );
}
- } else if (!strcmp( pwent->pw_passwd, "x" )) {
- spent = getspnam(uname);
- } else {
+ } else if (_unix_shadowed (pwent))
+ spent = _pammodutil_getspnam (pamh, uname);
+ else
return PAM_SUCCESS;
- }
+
+ if (!spent)
+ if (on(UNIX_BROKEN_SHADOW,ctrl))
+ return PAM_SUCCESS;
if (!spent)
return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */
curdays = time(NULL) / (60 * 60 * 24);
D(("today is %d, last change %d", curdays, spent->sp_lstchg));
- if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)
- && (spent->sp_lstchg != 0)) {
+ if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)) {
_log_err(LOG_NOTICE, pamh
,"account %s has expired (account expired)"
,uname);
@@ -143,18 +146,6 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
D(("account expired"));
return PAM_ACCT_EXPIRED;
}
- if ((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact))
- && (spent->sp_max != -1) && (spent->sp_inact != -1)
- && (spent->sp_lstchg != 0)) {
- _log_err(LOG_NOTICE, pamh
- ,"account %s has expired (failed to change password)"
- ,uname);
- _make_remark(pamh, ctrl, PAM_ERROR_MSG,
- "Your account has expired; please contact your system administrator");
- D(("account expired 2"));
- return PAM_ACCT_EXPIRED;
- }
- D(("when was the last change"));
if (spent->sp_lstchg == 0) {
_log_err(LOG_NOTICE, pamh
,"expired password for user %s (root enforced)"
@@ -164,7 +155,25 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
D(("need a new password"));
return PAM_NEW_AUTHTOK_REQD;
}
- if (((spent->sp_lstchg + spent->sp_max) < curdays) && (spent->sp_max != -1)) {
+ if (curdays < spent->sp_lstchg) {
+ _log_err(LOG_DEBUG, pamh
+ ,"account %s has password changed in future"
+ ,uname);
+ return PAM_SUCCESS;
+ }
+ if ((curdays - spent->sp_lstchg > spent->sp_max)
+ && (curdays - spent->sp_lstchg > spent->sp_inact)
+ && (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact)
+ && (spent->sp_max != -1) && (spent->sp_inact != -1)) {
+ _log_err(LOG_NOTICE, pamh
+ ,"account %s has expired (failed to change password)"
+ ,uname);
+ _make_remark(pamh, ctrl, PAM_ERROR_MSG,
+ "Your account has expired; please contact your system administrator");
+ D(("account expired 2"));
+ return PAM_ACCT_EXPIRED;
+ }
+ if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) {
_log_err(LOG_DEBUG, pamh
,"expired password for user %s (password aged)"
,uname);
@@ -173,7 +182,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
D(("need a new password 2"));
return PAM_NEW_AUTHTOK_REQD;
}
- if ((curdays > (spent->sp_lstchg + spent->sp_max - spent->sp_warn))
+ if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn)
&& (spent->sp_max != -1) && (spent->sp_warn != -1)) {
daysleft = (spent->sp_lstchg + spent->sp_max) - curdays;
_log_err(LOG_DEBUG, pamh
diff --git a/Linux-PAM/modules/pam_unix/pam_unix_auth.c b/Linux-PAM/modules/pam_unix/pam_unix_auth.c
index 67497e06..39e0cde5 100644
--- a/Linux-PAM/modules/pam_unix/pam_unix_auth.c
+++ b/Linux-PAM/modules/pam_unix/pam_unix_auth.c
@@ -15,13 +15,13 @@
* 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
@@ -88,7 +88,8 @@ do { \
*ret_data = retval; \
pam_set_data(pamh, "unix_setcred_return", \
(void *) ret_data, setcred_free); \
- } \
+ } else if (ret_data) \
+ free (ret_data); \
D(("done. [%s]", pam_strerror(pamh, retval))); \
return retval; \
} while (0)
@@ -148,7 +149,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags
/* if this user does not have a password... */
- if (_unix_blankpasswd(ctrl, name)) {
+ if (_unix_blankpasswd(pamh, ctrl, name)) {
D(("user '%s' has blank passwd", name));
name = NULL;
retval = PAM_SUCCESS;
@@ -183,7 +184,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags
}
-/*
+/*
* The only thing _pam_set_credentials_unix() does is initialization of
* UNIX group IDs.
*
@@ -203,7 +204,7 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags
retval = PAM_SUCCESS;
D(("recovering return code from auth call"));
- /* We will only find something here if UNIX_LIKE_AUTH is set --
+ /* We will only find something here if UNIX_LIKE_AUTH is set --
don't worry about an explicit check of argv. */
pam_get_data(pamh, "unix_setcred_return", (const void **) &pretval);
if(pretval) {
diff --git a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
index 6b51a6b2..2ea57cc6 100644
--- a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
+++ b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
@@ -1,5 +1,5 @@
/*
- * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
+ * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
* Copyright (C) 1996.
* Copyright (c) Jan Rêkorajski, 1999.
*
@@ -73,6 +73,8 @@
#include <security/pam_appl.h>
#endif /* LINUX_PAM */
+#include <security/_pam_modutil.h>
+
#include "yppasswd.h"
#include "md5.h"
#include "support.h"
@@ -88,7 +90,7 @@ extern int getrpcport(const char *host, unsigned long prognum,
*/
#ifdef NEED_LCKPWDF
-#include "./lckpwdf.-c"
+# include "./lckpwdf.-c"
#endif
extern char *bigcrypt(const char *key, const char *salt);
@@ -114,7 +116,9 @@ extern char *bigcrypt(const char *key, const char *salt);
#define MAX_PASSWD_TRIES 3
#define PW_TMPFILE "/etc/npasswd"
#define SH_TMPFILE "/etc/nshadow"
+#ifndef CRACKLIB_DICTS
#define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict"
+#endif
#define OPW_TMPFILE "/etc/security/nopasswd"
#define OLD_PASSWORDS_FILE "/etc/security/opasswd"
@@ -215,7 +219,7 @@ static int check_old_password(const char *forwho, const char *newpass)
opwfile = fopen(OLD_PASSWORDS_FILE, "r");
if (opwfile == NULL)
- return PAM_AUTHTOK_ERR;
+ return PAM_ABORT;
while (fgets(buf, 16380, opwfile)) {
if (!strncmp(buf, forwho, strlen(forwho))) {
@@ -242,7 +246,8 @@ static int check_old_password(const char *forwho, const char *newpass)
return retval;
}
-static int save_old_password(const char *forwho, const char *oldpass,
+static int save_old_password(pam_handle_t *pamh,
+ const char *forwho, const char *oldpass,
int howmany)
{
static char buf[16384];
@@ -254,6 +259,7 @@ static int save_old_password(const char *forwho, const char *oldpass,
int oldmask;
int found = 0;
struct passwd *pwd = NULL;
+ struct stat st;
if (howmany < 0) {
return PAM_SUCCESS;
@@ -276,8 +282,25 @@ static int save_old_password(const char *forwho, const char *oldpass,
return PAM_AUTHTOK_ERR;
}
- chown(OPW_TMPFILE, 0, 0);
- chmod(OPW_TMPFILE, 0600);
+ if (fstat (fileno (opwfile), &st) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+
+ if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+ if (fchmod (fileno (pwfile), st.st_mode) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
while (fgets(buf, 16380, opwfile)) {
if (!strncmp(buf, forwho, strlen(forwho))) {
@@ -314,7 +337,7 @@ static int save_old_password(const char *forwho, const char *oldpass,
fclose(opwfile);
if (!found) {
- pwd = getpwnam(forwho);
+ pwd = _pammodutil_getpwnam(pamh, forwho);
if (pwd == NULL) {
err = 1;
} else {
@@ -335,18 +358,20 @@ static int save_old_password(const char *forwho, const char *oldpass,
}
if (!err) {
- rename(OPW_TMPFILE, OLD_PASSWORDS_FILE);
- return PAM_SUCCESS;
- } else {
- unlink(OPW_TMPFILE);
- return PAM_AUTHTOK_ERR;
+ if (!rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) {
+ return PAM_SUCCESS;
+ }
}
+
+ unlink(OPW_TMPFILE);
+ return PAM_AUTHTOK_ERR;
}
static int _update_passwd(pam_handle_t *pamh,
const char *forwho, const char *towhat)
{
struct passwd *tmpent = NULL;
+ struct stat st;
FILE *pwfile, *opwfile;
int err = 1;
int oldmask;
@@ -364,9 +389,26 @@ static int _update_passwd(pam_handle_t *pamh,
return PAM_AUTHTOK_ERR;
}
- chown(PW_TMPFILE, 0, 0);
- chmod(PW_TMPFILE, 0644);
- tmpent = fgetpwent(opwfile);
+ if (fstat (fileno (opwfile), &st) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+
+ if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+ if (fchmod (fileno (pwfile), st.st_mode) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ }
+
+ tmpent = fgetpwent (opwfile);
while (tmpent) {
if (!strcmp(tmpent->pw_name, forwho)) {
/* To shut gcc up */
@@ -375,7 +417,7 @@ static int _update_passwd(pam_handle_t *pamh,
char *charp;
} assigned_passwd;
assigned_passwd.const_charp = towhat;
-
+
tmpent->pw_passwd = assigned_passwd.charp;
err = 0;
}
@@ -394,18 +436,20 @@ static int _update_passwd(pam_handle_t *pamh,
}
if (!err) {
- rename(PW_TMPFILE, "/etc/passwd");
- _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
- return PAM_SUCCESS;
- } else {
- unlink(PW_TMPFILE);
- return PAM_AUTHTOK_ERR;
+ if (!rename(PW_TMPFILE, "/etc/passwd")) {
+ _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
+ return PAM_SUCCESS;
+ }
}
+
+ unlink(PW_TMPFILE);
+ return PAM_AUTHTOK_ERR;
}
-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;
FILE *pwfile, *opwfile;
int err = 1;
int oldmask;
@@ -427,8 +471,26 @@ static int _update_shadow(const char *forwho, char *towhat)
return PAM_AUTHTOK_ERR;
}
- chown(SH_TMPFILE, 0, 0);
- chmod(SH_TMPFILE, 0600);
+ if (fstat (fileno (opwfile), &st) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+
+ if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+ if (fchmod (fileno (pwfile), st.st_mode) == -1)
+ {
+ fclose (opwfile);
+ fclose (pwfile);
+ return PAM_AUTHTOK_ERR;
+ }
+
stmpent = fgetspent(opwfile);
while (stmpent) {
@@ -455,12 +517,14 @@ static int _update_shadow(const char *forwho, char *towhat)
}
if (!err) {
- rename(SH_TMPFILE, "/etc/shadow");
- return PAM_SUCCESS;
- } else {
- unlink(SH_TMPFILE);
- return PAM_AUTHTOK_ERR;
+ if (!rename(SH_TMPFILE, "/etc/shadow")) {
+ _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
+ return PAM_SUCCESS;
+ }
}
+
+ unlink(SH_TMPFILE);
+ return PAM_AUTHTOK_ERR;
}
static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
@@ -471,14 +535,28 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
D(("called"));
- setpwent();
pwd = getpwnam(forwho);
- endpwent();
- if (pwd == NULL)
- return PAM_AUTHTOK_ERR;
+ if (pwd == NULL) {
+ retval = PAM_AUTHTOK_ERR;
+ goto done;
+ }
- if (on(UNIX_NIS, ctrl)) {
+ if (_unix_comesfromsource(pamh, forwho, 1, 0)) {
+ /* first, save old password */
+ if (save_old_password(pamh, forwho, fromwhat, remember)) {
+ retval = PAM_AUTHTOK_ERR;
+ goto done;
+ }
+ if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) {
+ retval = _update_shadow(pamh, forwho, towhat);
+ if (retval == PAM_SUCCESS)
+ if (!_unix_shadowed(pwd))
+ retval = _update_passwd(pamh, forwho, "x");
+ } else {
+ retval = _update_passwd(pamh, forwho, towhat);
+ }
+ } else if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
struct timeval timeout;
struct yppasswd yppwd;
CLIENT *clnt;
@@ -486,6 +564,10 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
int status;
int err = 0;
+ /* Unlock passwd file to avoid deadlock */
+#ifdef USE_LCKPWDF
+ ulckpwdf();
+#endif
/* Make RPC call to NIS server */
if ((master = getNISserver(pamh)) == NULL)
return PAM_TRY_AGAIN;
@@ -498,7 +580,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
yppwd.newpw.pw_gecos = pwd->pw_gecos;
yppwd.newpw.pw_dir = pwd->pw_dir;
yppwd.newpw.pw_shell = pwd->pw_shell;
- yppwd.oldpass = fromwhat;
+ yppwd.oldpass = fromwhat ? fromwhat : "";
yppwd.newpw.pw_passwd = towhat;
D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));
@@ -540,17 +622,11 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
#endif
return retval;
}
- /* first, save old password */
- if (save_old_password(forwho, fromwhat, remember)) {
- return PAM_AUTHTOK_ERR;
- }
- if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) {
- retval = _update_shadow(forwho, towhat);
- if (retval == PAM_SUCCESS)
- retval = _update_passwd(pamh, forwho, "x");
- } else {
- retval = _update_passwd(pamh, forwho, towhat);
- }
+
+done:
+#ifdef USE_LCKPWDF
+ ulckpwdf();
+#endif
return retval;
}
@@ -563,13 +639,11 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl)
int retval = PAM_SUCCESS;
/* UNIX passwords area */
- setpwent();
pwd = getpwnam(user); /* Get password file entry... */
- endpwent();
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();
@@ -579,7 +653,7 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl)
if (spwdent == NULL)
return PAM_AUTHINFO_UNAVAIL;
} else {
- if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */
+ if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */
uid_t save_uid;
save_uid = geteuid();
@@ -661,11 +735,17 @@ 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)
+ if (on(UNIX_REMEMBER_PASSWD, ctrl)) {
+ if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR)
remark = "Password has been already used. Choose another.";
+ if (retval == PAM_ABORT) {
+ _log_err(LOG_ERR, pamh, "can't open %s file to check old passwords",
+ OLD_PASSWORDS_FILE);
+ return retval;
+ }
+ }
}
if (remark) {
_make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
@@ -689,33 +769,12 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
D(("called."));
-#ifdef USE_LCKPWDF
- /* our current locking system requires that we lock the
- entire password database. This avoids both livelock
- and deadlock. */
- /* These values for the number of attempts and the sleep time
- are, of course, completely arbitrary.
- My reading of the PAM docs is that, once pam_chauthtok() has been
- called with PAM_UPDATE_AUTHTOK, we are obliged to take any
- reasonable steps to make sure the token is updated; so retrying
- for 1/10 sec. isn't overdoing it.
- The other possibility is to call lckpwdf() on the first
- pam_chauthtok() pass, and hold the lock until released in the
- second pass--but is this guaranteed to work? -SRL */
- i=0;
- while((retval = lckpwdf()) != 0 && i < 100) {
- usleep(1000);
- }
- if(retval != 0) {
- return PAM_AUTHTOK_LOCK_BUSY;
- }
-#endif
ctrl = _set_ctrl(pamh, flags, &remember, argc, argv);
/*
* First get the name of a user
*/
- retval = pam_get_user(pamh, &user, "Username: ");
+ retval = pam_get_user(pamh, &user, NULL);
if (retval == PAM_SUCCESS) {
/*
* Various libraries at various times have had bugs related to
@@ -725,9 +784,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
*/
if (user == NULL || !isalnum(*user)) {
_log_err(LOG_ERR, pamh, "bad username [%s]", user);
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return PAM_USER_UNKNOWN;
}
if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl))
@@ -737,15 +793,42 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
if (on(UNIX_DEBUG, ctrl))
_log_err(LOG_DEBUG, pamh,
"password - could not identify user");
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return retval;
}
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 (pwd == NULL) {
+ _log_err(LOG_DEBUG, pamh,
+ "user \"%s\" has corrupted passwd entry",
+ user);
+ return PAM_USER_UNKNOWN;
+ }
+ 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))
@@ -760,10 +843,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
D(("prelim check"));
- if (_unix_blankpasswd(ctrl, user)) {
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
+ if (_unix_blankpasswd(pamh, ctrl, user)) {
return PAM_SUCCESS;
} else if (off(UNIX__IAMROOT, ctrl)) {
@@ -773,9 +853,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
if (Announce == NULL) {
_log_err(LOG_CRIT, pamh,
"password - out of memory");
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return PAM_BUF_ERR;
}
(void) strcpy(Announce, greeting);
@@ -795,9 +872,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
if (retval != PAM_SUCCESS) {
_log_err(LOG_NOTICE, pamh
,"password - (old) token not obtained");
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return retval;
}
/* verify that this is the password for this user */
@@ -812,9 +886,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
if (retval != PAM_SUCCESS) {
D(("Authentication failed"));
pass_old = NULL;
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return retval;
}
retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
@@ -867,19 +938,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
if (retval != PAM_SUCCESS) {
_log_err(LOG_NOTICE, pamh, "user not authenticated");
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
- return retval;
- }
- retval = _unix_verify_shadow(user, ctrl);
- if (retval != PAM_SUCCESS) {
- _log_err(LOG_NOTICE, pamh, "user not authenticated 2");
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return retval;
}
+
D(("get new password now"));
lctrl = ctrl;
@@ -908,9 +969,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
,"password - new password not obtained");
}
pass_old = NULL; /* tidy up */
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return retval;
}
D(("returned to _unix_chauthtok"));
@@ -931,11 +989,56 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
_log_err(LOG_NOTICE, pamh,
"new password not acceptable");
pass_new = pass_old = NULL; /* tidy up */
+ return retval;
+ }
+#ifdef USE_LCKPWDF
+ /* These values for the number of attempts and the sleep time
+ are, of course, completely arbitrary.
+ My reading of the PAM docs is that, once pam_chauthtok() has been
+ called with PAM_UPDATE_AUTHTOK, we are obliged to take any
+ reasonable steps to make sure the token is updated; so retrying
+ for 1/10 sec. isn't overdoing it. */
+ i=0;
+ while((retval = lckpwdf()) != 0 && i < 100) {
+ usleep(1000);
+ i++;
+ }
+ if(retval != 0) {
+ return PAM_AUTHTOK_LOCK_BUSY;
+ }
+#endif
+
+ if (pass_old) {
+ retval = _unix_verify_password(pamh, user, pass_old, ctrl);
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, pamh, "user password changed by another process");
+#ifdef USE_LCKPWDF
+ ulckpwdf();
+#endif
+ return retval;
+ }
+ }
+
+ retval = _unix_verify_shadow(user, ctrl);
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, pamh, "user not authenticated 2");
#ifdef USE_LCKPWDF
ulckpwdf();
#endif
return retval;
}
+
+ retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, pamh,
+ "new password not acceptable 2");
+ pass_new = pass_old = NULL; /* tidy up */
+#ifdef USE_LCKPWDF
+ ulckpwdf();
+#endif
+ return retval;
+ }
+
/*
* By reaching here we have approved the passwords and must now
* rebuild the password database file.
@@ -962,7 +1065,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
salt[2] = '\0';
if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) {
- /*
+ /*
* to avoid using the _extensions_ of the bigcrypt()
* function we truncate the newly entered password
* [Problems that followed from this are fixed as per
@@ -998,6 +1101,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
retval = _do_setpass(pamh, user, pass_old, tpass, ctrl,
remember);
+ /* _do_setpass has called ulckpwdf for us */
+
_pam_delete(tpass);
pass_old = pass_new = NULL;
} else { /* something has broken with the module */
@@ -1008,9 +1113,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
D(("retval was %d", retval));
-#ifdef USE_LCKPWDF
- ulckpwdf();
-#endif
return retval;
}
@@ -1027,4 +1129,3 @@ struct pam_module _pam_unix_passwd_modstruct = {
pam_sm_chauthtok,
};
#endif
-
diff --git a/Linux-PAM/modules/pam_unix/pam_unix_sess.c b/Linux-PAM/modules/pam_unix/pam_unix_sess.c
index 0784bff8..a29a7085 100644
--- a/Linux-PAM/modules/pam_unix/pam_unix_sess.c
+++ b/Linux-PAM/modules/pam_unix/pam_unix_sess.c
@@ -1,5 +1,5 @@
/*
- * $Id: pam_unix_sess.c,v 1.1.1.1 2001/04/29 04:17:39 hartmans Exp $
+ * $Id: pam_unix_sess.c,v 1.5 2005/03/23 14:35:21 t8m Exp $
*
* Copyright Alexander O. Yuriev, 1996. All rights reserved.
* Copyright Jan Rêkorajski, 1999. All rights reserved.
@@ -53,6 +53,7 @@
#include <security/_pam_macros.h>
#include <security/pam_modules.h>
+#include <security/_pam_modutil.h>
#ifndef LINUX_PAM
#include <security/pam_appl.h>
@@ -71,27 +72,31 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags,
char *user_name, *service;
unsigned int ctrl;
int retval;
+ const char *login_name;
D(("called."));
ctrl = _set_ctrl(pamh, flags, NULL, argc, argv);
retval = pam_get_item(pamh, PAM_USER, (void *) &user_name);
- if (user_name == NULL || retval != PAM_SUCCESS) {
+ if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) {
_log_err(LOG_CRIT, pamh,
"open_session - error recovering username");
return PAM_SESSION_ERR; /* How did we get authenticated with
no username?! */
}
retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service);
- if (service == NULL || retval != PAM_SUCCESS) {
+ if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) {
_log_err(LOG_CRIT, pamh,
"open_session - error recovering service");
return PAM_SESSION_ERR;
}
- _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)"
- ,user_name
- ,PAM_getlogin() == NULL ? "" : PAM_getlogin(), getuid());
+ login_name = _pammodutil_getlogin(pamh);
+ if (login_name == NULL) {
+ login_name = "";
+ }
+ _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)",
+ user_name, login_name, getuid());
return PAM_SUCCESS;
}
@@ -108,14 +113,14 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags,
ctrl = _set_ctrl(pamh, flags, NULL, argc, argv);
retval = pam_get_item(pamh, PAM_USER, (void *) &user_name);
- if (user_name == NULL || retval != PAM_SUCCESS) {
+ if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) {
_log_err(LOG_CRIT, pamh,
"close_session - error recovering username");
return PAM_SESSION_ERR; /* How did we get authenticated with
no username?! */
}
retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service);
- if (service == NULL || retval != PAM_SUCCESS) {
+ if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) {
_log_err(LOG_CRIT, pamh,
"close_session - error recovering service");
return PAM_SESSION_ERR;
diff --git a/Linux-PAM/modules/pam_unix/support.c b/Linux-PAM/modules/pam_unix/support.c
index 15861af6..1584f2f1 100644
--- a/Linux-PAM/modules/pam_unix/support.c
+++ b/Linux-PAM/modules/pam_unix/support.c
@@ -1,5 +1,5 @@
/*
- * $Id: support.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $
+ * $Id: support.c,v 1.25 2005/01/10 09:45:37 kukuk Exp $
*
* Copyright information at end of file.
*/
@@ -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>
@@ -16,9 +17,13 @@
#include <limits.h>
#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>
+#include <security/_pam_modutil.h>
#include "md5.h"
#include "support.h"
@@ -106,36 +111,6 @@ int _make_remark(pam_handle_t * pamh, unsigned int ctrl
return retval;
}
- /*
- * Beacause getlogin() is braindead and sometimes it just
- * doesn't work, we reimplement it here.
- */
-char *PAM_getlogin(void)
-{
- struct utmp *ut, line;
- char *curr_tty, *retval;
- static char curr_user[sizeof(ut->ut_user) + 4];
-
- retval = NULL;
-
- curr_tty = ttyname(0);
- if (curr_tty != NULL) {
- D(("PAM_getlogin ttyname: %s", curr_tty));
- curr_tty += 5;
- setutent();
- strncpy(line.ut_line, curr_tty, sizeof(line.ut_line));
- if ((ut = getutline(&line)) != NULL) {
- strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user));
- curr_user[sizeof(curr_user) - 1] = '\0';
- retval = curr_user;
- }
- endutent();
- }
- D(("PAM_getlogin retval: %s", retval));
-
- return retval;
-}
-
/*
* set the control flags for the UNIX module.
*/
@@ -163,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);
@@ -195,7 +166,7 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc,
if (remember != NULL) {
if (j == UNIX_REMEMBER_PASSWD) {
*remember = strtol(*argv + 9, NULL, 10);
- if ((*remember == LONG_MIN) || (*remember == LONG_MAX))
+ if ((*remember == INT_MIN) || (*remember == INT_MAX))
*remember = -1;
if (*remember > 400)
*remember = 400;
@@ -206,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)) {
@@ -304,25 +280,178 @@ 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, 10);
+ if ((strlen(sgid) == 0) || (*p != '\0')) {
+ free(*ret);
+ *ret = NULL;
+ return matched;
+ }
+
+ (*ret)->pw_gid = strtol(sgid, &p, 10);
+ 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
* - to avoid prompting for one in such cases (CG)
*/
-int _unix_blankpasswd(unsigned int ctrl, const char *name)
+int
+_unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name)
{
struct passwd *pwd = NULL;
struct spwd *spwdent = NULL;
char *salt = NULL;
int retval;
-#if HAVE_GETPWNAM_R
- char *buf = NULL;
- int bufsize = 0;
- struct passwd pwd_buf;
-
- pwd = &pwd_buf;
-#endif
D(("called"));
@@ -338,23 +467,7 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name)
/* UNIX passwords area */
/* Get password file entry... */
-#if HAVE_GETPWNAM_R
- bufsize = 1024;
- buf = malloc(bufsize);
-
- if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) {
- pwd = NULL;
- }
- while (retval == ERANGE) {
- bufsize += 1024;
- buf = realloc(buf, bufsize);
- if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) {
- pwd = NULL;
- }
- }
-#else
- pwd = getpwnam(name);
-#endif
+ pwd = _pammodutil_getpwnam (pamh, name);
if (pwd != NULL) {
if (strcmp( pwd->pw_passwd, "*NP*" ) == 0)
@@ -372,28 +485,24 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name)
setreuid( 0, -1 );
if(setreuid( -1, pwd->pw_uid ) == -1)
/* Will fail elsewhere. */
-#if HAVE_GETPWNAM_R
- if (buf)
- free(buf);
-#endif
return 0;
}
}
- spwdent = getspnam( name );
+ spwdent = _pammodutil_getspnam (pamh, name);
if (save_uid == pwd->pw_uid)
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
*/
- spwdent = getspnam(name);
+ spwdent = _pammodutil_getspnam(pamh, name);
}
if (spwdent)
salt = x_strdup(spwdent->sp_pwdp);
@@ -415,11 +524,6 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name)
if (salt)
_pam_delete(salt);
-#if HAVE_GETPWNAM_R
- if (buf)
- free(buf);
-#endif
-
return retval;
}
@@ -434,6 +538,7 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
unsigned int ctrl, const char *user)
{
int retval, child, fds[2];
+ void (*sighandler)(int) = NULL;
D(("called."));
/* create a pipe for the password */
@@ -442,6 +547,18 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
return PAM_AUTH_ERR;
}
+ if (off(UNIX_NOREAP, ctrl)) {
+ /*
+ * This code arranges that the demise of the child does not cause
+ * the application to receive a signal it is not expecting - which
+ * may kill the application or worse.
+ *
+ * The "noreap" module argument is provided so that the admin can
+ * override this behavior.
+ */
+ sighandler = signal(SIGCHLD, SIG_DFL);
+ }
+
/* fork */
child = fork();
if (child == 0) {
@@ -486,6 +603,10 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
retval = PAM_AUTH_ERR;
}
+ if (sighandler != NULL) {
+ (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
+ }
+
D(("returning %d", retval));
return retval;
}
@@ -514,7 +635,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
D(("locating user's record"));
/* UNIX passwords area */
- pwd = getpwnam(name); /* Get password file entry... */
+ pwd = _pammodutil_getpwnam (pamh, name); /* Get password file entry... */
if (pwd != NULL) {
if (strcmp( pwd->pw_passwd, "*NP*" ) == 0)
@@ -535,7 +656,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
}
}
- spwdent = getspnam( name );
+ spwdent = _pammodutil_getspnam (pamh, name);
if (save_uid == pwd->pw_uid)
setreuid( save_uid, save_euid );
else {
@@ -543,12 +664,12 @@ 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
*/
- spwdent = getspnam(name);
+ spwdent = _pammodutil_getspnam (pamh, name);
}
if (spwdent)
salt = x_strdup(spwdent->sp_pwdp);
@@ -565,7 +686,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
}
retval = PAM_SUCCESS;
- if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) {
+ 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"));
@@ -577,6 +698,11 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
}
} else {
D(("user's record unavailable"));
+ p = NULL;
+ if (pwd == NULL)
+ retval = PAM_USER_UNKNOWN;
+ else
+ retval = PAM_AUTHINFO_UNAVAIL;
if (on(UNIX_AUDIT, ctrl)) {
/* this might be a typo and the user has given a password
instead of a username. Careful with this. */
@@ -584,54 +710,58 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
"check pass; user (%s) unknown", name);
} else {
name = NULL;
- _log_err(LOG_ALERT, pamh,
- "check pass; user unknown");
+ if (on(UNIX_DEBUG, ctrl) || pwd == NULL) {
+ _log_err(LOG_ALERT, pamh,
+ "check pass; user unknown");
+ } else {
+ /* don't log failure as another pam module can succeed */
+ goto cleanup;
+ }
}
- p = NULL;
- retval = PAM_AUTHINFO_UNAVAIL;
}
} else {
- if (!strlen(salt)) {
- /* the stored password is NULL */
- if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
- D(("user has empty password - access granted"));
- retval = PAM_SUCCESS;
- } else {
- D(("user has empty password - access denied"));
- retval = PAM_AUTH_ERR;
- }
- } else if (!p) {
- retval = PAM_AUTH_ERR;
+ int salt_len = strlen(salt);
+ if (!salt_len) {
+ /* the stored password is NULL */
+ if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */
+ D(("user has empty password - access granted"));
+ retval = PAM_SUCCESS;
} else {
- if (!strncmp(salt, "$1$", 3)) {
- pp = Goodcrypt_md5(p, salt);
- if (strcmp(pp, salt) != 0) {
- _pam_delete(pp);
- pp = Brokencrypt_md5(p, salt);
- }
- } else {
- pp = bigcrypt(p, salt);
- }
- p = NULL; /* no longer needed here */
+ D(("user has empty password - access denied"));
+ retval = PAM_AUTH_ERR;
+ }
+ } else if (!p || (*salt == '*') || (salt_len < 13)) {
+ retval = PAM_AUTH_ERR;
+ } else {
+ if (!strncmp(salt, "$1$", 3)) {
+ pp = Goodcrypt_md5(p, salt);
+ if (strcmp(pp, salt) != 0) {
+ _pam_delete(pp);
+ pp = Brokencrypt_md5(p, salt);
+ }
+ } else {
+ pp = bigcrypt(p, salt);
+ }
+ p = NULL; /* no longer needed here */
- /* the moment of truth -- do we agree with the password? */
- D(("comparing state of pp[%s] and salt[%s]", pp, salt));
+ /* the moment of truth -- do we agree with the password? */
+ D(("comparing state of pp[%s] and salt[%s]", pp, salt));
- /*
- * Note, we are comparing the bigcrypt of the password with
- * the contents of the password field. If the latter was
- * encrypted with regular crypt (and not bigcrypt) it will
- * have been truncated for storage relative to the output
- * of bigcrypt here. As such we need to compare only the
- * stored string with the subset of bigcrypt's result.
- * Bug 521314: The strncmp comparison is for legacy support.
- */
- if (strncmp(pp, salt, strlen(salt)) == 0) {
- retval = PAM_SUCCESS;
- } else {
- retval = PAM_AUTH_ERR;
- }
+ /*
+ * Note, we are comparing the bigcrypt of the password with
+ * the contents of the password field. If the latter was
+ * encrypted with regular crypt (and not bigcrypt) it will
+ * have been truncated for storage relative to the output
+ * of bigcrypt here. As such we need to compare only the
+ * stored string with the subset of bigcrypt's result.
+ * Bug 521314: The strncmp comparison is for legacy support.
+ */
+ if (strncmp(pp, salt, salt_len) == 0) {
+ retval = PAM_SUCCESS;
+ } else {
+ retval = PAM_AUTH_ERR;
}
+ }
}
if (retval == PAM_SUCCESS) {
@@ -649,10 +779,17 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
if (new != NULL) {
- new->user = x_strdup(name ? name : "");
+ const char *login_name;
+
+ login_name = _pammodutil_getlogin(pamh);
+ if (login_name == NULL) {
+ login_name = "";
+ }
+
+ new->user = x_strdup(name ? name : "");
new->uid = getuid();
new->euid = geteuid();
- new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : "");
+ new->name = x_strdup(login_name);
/* any previous failures for this user ? */
pam_get_data(pamh, data_name, (const void **) &old);
@@ -702,6 +839,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
}
}
+cleanup:
if (data_name)
_pam_delete(data_name);
if (salt)
@@ -762,7 +900,7 @@ int _unix_read_password(pam_handle_t * pamh
return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
} else if (on(UNIX_USE_AUTHTOK, ctrl)
&& off(UNIX__OLD_PASSWD, ctrl)) {
- return PAM_AUTHTOK_RECOVER_ERR;
+ return PAM_AUTHTOK_ERR;
}
}
/*
@@ -884,6 +1022,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/Linux-PAM/modules/pam_unix/support.h b/Linux-PAM/modules/pam_unix/support.h
index 368a4e8f..39abadd5 100644
--- a/Linux-PAM/modules/pam_unix/support.h
+++ b/Linux-PAM/modules/pam_unix/support.h
@@ -1,10 +1,11 @@
/*
- * $Id: support.h,v 1.1.1.1 2001/04/29 04:17:41 hartmans Exp $
+ * $Id: support.h,v 1.8 2004/10/06 13:42:36 kukuk Exp $
*/
#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
@@ -80,8 +81,11 @@ typedef struct {
#define UNIX_BIGCRYPT 18 /* use DEC-C2 crypt()^x function */
#define UNIX_LIKE_AUTH 19 /* need to auth for setcred to work */
#define UNIX_REMEMBER_PASSWD 20 /* Remember N previous passwords */
+#define UNIX_NOREAP 21 /* don't reap child process */
+#define UNIX_BROKEN_SHADOW 22 /* ignore errors reading password aging
+ * information during acct management */
/* -------------- */
-#define UNIX_CTRLS_ 21 /* number of ctrl arguments defined */
+#define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */
static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
@@ -110,6 +114,8 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
/* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000},
/* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000},
/* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000},
+/* UNIX_NOREAP */ {"noreap", _ALL_ON_, 04000000},
+/* UNIX_BROKEN_SHADOW */ {"broken_shadow", _ALL_ON_, 010000000},
};
#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
@@ -123,13 +129,18 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
_pam_drop(xx); \
}
-extern char *PAM_getlogin(void);
extern void _log_err(int err, pam_handle_t *pamh, const char *format,...);
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_blankpasswd(unsigned int ctrl, const char *name);
+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
,const char *p, unsigned int ctrl);
extern int _unix_read_password(pam_handle_t * pamh
@@ -139,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/Linux-PAM/modules/pam_unix/unix_chkpwd.c b/Linux-PAM/modules/pam_unix/unix_chkpwd.c
index 6188435f..be32348f 100644
--- a/Linux-PAM/modules/pam_unix/unix_chkpwd.c
+++ b/Linux-PAM/modules/pam_unix/unix_chkpwd.c
@@ -1,5 +1,5 @@
/*
- * $Id: unix_chkpwd.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $
+ * $Id: unix_chkpwd.c,v 1.11 2004/11/16 14:27:42 toady Exp $
*
* This program is designed to run setuid(root) or with sufficient
* privilege to read all of the unix password databases. It is designed
@@ -57,8 +57,31 @@ 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)
{
+#ifndef SA_RESETHAND
+ /* emulate the behaviour of the SA_RESETHAND flag */
+ if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV )
+ signal(sig, SIG_DFL);
+#endif
if (sig > 0) {
_log_err(LOG_NOTICE, "caught signal %d.", sig);
exit(sig);
@@ -74,7 +97,9 @@ static void setup_signals(void)
*/
(void) memset((void *) &action, 0, sizeof(action));
action.sa_handler = su_sighandler;
+#ifdef SA_RESETHAND
action.sa_flags = SA_RESETHAND;
+#endif
(void) sigaction(SIGILL, &action, NULL);
(void) sigaction(SIGTRAP, &action, NULL);
(void) sigaction(SIGBUS, &action, NULL);
@@ -87,20 +112,21 @@ 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;
char *salt = NULL;
char *pp = NULL;
int retval = UNIX_FAILED;
+ int salt_len;
/* UNIX passwords area */
setpwent();
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
@@ -133,8 +159,11 @@ static int _unix_verify_password(const char *name, const char *p, int opt)
return retval;
}
- if (strlen(salt) == 0)
- return (opt == 0) ? UNIX_FAILED : UNIX_PASSED;
+ salt_len = strlen(salt);
+ if (salt_len == 0)
+ return (nullok == 0) ? UNIX_FAILED : UNIX_PASSED;
+ else if (p == NULL || strlen(p) == 0)
+ return UNIX_FAILED;
/* the moment of truth -- do we agree with the password? */
retval = UNIX_FAILED;
@@ -147,6 +176,8 @@ static int _unix_verify_password(const char *name, const char *p, int opt)
if (strcmp(pp, salt) == 0)
retval = UNIX_PASSED;
}
+ } else if ((*salt == '*') || (salt_len < 13)) {
+ retval = UNIX_FAILED;
} else {
pp = bigcrypt(p, salt);
/*
@@ -158,7 +189,7 @@ static int _unix_verify_password(const char *name, const char *p, int opt)
* stored string with the subset of bigcrypt's result.
* Bug 521314: the strncmp comparison is for legacy support.
*/
- if (strncmp(pp, salt, strlen(salt)) == 0) {
+ if (strncmp(pp, salt, salt_len) == 0) {
retval = UNIX_PASSED;
}
}
@@ -197,7 +228,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;
@@ -250,9 +281,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) */
@@ -271,13 +302,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);
}
}