From: Todd C. Miller Date: Wed, 9 Mar 2016 16:39:46 +0000 (-0700) Subject: Work around an ambiguity in the PAM spec with respect to the conversation X-Git-Tag: SUDO_1_8_16^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48dff840810a6ec6d56422e687a7eb464dc27ad1;p=sudo Work around an ambiguity in the PAM spec with respect to the conversation function. It is not clear whether the "struct pam_message **msg" is an array of pointers or a pointer to an array. Linux-PAM and OpenPAM use an array of pointers while Solaris/HP-UX/AIX uses a pointer to an array. Bug #726. --- diff --git a/NEWS b/NEWS index 9e8f34ff6..274da1c48 100644 --- a/NEWS +++ b/NEWS @@ -63,6 +63,9 @@ What's new in Sudo 1.8.16 * Fixed a bug in the LDAP and SSSD backends that could allow an unauthorized user to list another user's privileges. Bug #738. + * The PAM conversation function now works around an ambiguity in the + PAM spec with respect to multiple messages. Bug #726. + What's new in Sudo 1.8.15 * Fixed a bug that prevented sudo from building outside the source tree diff --git a/config.h.in b/config.h.in index 3d11c0187..b71d9cdb4 100644 --- a/config.h.in +++ b/config.h.in @@ -963,6 +963,10 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Define to 1 if your system uses a Solaris-derived PAM and not Linux-PAM or + OpenPAM. */ +#undef PAM_SUN_CODEBASE + /* The default password prompt. */ #undef PASSPROMPT diff --git a/configure b/configure index 4cdba6eda..04cb26500 100755 --- a/configure +++ b/configure @@ -14729,6 +14729,9 @@ esac shadow_funcs="getpwanam issecure" ;; *-*-solaris2*) + $as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h + + # LD_PRELOAD is space-delimited RTLD_PRELOAD_DELIM=" " @@ -14756,6 +14759,9 @@ done ;; *-*-aix*) + $as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h + + # To get all prototypes (so we pass -Wall) $as_echo "#define _LINUX_SOURCE_COMPAT 1" >>confdefs.h @@ -14872,6 +14878,9 @@ _ACEOF ;; *-*-hiuxmpp*) + $as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h + + : ${mansectsu='1m'} : ${mansectform='4'} @@ -14897,6 +14906,9 @@ done ;; *-*-hpux*) + $as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h + + # AFS support needs -lBSD if test "$with_AFS" = "yes"; then AFS_LIBS="-lc -lBSD" @@ -26577,5 +26589,6 @@ fi + diff --git a/configure.ac b/configure.ac index 4c063979f..bb2ba2699 100644 --- a/configure.ac +++ b/configure.ac @@ -1685,6 +1685,8 @@ case "$host" in shadow_funcs="getpwanam issecure" ;; *-*-solaris2*) + AC_DEFINE([PAM_SUN_CODEBASE]) + # LD_PRELOAD is space-delimited RTLD_PRELOAD_DELIM=" " @@ -1702,6 +1704,8 @@ case "$host" in AC_CHECK_FUNCS([priv_set], [PSMAN=1]) ;; *-*-aix*) + AC_DEFINE([PAM_SUN_CODEBASE]) + # To get all prototypes (so we pass -Wall) AC_DEFINE([_LINUX_SOURCE_COMPAT]) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp" @@ -1756,6 +1760,8 @@ case "$host" in ]) ;; *-*-hiuxmpp*) + AC_DEFINE([PAM_SUN_CODEBASE]) + : ${mansectsu='1m'} : ${mansectform='4'} @@ -1771,6 +1777,8 @@ case "$host" in AC_CHECK_FUNCS([pstat_getproc]) ;; *-*-hpux*) + AC_DEFINE([PAM_SUN_CODEBASE]) + # AFS support needs -lBSD if test "$with_AFS" = "yes"; then AFS_LIBS="-lc -lBSD" @@ -4352,6 +4360,7 @@ AH_TEMPLATE(HAVE__NSS_XBYY_BUF_ALLOC, [Define to 1 if you have the `_nss_XbyY_bu AH_TEMPLATE(HAVE___NSS_XBYY_BUF_ALLOC, [Define to 1 if you have the `__nss_XbyY_buf_alloc' function.]) AH_TEMPLATE(NEED_RESOLV_H, [Define to 1 if resolv.h must be included to get the `inet_ntop' or `inet_pton' function prototypes.]) AH_TEMPLATE(HAVE_STRNLEN, [Define to 1 if you have the `strnlen' function.]) +AH_TEMPLATE(PAM_SUN_CODEBASE, [Define to 1 if your system uses a Solaris-derived PAM and not Linux-PAM or OpenPAM.]) dnl dnl Bits to copy verbatim into config.h.in diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c index 90f4eabf1..abb193226 100644 --- a/plugins/sudoers/auth/pam.c +++ b/plugins/sudoers/auth/pam.c @@ -58,11 +58,17 @@ #include "sudo_auth.h" /* Only OpenPAM and Linux PAM use const qualifiers. */ -#if defined(_OPENPAM) || defined(OPENPAM_VERSION) || \ - defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__) +#ifdef PAM_SUN_CODEBASE +# define PAM_CONST +#else # define PAM_CONST const +#endif + +/* Ambiguity in spec: is it an array of pointers or a pointer to an array? */ +#ifdef PAM_SUN_CODEBASE +# define PAM_MSG_GET(msg, n) (*(msg) + (n)) #else -# define PAM_CONST +# define PAM_MSG_GET(msg, n) ((msg)[(n)]) #endif #ifndef PAM_DATA_SILENT @@ -376,11 +382,10 @@ sudo_pam_end_session(struct passwd *pw, sudo_auth *auth) */ static int converse(int num_msg, PAM_CONST struct pam_message **msg, - struct pam_response **response, void *vcallback) + struct pam_response **reply_out, void *vcallback) { - struct pam_response *pr; struct sudo_conv_callback *callback = NULL; - PAM_CONST struct pam_message *pm; + struct pam_response *reply; const char *prompt; char *pass; int n, type; @@ -395,15 +400,18 @@ converse(int num_msg, PAM_CONST struct pam_message **msg, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "number of PAM messages: %d", num_msg); - if ((*response = calloc(num_msg, sizeof(struct pam_response))) == NULL) { + if ((reply = calloc(num_msg, sizeof(struct pam_response))) == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_int(PAM_BUF_ERR); } + *reply_out = reply; if (vcallback != NULL) callback = *((struct sudo_conv_callback **)vcallback); - for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { + for (n = 0; n < num_msg; n++) { + PAM_CONST struct pam_message *pm = PAM_MSG_GET(msg, n); + type = SUDO_CONV_PROMPT_ECHO_OFF; switch (pm->msg_style) { case PAM_PROMPT_ECHO_ON: @@ -447,7 +455,7 @@ converse(int num_msg, PAM_CONST struct pam_message **msg, memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass)); goto done; } - pr->resp = pass; /* auth_getpass() malloc's a copy */ + reply[n].resp = pass; /* auth_getpass() malloc's a copy */ break; case PAM_TEXT_INFO: if (pm->msg) @@ -470,15 +478,17 @@ converse(int num_msg, PAM_CONST struct pam_message **msg, done: if (ret != PAM_SUCCESS) { /* Zero and free allocated memory and return an error. */ - for (pr = *response, n = num_msg; n--; pr++) { + for (n = 0; n < num_msg; n++) { + struct pam_response *pr = &reply[n]; + if (pr->resp != NULL) { memset_s(pr->resp, SUDO_CONV_REPL_MAX, 0, strlen(pr->resp)); free(pr->resp); pr->resp = NULL; } } - free(*response); - *response = NULL; + free(reply); + *reply_out = NULL; } debug_return_int(ret); }