diff options
author | Steve Langasek <vorlon@debian.org> | 2019-01-22 14:54:11 -0800 |
---|---|---|
committer | Steve Langasek <vorlon@debian.org> | 2019-01-22 14:54:11 -0800 |
commit | f00afb1ef201b2eef7f9ddbe5a0c6ca802cf49bb (patch) | |
tree | 402838c53047b0e21466a653ae88d86a8e4b7b65 /modules/pam_unix/pam_unix_passwd.c | |
parent | 795badba7f95e737f979917859cd32c9bd47bcad (diff) | |
parent | 1cad9fb2a0d729c5b5e5aa7297c521df7d5a2d33 (diff) | |
download | pam-f00afb1ef201b2eef7f9ddbe5a0c6ca802cf49bb.tar.gz pam-f00afb1ef201b2eef7f9ddbe5a0c6ca802cf49bb.tar.bz2 pam-f00afb1ef201b2eef7f9ddbe5a0c6ca802cf49bb.zip |
New upstream version 1.3.0
Diffstat (limited to 'modules/pam_unix/pam_unix_passwd.c')
-rw-r--r-- | modules/pam_unix/pam_unix_passwd.c | 201 |
1 files changed, 123 insertions, 78 deletions
diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c index 9aae3b03..c2e43423 100644 --- a/modules/pam_unix/pam_unix_passwd.c +++ b/modules/pam_unix/pam_unix_passwd.c @@ -64,11 +64,7 @@ /* indicate the following groups are defined */ -#ifdef PAM_STATIC -# include "pam_unix_static.h" -#else -# define PAM_SM_PASSWORD -#endif +#define PAM_SM_PASSWORD #include <security/pam_modules.h> #include <security/pam_ext.h> @@ -96,7 +92,7 @@ # include "yppasswd.h" -# if !HAVE_DECL_GETRPCPORT +# if !HAVE_DECL_GETRPCPORT &&!HAVE_RPCB_GETADDR extern int getrpcport(const char *host, unsigned long prognum, unsigned long versnum, unsigned int proto); # endif /* GNU libc 2.1 */ @@ -118,11 +114,48 @@ extern int getrpcport(const char *host, unsigned long prognum, #define MAX_PASSWD_TRIES 3 #ifdef HAVE_NIS +#ifdef HAVE_RPCB_GETADDR +static unsigned short +__taddr2port (const struct netconfig *nconf, const struct netbuf *nbuf) +{ + unsigned short port = 0; + struct __rpc_sockinfo si; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + if (!__rpc_nconf2sockinfo(nconf, &si)) + return 0; + + switch (si.si_af) + { + case AF_INET: + sin = nbuf->buf; + port = sin->sin_port; + break; + case AF_INET6: + sin6 = nbuf->buf; + port = sin6->sin6_port; + break; + default: + break; + } + + return htons (port); +} +#endif + static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl) { char *master; char *domainname; int port, err; +#if defined(HAVE_RPCB_GETADDR) + struct netconfig *nconf; + struct netbuf svcaddr; + char addrbuf[INET6_ADDRSTRLEN]; + void *handle; + int found; +#endif + #ifdef HAVE_YP_GET_DEFAULT_DOMAIN if ((err = yp_get_default_domain(&domainname)) != 0) { @@ -150,7 +183,41 @@ static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl) yperr_string(err)); return NULL; } +#ifdef HAVE_RPCB_GETADDR + svcaddr.len = 0; + svcaddr.maxlen = sizeof (addrbuf); + svcaddr.buf = addrbuf; + port = 0; + found = 0; + + handle = setnetconfig(); + while ((nconf = getnetconfig(handle)) != NULL) { + if (!strcmp(nconf->nc_proto, "udp")) { + if (rpcb_getaddr(YPPASSWDPROG, YPPASSWDPROC_UPDATE, + nconf, &svcaddr, master)) { + port = __taddr2port (nconf, &svcaddr); + endnetconfig (handle); + found=1; + break; + } + + if (rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { + clnt_pcreateerror (master); + pam_syslog (pamh, LOG_ERR, + "rpcb_getaddr (%s) failed!", master); + return NULL; + } + } + } + + if (!found) { + pam_syslog (pamh, LOG_ERR, + "Cannot find suitable transport for protocol 'udp'"); + return NULL; + } +#else port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP); +#endif if (port == 0) { pam_syslog(pamh, LOG_WARNING, "yppasswdd not running on NIS master host"); @@ -201,39 +268,37 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const /* fork */ child = fork(); if (child == 0) { - int i=0; - struct rlimit rlim; static char *envp[] = { NULL }; - char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL }; + const char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL }; char buffer[16]; /* XXX - should really tidy up PAM here too */ /* reopen stdin as pipe */ - dup2(fds[0], STDIN_FILENO); - - if (getrlimit(RLIMIT_NOFILE,&rlim)==0) { - if (rlim.rlim_max >= MAX_FD_NO) - rlim.rlim_max = MAX_FD_NO; - for (i=0; i < (int)rlim.rlim_max; i++) { - if (i != STDIN_FILENO) - close(i); - } + if (dup2(fds[0], STDIN_FILENO) != STDIN_FILENO) { + pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdin"); + _exit(PAM_AUTHINFO_UNAVAIL); + } + + if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_IGNORE_FD, + PAM_MODUTIL_PIPE_FD, + PAM_MODUTIL_PIPE_FD) < 0) { + _exit(PAM_AUTHINFO_UNAVAIL); } /* exec binary helper */ - args[0] = x_strdup(UPDATE_HELPER); - args[1] = x_strdup(user); - args[2] = x_strdup("update"); + args[0] = UPDATE_HELPER; + args[1] = user; + args[2] = "update"; if (on(UNIX_SHADOW, ctrl)) - args[3] = x_strdup("1"); + args[3] = "1"; else - args[3] = x_strdup("0"); + args[3] = "0"; snprintf(buffer, sizeof(buffer), "%d", remember); - args[4] = x_strdup(buffer); + args[4] = buffer; - execve(UPDATE_HELPER, args, envp); + execve(UPDATE_HELPER, (char *const *) args, envp); /* should not get here: exit with error */ D(("helper binary is not available")); @@ -242,15 +307,22 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const /* 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); + if (fromwhat) { + int len = strlen(fromwhat); + + if (len > PAM_MAX_RESP_SIZE) + len = PAM_MAX_RESP_SIZE; + pam_modutil_write(fds[1], fromwhat, len); } - else - pam_modutil_write(fds[1], "", 1); + pam_modutil_write(fds[1], "", 1); + if (towhat) { + int len = strlen(towhat); + + if (len > PAM_MAX_RESP_SIZE) + len = PAM_MAX_RESP_SIZE; + pam_modutil_write(fds[1], towhat, len); + } + pam_modutil_write(fds[1], "", 1); close(fds[0]); /* close here to avoid possible SIGPIPE above */ close(fds[1]); @@ -303,7 +375,7 @@ static int check_old_password(const char *forwho, const char *newpass) s_pas = strtok_r(NULL, ":,", &sptr); while (s_pas != NULL) { char *md5pass = Goodcrypt_md5(newpass, s_pas); - if (!strcmp(md5pass, s_pas)) { + if (md5pass == NULL || !strcmp(md5pass, s_pas)) { _pam_delete(md5pass); retval = PAM_AUTHTOK_ERR; break; @@ -540,7 +612,8 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) /* <DO NOT free() THESE> */ const char *user; - const void *pass_old, *pass_new; + const void *item; + const char *pass_old, *pass_new; /* </DO NOT free() THESE> */ D(("called.")); @@ -608,30 +681,19 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) * 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)) { + } else if (off(UNIX__IAMROOT, ctrl) || + (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, user, 0, 1))) { /* 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; + if (off(UNIX__QUIET, ctrl)) { + retval = pam_info(pamh, _("Changing password for %s."), user); + if (retval != PAM_SUCCESS) + return retval; } - - 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); + retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &pass_old, NULL); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, @@ -652,12 +714,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 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)) @@ -687,23 +744,14 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) * 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)); + retval = pam_get_item(pamh, PAM_OLDAUTHTOK, &item); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "user not authenticated"); return retval; } + pass_old = item; + D(("pass_old [%s]", pass_old)); D(("get new password now")); @@ -712,7 +760,9 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) if (on(UNIX_USE_AUTHTOK, lctrl)) { set(UNIX_USE_FIRST_PASS, lctrl); } - retry = 0; + if (on(UNIX_USE_FIRST_PASS, lctrl)) { + retry = MAX_PASSWD_TRIES-1; + } retval = PAM_AUTHTOK_ERR; while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { /* @@ -720,12 +770,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) * 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); + retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass_new, NULL); if (retval != PAM_SUCCESS) { if (on(UNIX_DEBUG, ctrl)) { @@ -749,7 +794,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new, pass_min_len); - if (retval != PAM_SUCCESS && off(UNIX_NOT_SET_PASS, ctrl)) { + if (retval != PAM_SUCCESS) { pam_set_item(pamh, PAM_AUTHTOK, NULL); } } |