#define PAM_SM_PASSWORD
#include <security/pam_modules.h>
-
-#ifndef LINUX_PAM
-#include <security/pam_appl.h>
-#endif /* LINUX_PAM */
-
+#include <security/pam_ext.h>
#include <security/pam_modutil.h>
#include "yppasswd.h"
#include "md5.h"
#include "support.h"
+#include "bigcrypt.h"
#if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
extern int getrpcport(const char *host, unsigned long prognum,
# include "./lckpwdf.-c"
#endif
-extern char *bigcrypt(const char *key, const char *salt);
-
/*
How it works:
Gets in username (has to be done) from the calling program
int port, err;
if ((err = yp_get_default_domain(&domainname)) != 0) {
- _log_err(LOG_WARNING, pamh, "can't get local yp domain: %s\n",
+ 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) {
- _log_err(LOG_WARNING, pamh, "can't find the master ypserver: %s\n",
+ 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) {
- _log_err(LOG_WARNING, pamh,
- "yppasswdd not running on NIS master host\n");
+ pam_syslog(pamh, LOG_WARNING,
+ "yppasswdd not running on NIS master host");
return NULL;
}
if (port >= IPPORT_RESERVED) {
- _log_err(LOG_WARNING, pamh,
- "yppasswd daemon running on illegal port.\n");
+ pam_syslog(pamh, LOG_WARNING,
+ "yppasswd daemon running on illegal port");
return NULL;
}
return master;
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(CHKPWD_HELPER);
args[1] = x_strdup(user);
close(fds[1]);
rc=waitpid(child, &retval, 0); /* wait for helper to complete */
if (rc<0) {
- _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
+ pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc);
retval = PAM_AUTH_ERR;
} else {
retval = WEXITSTATUS(retval);
retval = PAM_AUTH_ERR;
}
- if (sighandler != NULL) {
+ if (sighandler != SIG_ERR) {
(void) signal(SIGCHLD, sighandler); /* restore old signal handler */
}
while (fgets(buf, 16380, opwfile)) {
if (!strncmp(buf, forwho, strlen(forwho))) {
+ char *sptr;
buf[strlen(buf) - 1] = '\0';
- s_luser = strtok(buf, ":,");
- s_uid = strtok(NULL, ":,");
- s_npas = strtok(NULL, ":,");
- s_pas = strtok(NULL, ":,");
+ 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)) {
retval = PAM_AUTHTOK_ERR;
break;
}
- s_pas = strtok(NULL, ":,");
+ s_pas = strtok_r(NULL, ":,", &sptr);
_pam_delete(md5pass);
}
break;
while (fgets(buf, 16380, opwfile)) {
if (!strncmp(buf, forwho, strlen(forwho))) {
+ char *sptr;
buf[strlen(buf) - 1] = '\0';
- s_luser = strtok(buf, ":");
- s_uid = strtok(NULL, ":");
- s_npas = strtok(NULL, ":");
- s_pas = strtok(NULL, ":");
+ s_luser = strtok_r(buf, ":", &sptr);
+ s_uid = strtok_r(NULL, ":", &sptr);
+ s_npas = strtok_r(NULL, ":", &sptr);
+ s_pas = strtok_r(NULL, ":", &sptr);
npas = strtol(s_npas, NULL, 10) + 1;
while (npas > howmany) {
s_pas = strpbrk(s_pas, ",");
err = 1;
} else {
pass = crypt_md5_wrapper(oldpass);
- snprintf(nbuf, sizeof(nbuf), "%s:%d:1:%s\n",
- forwho, pwd->pw_uid, pass);
+ snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n",
+ forwho, (unsigned long)pwd->pw_uid, pass);
_pam_delete(pass);
if (fputs(nbuf, pwfile) < 0) {
err = 1;
}
if (fclose(pwfile)) {
- D(("error writing entries to old passwords file: %s\n",
- strerror(errno)));
+ D(("error writing entries to old passwords file: %m"));
err = 1;
}
err = 0;
}
if (putpwent(tmpent, pwfile)) {
- D(("error writing entry to password file: %s\n", strerror(errno)));
+ D(("error writing entry to password file: %m"));
err = 1;
break;
}
fclose(opwfile);
if (fclose(pwfile)) {
- D(("error writing entries to password file: %s\n", strerror(errno)));
+ D(("error writing entries to password file: %m"));
err = 1;
}
done:
if (!err) {
if (!rename(PW_TMPFILE, "/etc/passwd"))
- _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
+ pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho);
else
err = 1;
}
}
if (putspent(stmpent, pwfile)) {
- D(("error writing entry to shadow file: %s\n", strerror(errno)));
+ D(("error writing entry to shadow file: %m"));
err = 1;
break;
}
fclose(opwfile);
if (fclose(pwfile)) {
- D(("error writing entries to shadow file: %s\n", strerror(errno)));
+ D(("error writing entries to shadow file: %m"));
err = 1;
}
done:
if (!err) {
if (!rename(SH_TMPFILE, "/etc/shadow"))
- _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
+ pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho);
else
err = 1;
}
struct yppasswd yppwd;
CLIENT *clnt;
int status;
- int err = 0;
+ enum clnt_stat err;
/* Unlock passwd file to avoid deadlock */
#ifdef USE_LCKPWDF
}
D(("The password has%s been changed on %s.",
(err || status) ? " not" : "", master));
- _log_err(LOG_NOTICE, pamh, "password%s changed for %s on %s",
+ pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s",
(err || status) ? " not" : "", pwd->pw_name, master);
auth_destroy(clnt->cl_auth);
if (off(UNIX__IAMROOT, ctrl)) {
/* Get the current number of days since 1970 */
curdays = time(NULL) / (60 * 60 * 24);
- if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min))
- && (spwdent->sp_min != -1))
+ if (curdays < spwdent->sp_lstchg) {
+ pam_syslog(pamh, LOG_DEBUG,
+ "account %s has password changed in future",
+ user);
+ curdays = spwdent->sp_lstchg;
+ }
+ if ((curdays - spwdent->sp_lstchg < spwdent->sp_min)
+ && (spwdent->sp_min != -1))
+ /*
+ * The last password change was too recent.
+ */
retval = PAM_AUTHTOK_ERR;
- else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact))
+ else if ((curdays - spwdent->sp_lstchg > spwdent->sp_max)
+ && (curdays - spwdent->sp_lstchg > spwdent->sp_inact)
+ && (curdays - spwdent->sp_lstchg >
+ spwdent->sp_max + spwdent->sp_inact)
&& (spwdent->sp_max != -1) && (spwdent->sp_inact != -1)
&& (spwdent->sp_lstchg != 0))
/*
if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) {
if (on(UNIX_DEBUG, ctrl)) {
- _log_err(LOG_DEBUG, pamh, "bad authentication token");
+ pam_syslog(pamh, LOG_DEBUG, "bad authentication token");
}
_make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
_("No password supplied") : _("Password unchanged"));
retval = pam_get_item(pamh, PAM_USER, &user);
if (retval != PAM_SUCCESS) {
if (on(UNIX_DEBUG, ctrl)) {
- _log_err(LOG_ERR, pamh, "Can not get username");
+ pam_syslog(pamh, LOG_ERR, "Can not get username");
return PAM_AUTHTOK_ERR;
}
}
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",
+ pam_syslog(pamh, LOG_ERR, "can't open %s file to check old passwords",
OLD_PASSWORDS_FILE);
return retval;
}
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 take
- * any chances here. Require that the username starts with an
- * alphanumeric character.
+ * '+' or '-' as the first character of a user name. Don't
+ * allow them.
*/
- if (user == NULL || !isalnum(*user)) {
- _log_err(LOG_ERR, pamh, "bad username [%s]", user);
+ 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))
- _log_err(LOG_DEBUG, pamh, "username [%s] obtained",
+ pam_syslog(pamh, LOG_DEBUG, "username [%s] obtained",
user);
} else {
if (on(UNIX_DEBUG, ctrl))
- _log_err(LOG_DEBUG, pamh,
+ pam_syslog(pamh, LOG_DEBUG,
"password - could not identify user");
return retval;
}
* came from, nor should it. That's our job.
*/
if (_unix_comesfromsource(pamh, user, 1, on(UNIX_NIS, ctrl)) == 0) {
- _log_err(LOG_DEBUG, pamh,
+ 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;
struct passwd *pwd;
_unix_getpwnam(pamh, user, 1, 1, &pwd);
if (pwd == NULL) {
- _log_err(LOG_DEBUG, pamh,
+ pam_syslog(pamh, LOG_DEBUG,
"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;
- }
}
/*
if (_unix_blankpasswd(pamh, ctrl, user)) {
return PAM_SUCCESS;
} else if (off(UNIX__IAMROOT, ctrl)) {
-
/* instruct user what is happening */
-#define greeting "Changing password for "
- Announce = (char *) malloc(sizeof(greeting) + strlen(user));
- if (Announce == NULL) {
- _log_err(LOG_CRIT, pamh,
+ if (asprintf(&Announce, _("Changing password for %s."),
+ user) < 0) {
+ pam_syslog(pamh, LOG_CRIT,
"password - out of memory");
return PAM_BUF_ERR;
}
- (void) strcpy(Announce, greeting);
- (void) strcpy(Announce + sizeof(greeting) - 1, user);
-#undef greeting
lctrl = ctrl;
set(UNIX__OLD_PASSWD, lctrl);
free(Announce);
if (retval != PAM_SUCCESS) {
- _log_err(LOG_NOTICE, pamh
- ,"password - (old) token not obtained");
+ pam_syslog(pamh, LOG_NOTICE,
+ "password - (old) token not obtained");
return retval;
}
/* verify that this is the password for this user */
retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
pass_old = NULL;
if (retval != PAM_SUCCESS) {
- _log_err(LOG_CRIT, pamh,
+ pam_syslog(pamh, LOG_CRIT,
"failed to set PAM_OLDAUTHTOK");
}
retval = _unix_verify_shadow(pamh,user, ctrl);
D(("pass_old [%s]", pass_old));
if (retval != PAM_SUCCESS) {
- _log_err(LOG_NOTICE, pamh, "user not authenticated");
+ pam_syslog(pamh, LOG_NOTICE, "user not authenticated");
return retval;
}
if (retval != PAM_SUCCESS) {
if (on(UNIX_DEBUG, ctrl)) {
- _log_err(LOG_ALERT, pamh
- ,"password - new password not obtained");
+ pam_syslog(pamh, LOG_ALERT,
+ "password - new password not obtained");
}
pass_old = NULL; /* tidy up */
return retval;
}
if (retval != PAM_SUCCESS) {
- _log_err(LOG_NOTICE, pamh,
+ pam_syslog(pamh, LOG_NOTICE,
"new password not acceptable");
pass_new = pass_old = NULL; /* tidy up */
return retval;
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");
+ pam_syslog(pamh, LOG_NOTICE, "user password changed by another process");
#ifdef USE_LCKPWDF
ulckpwdf();
#endif
retval = _unix_verify_shadow(pamh, user, ctrl);
if (retval != PAM_SUCCESS) {
- _log_err(LOG_NOTICE, pamh, "user not authenticated 2");
+ pam_syslog(pamh, LOG_NOTICE, "user not authenticated 2");
#ifdef USE_LCKPWDF
ulckpwdf();
#endif
retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
if (retval != PAM_SUCCESS) {
- _log_err(LOG_NOTICE, pamh,
+ pam_syslog(pamh, LOG_NOTICE,
"new password not acceptable 2");
pass_new = pass_old = NULL; /* tidy up */
#ifdef USE_LCKPWDF
char *temp = malloc(9);
if (temp == NULL) {
- _log_err(LOG_CRIT, pamh,
+ pam_syslog(pamh, LOG_CRIT,
"out of memory for password");
pass_new = pass_old = NULL; /* tidy up */
#ifdef USE_LCKPWDF
_pam_delete(tpass);
pass_old = pass_new = NULL;
} else { /* something has broken with the module */
- _log_err(LOG_ALERT, pamh,
+ pam_syslog(pamh, LOG_ALERT,
"password received unknown request");
retval = PAM_ABORT;
}