aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeraphim Mellos <mellos@ceid.upatras.gr>2008-06-19 19:54:42 +0300
committerSeraphim Mellos <mellos@ceid.upatras.gr>2008-06-19 19:54:42 +0300
commit8b00f4aacb15ecad5227d1f4c5354c1938ba8fbf (patch)
tree10b155bdb6df9b9801c949ba24c867b2d7ca3eb7
parentAdded logging/debug msgs in pam_unix (diff)
downloadopenpam-modules-8b00f4aacb15ecad5227d1f4c5354c1938ba8fbf.tar.gz
openpam-modules-8b00f4aacb15ecad5227d1f4c5354c1938ba8fbf.tar.bz2
openpam-modules-8b00f4aacb15ecad5227d1f4c5354c1938ba8fbf.zip
Completed shadow update mechanisms for pam_unix
-rw-r--r--modules/pam_unix/pam_unix.c148
-rw-r--r--modules/pam_unix/pam_unix.c~149
2 files changed, 267 insertions, 30 deletions
diff --git a/modules/pam_unix/pam_unix.c b/modules/pam_unix/pam_unix.c
index ae824f5..dd3c519 100644
--- a/modules/pam_unix/pam_unix.c
+++ b/modules/pam_unix/pam_unix.c
@@ -3,6 +3,9 @@
#include <pwd.h>
#include <netdb.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
@@ -20,7 +23,7 @@
#include <login_cap.h> /* for BSD login classes */
#include <util.h> /* libutil functions */
#else
-#include <shadow.h> /* for linux boxes */
+#include <shadow.h>
#endif
#define PASSWORD_HASH "md5"
@@ -33,7 +36,19 @@
#include <security/pam_appl.h>
#include <security/pam_mod_misc.h>
+
+/*
+ * Helper functions for internal use
+ */
+
+#ifdef __linux__
+static int update_shadow( pam_handle_t * pamh , const char * user , const char * newhashedpwd ) ;
static char * read_shadow(const char * user) ;
+#endif
+
+static void to64(char *s, long v, int n);
+void makesalt(char salt[SALTSIZE]);
+
/*
* User authentication
*/
@@ -278,7 +293,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags ,
*/
PAM_EXTERN int
-pam_sm_chautok(pam_handle_t *pamh, int flags,
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
int argc, const char *argv[])
{
@@ -288,9 +303,11 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
*/
struct passwd *new_pwd, *old_pwd;
const char *user, *old_pass, *new_pass;
- char *hashedpwd ;
+ char *hashedpwd, salt[SALTSIZE+1];
+
#ifndef __linux__
login_cap_t * lc;
+ int pfd, tfd;
#endif
int pam_err, retries;
@@ -387,7 +404,7 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
&new_pass, NULL);
- pam_error(pamh, "Unable to get new passwd. Please \
+ PAM_ERROR("Unable to get new passwd. Please \
try again");
}
@@ -408,9 +425,6 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
!openpam_get_option(pamh, PAM_OPT_NULLOK))
return (PAM_PERM_DENIED);
-
-
-
#ifndef __linux__
/*
@@ -449,10 +463,13 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
pw_fini();
free(old_pwd);
-#endif
-
+#else
+ makesalt(salt);
+ update_shadow( pamh ,user,crypt(new_pass, salt) );
+ free(old_pwd);
/* Update shadow/passwd entries for Linux */
-
+
+#endif
} else {
pam_err = PAM_ABORT;
@@ -460,13 +477,109 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
return (pam_err);
}
+ return (PAM_SUCCESS);
+}
- return (PAM_SUCCESS);
+#ifdef __linux__
-}
+#define NEW_SHADOW "/etc/.shadow"
+/*
+ * Update shadow with new user password
+ */
+static int update_shadow( pam_handle_t * pamh , const char * user ,const char * newhashedpwd ) {
+ FILE *oldshadow, *newshadow;
+ struct spwd *pwd,*cur_pwd;
+ struct stat filestat;
+
+
+ if ( (pwd = getspnam(user)) == NULL)
+ return PAM_USER_UNKNOWN;
+
+ if ( (oldshadow = fopen ("/etc/shadow", "r")) == NULL ) {
+ PAM_ERROR("Could not open /etc/shadow. Updating shadow \
+ database cancelled.");
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if ( (newshadow = fopen (NEW_SHADOW, "w")) == NULL ) {
+ PAM_ERROR("Could not open temp file. Updating shadow \
+ database cancelled.");
+ fclose(oldshadow);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if (fstat(fileno(oldshadow), &filestat) == -1 ) {
+ PAM_ERROR("Could not get stat for /etc/shadow. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if (fchown(fileno(newshadow), filestat.st_uid, filestat.st_gid) == -1 ) {
+ PAM_ERROR("Could not set uid/gid for new shadwow file. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if (fchmod(fileno(newshadow), filestat.st_mode) == -1 ) {
+ PAM_ERROR("Could not chmod for new shadow file. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ while ( (cur_pwd = fgetspent(oldshadow)) ) {
+ if( strlen(user) == strlen(cur_pwd->sp_namp)
+ && !strncmp(cur_pwd->sp_namp, user, strlen(user))) {
+ cur_pwd->sp_pwdp = newhashedpwd;
+ cur_pwd->sp_lstchg = time(NULL) / (60 * 60 * 24);
+ PAM_LOG("Updated password for user [%s]",user);
+ }
+
+ if(putspent(cur_pwd, newshadow)) {
+ PAM_ERROR("Error writing entry to new shadow file. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+ }
+
+ fclose(oldshadow);
+
+ if (fclose(newshadow)) {
+ PAM_ERROR("Error updating new shadow file.");
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ /*
+ * If program flow has come up to here, all is good
+ * and it's safe to update the shadow file.
+ */
+
+ if( rename(NEW_SHADOW, "/etc/shadow") == 0 ) {
+ PAM_LOG("Password updated successfully for user [%s]",user);
+ } else {
+ PAM_ERROR("Error updating shadow file.");
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ return (PAM_SUCCESS);
+
+}
/*
* Read hashed password for user from shadow entry.
@@ -485,8 +598,8 @@ static char * read_shadow(const char * user) {
}
+#endif
-#ifndef __linux__
/*
* Mostly stolen from freebsd-lib's pam_unix module which was mostly
* stolen from passwd(1)'s local_passwd.c
@@ -514,8 +627,13 @@ makesalt(char salt[SALTSIZE]) {
*/
for (i = 0; i < SALTSIZE; i += 4)
-// to64(&salt[i], arc4random(), 4);
+
+#ifndef __linux__
+ to64(&salt[i], arc4random(), 4);
+#else
+ to64(&salt[i], random(), 4);
+#endif
+
salt[SALTSIZE] = '\0';
}
-#endif
PAM_MODULE_ENTRY("pam_unix")
diff --git a/modules/pam_unix/pam_unix.c~ b/modules/pam_unix/pam_unix.c~
index 79e1131..dd3c519 100644
--- a/modules/pam_unix/pam_unix.c~
+++ b/modules/pam_unix/pam_unix.c~
@@ -3,6 +3,9 @@
#include <pwd.h>
#include <netdb.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
@@ -18,8 +21,9 @@
#ifndef __linux__
#include <login_cap.h> /* for BSD login classes */
+#include <util.h> /* libutil functions */
#else
-#include <shadow.h> /* for linux boxes */
+#include <shadow.h>
#endif
#define PASSWORD_HASH "md5"
@@ -32,7 +36,19 @@
#include <security/pam_appl.h>
#include <security/pam_mod_misc.h>
+
+/*
+ * Helper functions for internal use
+ */
+
+#ifdef __linux__
+static int update_shadow( pam_handle_t * pamh , const char * user , const char * newhashedpwd ) ;
static char * read_shadow(const char * user) ;
+#endif
+
+static void to64(char *s, long v, int n);
+void makesalt(char salt[SALTSIZE]);
+
/*
* User authentication
*/
@@ -277,7 +293,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags ,
*/
PAM_EXTERN int
-pam_sm_chautok(pam_handle_t *pamh, int flags,
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
int argc, const char *argv[])
{
@@ -287,9 +303,11 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
*/
struct passwd *new_pwd, *old_pwd;
const char *user, *old_pass, *new_pass;
- char *hashedpwd ;
+ char *hashedpwd, salt[SALTSIZE+1];
+
#ifndef __linux__
login_cap_t * lc;
+ int pfd, tfd;
#endif
int pam_err, retries;
@@ -386,7 +404,7 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
&new_pass, NULL);
- pam_error(pamh, "Unable to get new passwd. Please \
+ PAM_ERROR("Unable to get new passwd. Please \
try again");
}
@@ -407,9 +425,6 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
!openpam_get_option(pamh, PAM_OPT_NULLOK))
return (PAM_PERM_DENIED);
-
-
-
#ifndef __linux__
/*
@@ -448,10 +463,13 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
pw_fini();
free(old_pwd);
-#endif
-
+#else
+ makesalt(salt);
+ update_shadow( pamh ,user,crypt(new_pass, salt) );
+ free(old_pwd);
/* Update shadow/passwd entries for Linux */
-
+
+#endif
} else {
pam_err = PAM_ABORT;
@@ -459,13 +477,109 @@ pam_sm_chautok(pam_handle_t *pamh, int flags,
return (pam_err);
}
+ return (PAM_SUCCESS);
+}
- return (PAM_SUCCESS);
+#ifdef __linux__
-}
+#define NEW_SHADOW "/etc/.shadow"
+/*
+ * Update shadow with new user password
+ */
+static int update_shadow( pam_handle_t * pamh , const char * user ,const char * newhashedpwd ) {
+ FILE *oldshadow, *newshadow;
+ struct spwd *pwd,*cur_pwd;
+ struct stat filestat;
+
+
+ if ( (pwd = getspnam(user)) == NULL)
+ return PAM_USER_UNKNOWN;
+
+ if ( (oldshadow = fopen ("/etc/shadow", "r")) == NULL ) {
+ PAM_ERROR("Could not open /etc/shadow. Updating shadow \
+ database cancelled.");
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if ( (newshadow = fopen (NEW_SHADOW, "w")) == NULL ) {
+ PAM_ERROR("Could not open temp file. Updating shadow \
+ database cancelled.");
+ fclose(oldshadow);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if (fstat(fileno(oldshadow), &filestat) == -1 ) {
+ PAM_ERROR("Could not get stat for /etc/shadow. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if (fchown(fileno(newshadow), filestat.st_uid, filestat.st_gid) == -1 ) {
+ PAM_ERROR("Could not set uid/gid for new shadwow file. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ if (fchmod(fileno(newshadow), filestat.st_mode) == -1 ) {
+ PAM_ERROR("Could not chmod for new shadow file. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ while ( (cur_pwd = fgetspent(oldshadow)) ) {
+ if( strlen(user) == strlen(cur_pwd->sp_namp)
+ && !strncmp(cur_pwd->sp_namp, user, strlen(user))) {
+ cur_pwd->sp_pwdp = newhashedpwd;
+ cur_pwd->sp_lstchg = time(NULL) / (60 * 60 * 24);
+ PAM_LOG("Updated password for user [%s]",user);
+ }
+
+ if(putspent(cur_pwd, newshadow)) {
+ PAM_ERROR("Error writing entry to new shadow file. \
+ Updating shadow database cancelled.");
+ fclose(oldshadow);
+ fclose(newshadow);
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+ }
+
+ fclose(oldshadow);
+
+ if (fclose(newshadow)) {
+ PAM_ERROR("Error updating new shadow file.");
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ /*
+ * If program flow has come up to here, all is good
+ * and it's safe to update the shadow file.
+ */
+
+ if( rename(NEW_SHADOW, "/etc/shadow") == 0 ) {
+ PAM_LOG("Password updated successfully for user [%s]",user);
+ } else {
+ PAM_ERROR("Error updating shadow file.");
+ unlink(NEW_SHADOW);
+ return (PAM_AUTHTOK_ERR);
+ }
+
+ return (PAM_SUCCESS);
+
+}
/*
* Read hashed password for user from shadow entry.
@@ -484,8 +598,8 @@ static char * read_shadow(const char * user) {
}
+#endif
-#ifndef __linux__
/*
* Mostly stolen from freebsd-lib's pam_unix module which was mostly
* stolen from passwd(1)'s local_passwd.c
@@ -513,8 +627,13 @@ makesalt(char salt[SALTSIZE]) {
*/
for (i = 0; i < SALTSIZE; i += 4)
-// to64(&salt[i], arc4random(), 4);
+
+#ifndef __linux__
+ to64(&salt[i], arc4random(), 4);
+#else
+ to64(&salt[i], random(), 4);
+#endif
+
salt[SALTSIZE] = '\0';
}
-#endif
PAM_MODULE_ENTRY("pam_unix")