summaryrefslogtreecommitdiff
path: root/modules/pam_unix/unix_chkpwd.c
diff options
context:
space:
mode:
authorTomas Mraz <tm@t8m.info>2008-01-04 17:46:45 +0000
committerTomas Mraz <tm@t8m.info>2008-01-04 17:46:45 +0000
commitc8c84e2bf94a4172ad104212e0cd739dbf12eb49 (patch)
tree5c1603c33f36e90308db8d0cb7cb21570774730d /modules/pam_unix/unix_chkpwd.c
parentc6912ac61ece224b03cf81499cf6d76add564c8a (diff)
downloadlinux-pam-git-pam_unix_ref_branch.tar.gz
Relevant BUGIDs:pam_unix_ref_branch
Purpose of commit: new feature Commit summary: --------------- * modules/pam_unix/Makefile.am: Add unix_update helper. * modules/pam_unix/pam_unix_passwd.c: Move functions i64c(), crypt_md5_wrapper(), save_old_password(), _update_passwd() and _update_shadow() to passverify.c file. Rename _unix_run_shadow_binary() to _unix_run_update_binary(), which also verifies old password and does all writing. (_do_setpass, pam_sm_chauthtok): lckpwdf()->lock_pwdf(), the same for unlock. Call _unix_run_update_binary() appropriately. _update_passwd()->unix_update_passwd(), the same for shadow. * modules/pam_unix/passverify.c: Add new functions moved from pam_unix_passwd.c and unix_chkpwd.c. * modules/pam_unix/passverify.h: Likewise. * modules/pam_unix/unix_chkpwd.c: Remove SELinux checks. Move su_sighandler(), setup_signals(), getuidname() to passverify.c. (main): Remove 'shadow' option. Refactor out read_passwords() and call it. More strict checking how the binary is called. * modules/pam_unix/unix_update.c: New helper binary - non-setuid, called from SELinux confined apps only.
Diffstat (limited to 'modules/pam_unix/unix_chkpwd.c')
-rw-r--r--modules/pam_unix/unix_chkpwd.c277
1 files changed, 17 insertions, 260 deletions
diff --git a/modules/pam_unix/unix_chkpwd.c b/modules/pam_unix/unix_chkpwd.c
index b6508b87..11ac3aac 100644
--- a/modules/pam_unix/unix_chkpwd.c
+++ b/modules/pam_unix/unix_chkpwd.c
@@ -24,61 +24,12 @@
#include <shadow.h>
#include <signal.h>
#include <time.h>
-#ifdef WITH_SELINUX
-#include <selinux/selinux.h>
-#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0))
-static security_context_t prev_context=NULL;
-static int selinux_enabled=-1;
-#else
-#define SELINUX_ENABLED 0
-#endif
-
-#define MAXPASS 200 /* the maximum length of a password */
#include <security/_pam_types.h>
#include <security/_pam_macros.h>
#include "passverify.h"
-/* syslogging function for errors and other information */
-
-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) {
- helper_log_err(LOG_NOTICE, "caught signal %d.", sig);
- exit(sig);
- }
-}
-
-static void setup_signals(void)
-{
- struct sigaction action; /* posix signal structure */
-
- /*
- * Setup signal handlers
- */
- (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);
- (void) sigaction(SIGSEGV, &action, NULL);
- action.sa_handler = SIG_IGN;
- action.sa_flags = 0;
- (void) sigaction(SIGTERM, &action, NULL);
- (void) sigaction(SIGHUP, &action, NULL);
- (void) sigaction(SIGINT, &action, NULL);
- (void) sigaction(SIGQUIT, &action, NULL);
-}
-
static int _check_expiry(const char *uname)
{
struct spwd *spent;
@@ -103,190 +54,15 @@ static int _check_expiry(const char *uname)
return retval;
}
-static char *getuidname(uid_t uid)
-{
- struct passwd *pw;
- static char username[32];
-
- pw = getpwuid(uid);
- if (pw == NULL)
- return NULL;
-
- strncpy(username, pw->pw_name, sizeof(username));
- username[sizeof(username) - 1] = '\0';
-
- return username;
-}
-
-#define SH_TMPFILE "/etc/nshadow"
-static int _update_shadow(const char *forwho)
-{
- struct spwd *spwdent = NULL, *stmpent = NULL;
- FILE *pwfile, *opwfile;
- int err = 1;
- int oldmask;
- struct stat st;
- char pass[MAXPASS + 1];
- char towhat[MAXPASS + 1];
- int npass=0;
-
- /* read the password from stdin (a pipe from the pam_unix module) */
-
- npass = read(STDIN_FILENO, pass, MAXPASS);
-
- if (npass < 0) { /* is it a valid password? */
-
- helper_log_err(LOG_DEBUG, "no password supplied");
- return PAM_AUTHTOK_ERR;
-
- } else if (npass >= MAXPASS) {
-
- helper_log_err(LOG_DEBUG, "password too long");
- return PAM_AUTHTOK_ERR;
-
- } else {
- /* does pass agree with the official one? */
- int retval=0;
- pass[npass] = '\0'; /* NUL terminate */
- retval = helper_verify_password(forwho, pass, 0);
- if (retval != PAM_SUCCESS) {
- return retval;
- }
- }
-
- /* read the password from stdin (a pipe from the pam_unix module) */
-
- npass = read(STDIN_FILENO, towhat, MAXPASS);
-
- if (npass < 0) { /* is it a valid password? */
-
- helper_log_err(LOG_DEBUG, "no new password supplied");
- return PAM_AUTHTOK_ERR;
-
- } else if (npass >= MAXPASS) {
-
- helper_log_err(LOG_DEBUG, "new password too long");
- return PAM_AUTHTOK_ERR;
-
- }
-
- towhat[npass] = '\0'; /* NUL terminate */
- spwdent = getspnam(forwho);
- if (spwdent == NULL) {
- return PAM_USER_UNKNOWN;
- }
- oldmask = umask(077);
-
-#ifdef WITH_SELINUX
- if (SELINUX_ENABLED) {
- security_context_t shadow_context=NULL;
- if (getfilecon("/etc/shadow",&shadow_context)<0) {
- return PAM_AUTHTOK_ERR;
- };
- if (getfscreatecon(&prev_context)<0) {
- freecon(shadow_context);
- return PAM_AUTHTOK_ERR;
- }
- if (setfscreatecon(shadow_context)) {
- freecon(shadow_context);
- freecon(prev_context);
- return PAM_AUTHTOK_ERR;
- }
- freecon(shadow_context);
- }
-#endif
- pwfile = fopen(SH_TMPFILE, "w");
- umask(oldmask);
- if (pwfile == NULL) {
- err = 1;
- goto done;
- }
-
- opwfile = fopen("/etc/shadow", "r");
- if (opwfile == NULL) {
- fclose(pwfile);
- err = 1;
- goto done;
- }
-
- if (fstat(fileno(opwfile), &st) == -1) {
- fclose(opwfile);
- fclose(pwfile);
- err = 1;
- goto done;
- }
-
- if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
- fclose(opwfile);
- fclose(pwfile);
- err = 1;
- goto done;
- }
- if (fchmod(fileno(pwfile), st.st_mode) == -1) {
- fclose(opwfile);
- fclose(pwfile);
- err = 1;
- goto done;
- }
-
- stmpent = fgetspent(opwfile);
- while (stmpent) {
-
- if (!strcmp(stmpent->sp_namp, forwho)) {
- stmpent->sp_pwdp = towhat;
- stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
- err = 0;
- D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
- }
-
- if (putspent(stmpent, pwfile)) {
- D(("error writing entry to shadow file: %m"));
- err = 1;
- break;
- }
-
- stmpent = fgetspent(opwfile);
- }
- fclose(opwfile);
-
- if (fclose(pwfile)) {
- D(("error writing entries to shadow file: %m"));
- err = 1;
- }
-
- done:
- if (!err) {
- if (rename(SH_TMPFILE, "/etc/shadow"))
- err = 1;
- }
-
-#ifdef WITH_SELINUX
- if (SELINUX_ENABLED) {
- if (setfscreatecon(prev_context)) {
- err = 1;
- }
- if (prev_context)
- freecon(prev_context);
- prev_context=NULL;
- }
-#endif
-
- if (!err) {
- return PAM_SUCCESS;
- } else {
- unlink(SH_TMPFILE);
- return PAM_AUTHTOK_ERR;
- }
-}
-
int main(int argc, char *argv[])
{
char pass[MAXPASS + 1];
char *option;
int npass, nullok;
- int blankpass;
+ int blankpass = 0;
int retval = PAM_AUTH_ERR;
char *user;
+ char *passwords[] = { pass };
/*
* Catch or ignore as many signal as possible.
@@ -331,51 +107,32 @@ int main(int argc, char *argv[])
option=argv[2];
- if (strncmp(argv[2], "chkexpiry", 8) == 0) {
+ if (strcmp(option, "chkexpiry") == 0)
/* Check account information from the shadow file */
- return _check_expiry(argv[1]);
-
- }
-
- if (strncmp(option, "shadow", 8) == 0) {
- /* Attempting to change the password */
- return _update_shadow(argv[1]);
- }
-
+ return _check_expiry(argv[1]);
/* read the nullok/nonull option */
- if (strncmp(option, "nullok", 8) == 0)
+ else if (strcmp(option, "nullok") == 0)
nullok = 1;
- else
+ else if (strcmp(option, "nonull") == 0)
nullok = 0;
+ else
+ return PAM_SYSTEM_ERR;
/* read the password from stdin (a pipe from the pam_unix module) */
- npass = read(STDIN_FILENO, pass, MAXPASS);
-
- if (npass < 0) { /* is it a valid password? */
+ npass = read_passwords(STDIN_FILENO, 1, passwords);
+ if (npass != 1) { /* is it a valid password? */
helper_log_err(LOG_DEBUG, "no password supplied");
+ *pass = '\0';
+ }
- } else if (npass >= MAXPASS) {
-
- helper_log_err(LOG_DEBUG, "password too long");
-
- } else {
- if (npass == 0) {
- /* the password is NULL */
- blankpass = 1;
- retval = helper_verify_password(user, NULL, nullok);
-
- } else {
- /* does pass agree with the official one? */
- if (pass[0] == '\0')
- blankpass = 1;
- pass[npass] = '\0'; /* NUL terminate */
- retval = helper_verify_password(user, pass, nullok);
-
- }
+ if (*pass == '\0') {
+ blankpass = 1;
}
+ retval = helper_verify_password(user, pass, nullok);
+
memset(pass, '\0', MAXPASS); /* clear memory of the password */
/* return pass or fail */
@@ -392,7 +149,7 @@ int main(int argc, char *argv[])
/*
* Copyright (c) Andrew G. Morgan, 1996. All rights reserved
- * Copyright (c) Red Hat, Inc., 2007. All rights reserved
+ * Copyright (c) Red Hat, Inc., 2007,2008. All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions