diff options
Diffstat (limited to 'modules/pam_unix/unix_chkpwd.c')
-rw-r--r-- | modules/pam_unix/unix_chkpwd.c | 566 |
1 files changed, 0 insertions, 566 deletions
diff --git a/modules/pam_unix/unix_chkpwd.c b/modules/pam_unix/unix_chkpwd.c deleted file mode 100644 index 87d29256..00000000 --- a/modules/pam_unix/unix_chkpwd.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * This program is designed to run setuid(root) or with sufficient - * privilege to read all of the unix password databases. It is designed - * to provide a mechanism for the current user (defined by this - * process' uid) to verify their own password. - * - * The password is read from the standard input. The exit status of - * this program indicates whether the user is authenticated or not. - * - * Copyright information is located at the end of the file. - * - */ - -#include "config.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <pwd.h> -#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 "md5.h" -#include "bigcrypt.h" - -/* syslogging function for errors and other information */ - -static void _log_err(int err, const char *format,...) -{ - va_list args; - - va_start(args, format); - openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTHPRIV); - vsyslog(err, format, args); - va_end(args); - 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); - } -} - -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 _verify_account(const char * const uname) -{ - struct spwd *spent; - struct passwd *pwent; - - pwent = getpwnam(uname); - if (!pwent) { - _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname); - return PAM_USER_UNKNOWN; - } - - spent = getspnam( uname ); - if (!spent) { - _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname); - return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ - } - printf("%ld:%ld:%ld:%ld:%ld:%ld", - spent->sp_lstchg, /* last password change */ - spent->sp_min, /* days until change allowed. */ - spent->sp_max, /* days before change required */ - spent->sp_warn, /* days warning for expiration */ - spent->sp_inact, /* days before account inactive */ - spent->sp_expire); /* date when account expires */ - - return PAM_SUCCESS; -} - -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 = PAM_AUTH_ERR; - int salt_len; - - /* UNIX passwords area */ - setpwent(); - pwd = getpwnam(name); /* Get password file entry... */ - endpwent(); - if (pwd != NULL) { - if (_unix_shadowed(pwd)) { - /* - * ...and shadow password file entry for this user, - * if shadowing is enabled - */ - setspent(); - spwdent = getspnam(name); - endspent(); - if (spwdent != NULL) - salt = x_strdup(spwdent->sp_pwdp); - else - pwd = NULL; - } else { - if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ - uid_t save_uid; - - save_uid = geteuid(); - seteuid(pwd->pw_uid); - spwdent = getspnam(name); - seteuid(save_uid); - - salt = x_strdup(spwdent->sp_pwdp); - } else { - salt = x_strdup(pwd->pw_passwd); - } - } - } - if (pwd == NULL || salt == NULL) { - _log_err(LOG_ALERT, "check pass; user unknown"); - p = NULL; - return PAM_USER_UNKNOWN; - } - - salt_len = strlen(salt); - if (salt_len == 0) { - return (nullok == 0) ? PAM_AUTH_ERR : PAM_SUCCESS; - } - if (p == NULL || strlen(p) == 0) { - return PAM_AUTHTOK_ERR; - } - - /* the moment of truth -- do we agree with the password? */ - retval = PAM_AUTH_ERR; - if (!strncmp(salt, "$1$", 3)) { - pp = Goodcrypt_md5(p, salt); - if (strcmp(pp, salt) == 0) { - retval = PAM_SUCCESS; - } else { - pp = Brokencrypt_md5(p, salt); - if (strcmp(pp, salt) == 0) - retval = PAM_SUCCESS; - } - } else if (*salt == '$') { - /* - * Ok, we don't know the crypt algorithm, but maybe - * libcrypt nows about it? We should try it. - */ - pp = x_strdup (crypt(p, salt)); - if (strcmp(pp, salt) == 0) { - retval = PAM_SUCCESS; - } - } else if ((*salt == '*') || (salt_len < 13)) { - retval = PAM_AUTH_ERR; - } else { - pp = bigcrypt(p, 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, salt_len) == 0) { - retval = PAM_SUCCESS; - } - } - p = NULL; /* no longer needed here */ - - /* clean up */ - { - char *tp = pp; - if (pp != NULL) { - while (tp && *tp) - *tp++ = '\0'; - free(pp); - } - pp = tp = NULL; - } - - 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? */ - - _log_err(LOG_DEBUG, "no password supplied"); - return PAM_AUTHTOK_ERR; - - } else if (npass >= MAXPASS) { - - _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 = _unix_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? */ - - _log_err(LOG_DEBUG, "no new password supplied"); - return PAM_AUTHTOK_ERR; - - } else if (npass >= MAXPASS) { - - _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 force_failure = 0; - int retval = PAM_AUTH_ERR; - char *user; - - /* - * Catch or ignore as many signal as possible. - */ - setup_signals(); - - /* - * we establish that this program is running with non-tty stdin. - * this is to discourage casual use. It does *NOT* prevent an - * intruder from repeatadly running this program to determine the - * password of the current user (brute force attack, but one for - * which the attacker must already have gained access to the user's - * account). - */ - - if (isatty(STDIN_FILENO) || argc != 3 ) { - _log_err(LOG_NOTICE - ,"inappropriate use of Unix helper binary [UID=%d]" - ,getuid()); - fprintf(stderr - ,"This binary is not designed for running in this way\n" - "-- the system administrator has been informed\n"); - sleep(10); /* this should discourage/annoy the user */ - return PAM_SYSTEM_ERR; - } - - /* - * Determine what the current user's name is. - * On a SELinux enabled system with a strict policy leaving the - * existing check prevents shadow password authentication from working. - * We must thus skip the check if the real uid is 0. - */ - if (SELINUX_ENABLED && getuid() == 0) { - user=argv[1]; - } - else { - user = getuidname(getuid()); - /* if the caller specifies the username, verify that user - matches it */ - if (strcmp(user, argv[1])) { - return PAM_AUTH_ERR; - } - } - - option=argv[2]; - - if (strncmp(argv[2], "verify", 8) == 0) { - /* Get the account information from the shadow file */ - return _verify_account(argv[1]); - } - - if (strncmp(option, "shadow", 8) == 0) { - /* Attempting to change the password */ - return _update_shadow(argv[1]); - } - - /* read the nullok/nonull option */ - if (strncmp(option, "nullok", 8) == 0) - nullok = 1; - else - nullok = 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? */ - - _log_err(LOG_DEBUG, "no password supplied"); - - } else if (npass >= MAXPASS) { - - _log_err(LOG_DEBUG, "password too long"); - - } else { - if (npass == 0) { - /* the password is NULL */ - - 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, nullok); - - } - } - - memset(pass, '\0', MAXPASS); /* clear memory of the password */ - - /* return pass or fail */ - - if ((retval != PAM_SUCCESS) || force_failure) { - _log_err(LOG_NOTICE, "password check failed for user (%s)", user); - return PAM_AUTH_ERR; - } else { - return PAM_SUCCESS; - } -} - -/* - * Copyright (c) Andrew G. Morgan, 1996. All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 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 - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ |