summaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'Linux-PAM/modules/pam_unix/pam_unix_passwd.c')
-rw-r--r--Linux-PAM/modules/pam_unix/pam_unix_passwd.c802
1 files changed, 0 insertions, 802 deletions
diff --git a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
deleted file mode 100644
index 432f687f..00000000
--- a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
- * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
- * Copyright (C) 1996.
- * Copyright (c) Jan Rêkorajski, 1999.
- * Copyright (c) Red Hat, Inc., 2007, 2008.
- *
- * 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.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <syslog.h>
-#include <shadow.h>
-#include <time.h> /* for time() */
-#include <fcntl.h>
-#include <ctype.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
-#include <rpcsvc/ypclnt.h>
-
-#include <signal.h>
-#include <errno.h>
-#include <sys/wait.h>
-#ifdef WITH_SELINUX
-static int selinux_enabled=-1;
-#include <selinux/selinux.h>
-#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0))
-#endif
-
-#ifdef USE_CRACKLIB
-#include <crack.h>
-#endif
-
-#include <security/_pam_macros.h>
-
-/* indicate the following groups are defined */
-
-#define PAM_SM_PASSWORD
-
-#include <security/pam_modules.h>
-#include <security/pam_ext.h>
-#include <security/pam_modutil.h>
-
-#include "yppasswd.h"
-#include "md5.h"
-#include "support.h"
-#include "passverify.h"
-#include "bigcrypt.h"
-
-#if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
-extern int getrpcport(const char *host, unsigned long prognum,
- unsigned long versnum, unsigned int proto);
-#endif /* GNU libc 2.1 */
-
-/*
- How it works:
- Gets in username (has to be done) from the calling program
- Does authentication of user (only if we are not running as root)
- Gets new password/checks for sanity
- Sets it.
- */
-
-/* data tokens */
-
-#define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS"
-#define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS"
-
-#define MAX_PASSWD_TRIES 3
-#ifndef CRACKLIB_DICTS
-#define CRACKLIB_DICTS NULL
-#endif
-
-static char *getNISserver(pam_handle_t *pamh)
-{
- char *master;
- char *domainname;
- int port, err;
-
- if ((err = yp_get_default_domain(&domainname)) != 0) {
- pam_syslog(pamh, LOG_WARNING, "can't get local yp domain: %s",
- yperr_string(err));
- return NULL;
- }
- if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) {
- pam_syslog(pamh, LOG_WARNING, "can't find the master ypserver: %s",
- yperr_string(err));
- return NULL;
- }
- port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP);
- if (port == 0) {
- pam_syslog(pamh, LOG_WARNING,
- "yppasswdd not running on NIS master host");
- return NULL;
- }
- if (port >= IPPORT_RESERVED) {
- pam_syslog(pamh, LOG_WARNING,
- "yppasswd daemon running on illegal port");
- return NULL;
- }
- return master;
-}
-
-#ifdef WITH_SELINUX
-
-static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user,
- const char *fromwhat, const char *towhat, int remember)
-{
- int retval, child, fds[2];
- void (*sighandler)(int) = NULL;
-
- D(("called."));
- /* create a pipe for the password */
- if (pipe(fds) != 0) {
- D(("could not make pipe"));
- 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) {
- size_t i=0;
- struct rlimit rlim;
- static char *envp[] = { NULL };
- char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL };
- char buffer[16];
-
- /* XXX - should really tidy up PAM here too */
-
- close(0); close(1);
- /* reopen stdin as pipe */
- close(fds[1]);
- dup2(fds[0], STDIN_FILENO);
-
- if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
- for (i=2; i < rlim.rlim_max; i++) {
- if ((unsigned int)fds[0] != i)
- close(i);
- }
- }
-
- if (SELINUX_ENABLED && geteuid() == 0) {
- /* must set the real uid to 0 so the helper will not error
- out if pam is called from setuid binary (su, sudo...) */
- setuid(0);
- }
-
- /* exec binary helper */
- args[0] = x_strdup(UPDATE_HELPER);
- args[1] = x_strdup(user);
- args[2] = x_strdup("update");
- if (on(UNIX_SHADOW, ctrl))
- args[3] = x_strdup("1");
- else
- args[3] = x_strdup("0");
-
- snprintf(buffer, sizeof(buffer), "%d", remember);
- args[4] = x_strdup(buffer);
-
- execve(UPDATE_HELPER, args, envp);
-
- /* should not get here: exit with error */
- D(("helper binary is not available"));
- exit(PAM_AUTHINFO_UNAVAIL);
- } else if (child > 0) {
- /* wait for child */
- /* if the stored password is NULL */
- int rc=0;
- if (fromwhat)
- pam_modutil_write(fds[1], fromwhat, strlen(fromwhat)+1);
- else
- pam_modutil_write(fds[1], "", 1);
- if (towhat) {
- pam_modutil_write(fds[1], towhat, strlen(towhat)+1);
- }
- else
- pam_modutil_write(fds[1], "", 1);
-
- close(fds[0]); /* close here to avoid possible SIGPIPE above */
- close(fds[1]);
- rc=waitpid(child, &retval, 0); /* wait for helper to complete */
- if (rc<0) {
- pam_syslog(pamh, LOG_ERR, "unix_update waitpid failed: %m");
- retval = PAM_AUTH_ERR;
- } else {
- retval = WEXITSTATUS(retval);
- }
- } else {
- D(("fork failed"));
- close(fds[0]);
- close(fds[1]);
- retval = PAM_AUTH_ERR;
- }
-
- if (sighandler != SIG_ERR) {
- (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
- }
-
- return retval;
-}
-#endif
-
-static int check_old_password(const char *forwho, const char *newpass)
-{
- static char buf[16384];
- char *s_luser, *s_uid, *s_npas, *s_pas;
- int retval = PAM_SUCCESS;
- FILE *opwfile;
-
- opwfile = fopen(OLD_PASSWORDS_FILE, "r");
- if (opwfile == NULL)
- return PAM_ABORT;
-
- while (fgets(buf, 16380, opwfile)) {
- if (!strncmp(buf, forwho, strlen(forwho))) {
- char *sptr;
- buf[strlen(buf) - 1] = '\0';
- s_luser = strtok_r(buf, ":,", &sptr);
- s_uid = strtok_r(NULL, ":,", &sptr);
- s_npas = strtok_r(NULL, ":,", &sptr);
- s_pas = strtok_r(NULL, ":,", &sptr);
- while (s_pas != NULL) {
- char *md5pass = Goodcrypt_md5(newpass, s_pas);
- if (!strcmp(md5pass, s_pas)) {
- _pam_delete(md5pass);
- retval = PAM_AUTHTOK_ERR;
- break;
- }
- s_pas = strtok_r(NULL, ":,", &sptr);
- _pam_delete(md5pass);
- }
- break;
- }
- }
- fclose(opwfile);
-
- return retval;
-}
-
-static int _do_setpass(pam_handle_t* pamh, const char *forwho,
- const char *fromwhat,
- char *towhat, unsigned int ctrl, int remember)
-{
- struct passwd *pwd = NULL;
- int retval = 0;
- int unlocked = 0;
- char *master = NULL;
-
- D(("called"));
-
- pwd = getpwnam(forwho);
-
- if (pwd == NULL) {
- retval = PAM_AUTHTOK_ERR;
- goto done;
- }
-
- if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
- if ((master=getNISserver(pamh)) != NULL) {
- struct timeval timeout;
- struct yppasswd yppwd;
- CLIENT *clnt;
- int status;
- enum clnt_stat err;
-
- /* Unlock passwd file to avoid deadlock */
- unlock_pwdf();
- unlocked = 1;
-
- /* Initialize password information */
- yppwd.newpw.pw_passwd = pwd->pw_passwd;
- yppwd.newpw.pw_name = pwd->pw_name;
- yppwd.newpw.pw_uid = pwd->pw_uid;
- yppwd.newpw.pw_gid = pwd->pw_gid;
- yppwd.newpw.pw_gecos = pwd->pw_gecos;
- yppwd.newpw.pw_dir = pwd->pw_dir;
- yppwd.newpw.pw_shell = pwd->pw_shell;
- yppwd.oldpass = fromwhat ? strdup (fromwhat) : strdup ("");
- yppwd.newpw.pw_passwd = towhat;
-
- D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));
-
- /* The yppasswd.x file said `unix authentication required',
- * so I added it. This is the only reason it is in here.
- * My yppasswdd doesn't use it, but maybe some others out there
- * do. --okir
- */
- clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
- clnt->cl_auth = authunix_create_default();
- memset((char *) &status, '\0', sizeof(status));
- timeout.tv_sec = 25;
- timeout.tv_usec = 0;
- err = clnt_call(clnt, YPPASSWDPROC_UPDATE,
- (xdrproc_t) xdr_yppasswd, (char *) &yppwd,
- (xdrproc_t) xdr_int, (char *) &status,
- timeout);
-
- free (yppwd.oldpass);
-
- if (err) {
- _make_remark(pamh, ctrl, PAM_TEXT_INFO,
- clnt_sperrno(err));
- } else if (status) {
- D(("Error while changing NIS password.\n"));
- }
- D(("The password has%s been changed on %s.",
- (err || status) ? " not" : "", master));
- pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s",
- (err || status) ? " not" : "", pwd->pw_name, master);
-
- auth_destroy(clnt->cl_auth);
- clnt_destroy(clnt);
- if (err || status) {
- _make_remark(pamh, ctrl, PAM_TEXT_INFO,
- _("NIS password could not be changed."));
- retval = PAM_TRY_AGAIN;
- }
-#ifdef DEBUG
- sleep(5);
-#endif
- } else {
- retval = PAM_TRY_AGAIN;
- }
- }
-
- if (_unix_comesfromsource(pamh, forwho, 1, 0)) {
- if(unlocked) {
- if (lock_pwdf() != PAM_SUCCESS) {
- return PAM_AUTHTOK_LOCK_BUSY;
- }
- }
-#ifdef WITH_SELINUX
- if (unix_selinux_confined())
- return _unix_run_update_binary(pamh, ctrl, forwho, fromwhat, towhat, remember);
-#endif
- /* first, save old password */
- if (save_old_password(forwho, fromwhat, remember)) {
- retval = PAM_AUTHTOK_ERR;
- goto done;
- }
- if (on(UNIX_SHADOW, ctrl) || is_pwd_shadowed(pwd)) {
- retval = unix_update_shadow(pamh, forwho, towhat);
- if (retval == PAM_SUCCESS)
- if (!is_pwd_shadowed(pwd))
- retval = unix_update_passwd(pamh, forwho, "x");
- } else {
- retval = unix_update_passwd(pamh, forwho, towhat);
- }
- }
-
-
-done:
- unlock_pwdf();
-
- return retval;
-}
-
-static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned int ctrl)
-{
- struct passwd *pwent = NULL; /* Password and shadow password */
- struct spwd *spent = NULL; /* file entries for the user */
- int daysleft;
- int retval;
-
- retval = get_account_info(pamh, user, &pwent, &spent);
- if (retval == PAM_USER_UNKNOWN) {
- return retval;
- }
-
- if (retval == PAM_SUCCESS && spent == NULL)
- return PAM_SUCCESS;
-
- if (retval == PAM_UNIX_RUN_HELPER) {
- retval = _unix_run_verify_binary(pamh, ctrl, user, &daysleft);
- if (retval == PAM_AUTH_ERR || retval == PAM_USER_UNKNOWN)
- return retval;
- }
- else if (retval == PAM_SUCCESS)
- retval = check_shadow_expiry(pamh, spent, &daysleft);
-
- if (on(UNIX__IAMROOT, ctrl) || retval == PAM_NEW_AUTHTOK_REQD)
- return PAM_SUCCESS;
-
- return retval;
-}
-
-static int _pam_unix_approve_pass(pam_handle_t * pamh
- ,unsigned int ctrl
- ,const char *pass_old
- ,const char *pass_new)
-{
- const void *user;
- const char *remark = NULL;
- int retval = PAM_SUCCESS;
-
- D(("&new=%p, &old=%p", pass_old, pass_new));
- D(("new=[%s]", pass_new));
- D(("old=[%s]", pass_old));
-
- if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) {
- if (on(UNIX_DEBUG, ctrl)) {
- pam_syslog(pamh, LOG_DEBUG, "bad authentication token");
- }
- _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
- _("No password supplied") : _("Password unchanged"));
- return PAM_AUTHTOK_ERR;
- }
- /*
- * if one wanted to hardwire authentication token strength
- * checking this would be the place - AGM
- */
-
- retval = pam_get_item(pamh, PAM_USER, &user);
- if (retval != PAM_SUCCESS) {
- if (on(UNIX_DEBUG, ctrl)) {
- pam_syslog(pamh, LOG_ERR, "Can not get username");
- return PAM_AUTHTOK_ERR;
- }
- }
- if (off(UNIX__IAMROOT, ctrl)) {
-#ifdef USE_CRACKLIB
- remark = FascistCheck (pass_new, CRACKLIB_DICTS);
- D(("called cracklib [%s]", remark));
-#else
- if (strlen(pass_new) < 6)
- remark = _("You must choose a longer password");
- D(("length check [%s]", remark));
-#endif
- 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) {
- pam_syslog(pamh, LOG_ERR, "can't open %s file to check old passwords",
- OLD_PASSWORDS_FILE);
- return retval;
- }
- }
- }
- if (remark) {
- _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
- retval = PAM_AUTHTOK_ERR;
- }
- return retval;
-}
-
-
-PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
- int argc, const char **argv)
-{
- unsigned int ctrl, lctrl;
- int retval;
- int remember = -1;
- int rounds = -1;
-
- /* <DO NOT free() THESE> */
- const char *user;
- const void *pass_old, *pass_new;
- /* </DO NOT free() THESE> */
-
- D(("called."));
-
- ctrl = _set_ctrl(pamh, flags, &remember, &rounds, argc, argv);
-
- /*
- * First get the name of a user
- */
- retval = pam_get_user(pamh, &user, NULL);
- if (retval == PAM_SUCCESS) {
- /*
- * Various libraries at various times have had bugs related to
- * '+' or '-' as the first character of a user name. Don't
- * allow them.
- */
- if (user == NULL || user[0] == '-' || user[0] == '+') {
- pam_syslog(pamh, LOG_ERR, "bad username [%s]", user);
- return PAM_USER_UNKNOWN;
- }
- if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl))
- pam_syslog(pamh, LOG_DEBUG, "username [%s] obtained",
- user);
- } else {
- if (on(UNIX_DEBUG, ctrl))
- pam_syslog(pamh, LOG_DEBUG,
- "password - could not identify user");
- 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, on(UNIX_NIS, ctrl)) == 0) {
- pam_syslog(pamh, LOG_DEBUG,
- "user \"%s\" does not exist in /etc/passwd%s",
- user, on(UNIX_NIS, ctrl) ? " or NIS" : "");
- return PAM_USER_UNKNOWN;
- } else {
- struct passwd *pwd;
- _unix_getpwnam(pamh, user, 1, 1, &pwd);
- if (pwd == NULL) {
- pam_syslog(pamh, LOG_DEBUG,
- "user \"%s\" has corrupted passwd entry",
- user);
- return PAM_USER_UNKNOWN;
- }
- }
-
- /*
- * This is not an AUTH module!
- */
- if (on(UNIX__NONULL, ctrl))
- set(UNIX__NULLOK, ctrl);
-
- if (on(UNIX__PRELIM, ctrl)) {
- /*
- * obtain and verify the current password (OLDAUTHTOK) for
- * the user.
- */
- char *Announce;
-
- D(("prelim check"));
-
- if (_unix_blankpasswd(pamh, ctrl, user)) {
- return PAM_SUCCESS;
- } else if (off(UNIX__IAMROOT, ctrl)) {
- /* instruct user what is happening */
- if (asprintf(&Announce, _("Changing password for %s."),
- user) < 0) {
- pam_syslog(pamh, LOG_CRIT,
- "password - out of memory");
- return PAM_BUF_ERR;
- }
-
- lctrl = ctrl;
- set(UNIX__OLD_PASSWD, lctrl);
- retval = _unix_read_password(pamh, lctrl
- ,Announce
- ,_("(current) UNIX password: ")
- ,NULL
- ,_UNIX_OLD_AUTHTOK
- ,&pass_old);
- free(Announce);
-
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_NOTICE,
- "password - (old) token not obtained");
- return retval;
- }
- /* verify that this is the password for this user */
-
- retval = _unix_verify_password(pamh, user, pass_old, ctrl);
- } else {
- D(("process run by root so do nothing this time around"));
- pass_old = NULL;
- retval = PAM_SUCCESS; /* root doesn't have too */
- }
-
- if (retval != PAM_SUCCESS) {
- D(("Authentication failed"));
- pass_old = NULL;
- return retval;
- }
- retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
- pass_old = NULL;
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_CRIT,
- "failed to set PAM_OLDAUTHTOK");
- }
- retval = _unix_verify_shadow(pamh,user, ctrl);
- if (retval == PAM_AUTHTOK_ERR) {
- if (off(UNIX__IAMROOT, ctrl))
- _make_remark(pamh, ctrl, PAM_ERROR_MSG,
- _("You must wait longer to change your password"));
- else
- retval = PAM_SUCCESS;
- }
- } else if (on(UNIX__UPDATE, ctrl)) {
- /*
- * tpass is used below to store the _pam_md() return; it
- * should be _pam_delete()'d.
- */
-
- char *tpass = NULL;
- int retry = 0;
-
- /*
- * obtain the proposed password
- */
-
- D(("do update"));
-
- /*
- * get the old token back. NULL was ok only if root [at this
- * point we assume that this has already been enforced on a
- * previous call to this function].
- */
-
- if (off(UNIX_NOT_SET_PASS, ctrl)) {
- retval = pam_get_item(pamh, PAM_OLDAUTHTOK
- ,&pass_old);
- } else {
- retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK
- ,&pass_old);
- if (retval == PAM_NO_MODULE_DATA) {
- retval = PAM_SUCCESS;
- pass_old = NULL;
- }
- }
- D(("pass_old [%s]", pass_old));
-
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_NOTICE, "user not authenticated");
- return retval;
- }
-
- D(("get new password now"));
-
- lctrl = ctrl;
-
- if (on(UNIX_USE_AUTHTOK, lctrl)) {
- set(UNIX_USE_FIRST_PASS, lctrl);
- }
- retry = 0;
- retval = PAM_AUTHTOK_ERR;
- while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
- /*
- * use_authtok is to force the use of a previously entered
- * password -- needed for pluggable password strength checking
- */
-
- retval = _unix_read_password(pamh, lctrl
- ,NULL
- ,_("Enter new UNIX password: ")
- ,_("Retype new UNIX password: ")
- ,_UNIX_NEW_AUTHTOK
- ,&pass_new);
-
- if (retval != PAM_SUCCESS) {
- if (on(UNIX_DEBUG, ctrl)) {
- pam_syslog(pamh, LOG_ALERT,
- "password - new password not obtained");
- }
- pass_old = NULL; /* tidy up */
- return retval;
- }
- D(("returned to _unix_chauthtok"));
-
- /*
- * At this point we know who the user is and what they
- * propose as their new password. Verify that the new
- * password is acceptable.
- */
-
- if (*(const char *)pass_new == '\0') { /* "\0" password = NULL */
- pass_new = NULL;
- }
- retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
- }
-
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_NOTICE,
- "new password not acceptable");
- pass_new = pass_old = NULL; /* tidy up */
- return retval;
- }
- if (lock_pwdf() != PAM_SUCCESS) {
- return PAM_AUTHTOK_LOCK_BUSY;
- }
-
- if (pass_old) {
- retval = _unix_verify_password(pamh, user, pass_old, ctrl);
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_NOTICE, "user password changed by another process");
- unlock_pwdf();
- return retval;
- }
- }
-
- retval = _unix_verify_shadow(pamh, user, ctrl);
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_NOTICE, "user shadow entry expired");
- unlock_pwdf();
- return retval;
- }
-
- retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_NOTICE,
- "new password not acceptable 2");
- pass_new = pass_old = NULL; /* tidy up */
- unlock_pwdf();
- return retval;
- }
-
- /*
- * By reaching here we have approved the passwords and must now
- * rebuild the password database file.
- */
-
- /*
- * First we encrypt the new password.
- */
-
- tpass = create_password_hash(pass_new, ctrl, rounds);
- if (tpass == NULL) {
- pam_syslog(pamh, LOG_CRIT,
- "out of memory for password");
- pass_new = pass_old = NULL; /* tidy up */
- unlock_pwdf();
- return PAM_BUF_ERR;
- }
-
- D(("password processed"));
-
- /* update the password database(s) -- race conditions..? */
-
- retval = _do_setpass(pamh, user, pass_old, tpass, ctrl,
- remember);
- /* _do_setpass has called unlock_pwdf for us */
-
- _pam_delete(tpass);
- pass_old = pass_new = NULL;
- } else { /* something has broken with the module */
- pam_syslog(pamh, LOG_ALERT,
- "password received unknown request");
- retval = PAM_ABORT;
- }
-
- D(("retval was %d", retval));
-
- return retval;
-}
-
-
-/* static module data */
-#ifdef PAM_STATIC
-struct pam_module _pam_unix_passwd_modstruct = {
- "pam_unix_passwd",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- pam_sm_chauthtok,
-};
-#endif