From: Todd C. Miller Date: Sat, 1 Dec 2007 16:22:25 +0000 (+0000) Subject: Add basic support for looking up the string "Password: " in the PAM X-Git-Tag: SUDO_1_7_0~322 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8694c73146d2a8f24df08538817a968fa22f27b9;p=sudo Add basic support for looking up the string "Password: " in the PAM localized text db. This allows us to determine whether the PAM prompt is the default "Password: " one even if it has been localized. TODO: concatenate non-std PAM prompts and user-specified sudo prompts. --- diff --git a/auth/pam.c b/auth/pam.c index 7fb45b74c..c28477061 100644 --- a/auth/pam.c +++ b/auth/pam.c @@ -52,6 +52,15 @@ # include #endif +#ifdef HAVE_DGETTEXT +# include +# if defined(__LINUX_PAM__) +# define PAM_TEXT_DOMAIN "Linux-PAM" +# elif defined(__sun__) +# define PAM_TEXT_DOMAIN "SUNW_OST_SYSOSPAM" +# endif +#endif + #include "sudo.h" #include "sudo_auth.h" @@ -239,27 +248,41 @@ sudo_conv(num_msg, msg, response, appdata_ptr) { struct pam_response *pr; PAM_CONST struct pam_message *pm; - const char *p = def_prompt; + const char *prompt; char *pass; - int n, flags; + int n, flags, std_prompt; extern int nil_pw; if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) return(PAM_CONV_ERR); zero_bytes(*response, num_msg * sizeof(struct pam_response)); + /* Is the sudo prompt standard? (If so, we'l just use PAM's) */ + std_prompt = strncmp(def_prompt, "Password:", 9) == 0 && + (def_prompt[9] == '\0' || + (def_prompt[9] == ' ' && def_prompt[10] == '\0')); + for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { flags = tgetpass_flags; switch (pm->msg_style) { case PAM_PROMPT_ECHO_ON: SET(flags, TGP_ECHO); case PAM_PROMPT_ECHO_OFF: + prompt = def_prompt; /* Only override PAM prompt if it matches /^Password: ?/ */ - if (strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0' +#if defined(PAM_TEXT_DOMAIN) && defined(HAVE_DGETTEXT) + if (std_prompt || + (strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) && + strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:")))) + prompt = pm->msg; +#else + if (std_prompt || + strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0' && (pm->msg[9] != ' ' || pm->msg[10] != '\0'))) - p = pm->msg; + prompt = pm->msg; +#endif /* Read the password. */ - pass = tgetpass(p, def_passwd_timeout * 60, flags); + pass = tgetpass(prompt, def_passwd_timeout * 60, flags); if (pass == NULL) { /* We got ^C instead of a password; abort quickly. */ nil_pw = 1; diff --git a/config.h.in b/config.h.in index 691f175d3..b37499d7d 100644 --- a/config.h.in +++ b/config.h.in @@ -75,6 +75,9 @@ /* Define to 1 if your `DIR' contains dd_fd. */ #undef HAVE_DD_FD +/* Define to 1 if you have the `dgettext' function. */ +#undef HAVE_DGETTEXT + /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H diff --git a/configure b/configure index 25b555f33..26234a25d 100755 --- a/configure +++ b/configure @@ -11751,6 +11751,170 @@ fi shadow_funcs="getspnam" shadow_libs_optional="-lshadow" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" + +for ac_func in dgettext +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + { echo "$as_me:$LINENO: checking for dgettext in -lintl" >&5 +echo $ECHO_N "checking for dgettext in -lintl... $ECHO_C" >&6; } +if test "${ac_cv_lib_intl_dgettext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lintl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dgettext (); +int +main () +{ +return dgettext (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_intl_dgettext=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_intl_dgettext=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_intl_dgettext" >&5 +echo "${ECHO_T}$ac_cv_lib_intl_dgettext" >&6; } +if test $ac_cv_lib_intl_dgettext = yes; then + LIBS="${LIBS} -lintl" + cat >>confdefs.h <<\_ACEOF +#define HAVE_DGETTEXT 1 +_ACEOF + +fi + +fi +done + ;; *-convex-bsd*) OSDEFS="${OSDEFS} -D_CONVEX_SOURCE" @@ -23703,6 +23867,8 @@ fi + + diff --git a/configure.in b/configure.in index b5754124f..f9e8995de 100644 --- a/configure.in +++ b/configure.in @@ -1397,6 +1397,9 @@ case "$host" in shadow_funcs="getspnam" shadow_libs_optional="-lshadow" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" + AC_CHECK_FUNCS(dgettext, [], + [AC_CHECK_LIB(intl, dgettext, [LIBS="${LIBS} -lintl"] + [AC_DEFINE(HAVE_DGETTEXT)])]) ;; *-convex-bsd*) OSDEFS="${OSDEFS} -D_CONVEX_SOURCE" @@ -2423,6 +2426,7 @@ AH_TEMPLATE(HAVE_BSD_AUTH_H, [Define to 1 if you use BSD authentication.]) AH_TEMPLATE(HAVE_DCE, [Define to 1 if you use OSF DCE.]) AH_TEMPLATE(HAVE_DD_FD, [Define to 1 if your `DIR' contains dd_fd.]) AH_TEMPLATE(HAVE_DIRFD, [Define to 1 if you have the `dirfd' function or macro.]) +AH_TEMPLATE(HAVE_DGETTEXT, [Define to 1 if you have the `dgettext' function.]) AH_TEMPLATE(HAVE_DISPCRYPT, [Define to 1 if you have the `dispcrypt' function.]) AH_TEMPLATE(HAVE_EXTENDED_GLOB, [Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags.]) AH_TEMPLATE(HAVE_FCNTL_CLOSEM, [Define to 1 if your system has the F_CLOSEM fcntl.])