]> granicus.if.org Git - sudo/commitdiff
Add support for running a helper program to read the password when
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 2 Mar 2008 14:31:57 +0000 (14:31 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 2 Mar 2008 14:31:57 +0000 (14:31 +0000)
no tty is present (or when specified with the -A flag).  TODO: docs.

13 files changed:
auth/sudo_auth.c
check.c
configure
configure.in
def_data.c
def_data.h
def_data.in
defaults.c
pathnames.h.in
sudo.c
sudo.h
sudo_usage.h.in
tgetpass.c

index 11860bafdd71d5abdb223f66af6f109cc857ba6a..4ee39c1d1b645dea3bd547ca216e3f190a8dcb2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -195,7 +195,8 @@ verify_user(pw, prompt)
                break;
        }
 
-       pass_warn(stderr);
+       if (!ISSET(tgetpass_flags, TGP_ASKPASS))
+           pass_warn(stderr);
     }
 
 cleanup:
diff --git a/check.c b/check.c
index cc6c80823db720dcea32778524e35ea3e71349d5..0297df5c33978d763fde3def131c805da13d01ae 100644 (file)
--- a/check.c
+++ b/check.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1993-1996,1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1993-1996,1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -98,7 +99,8 @@ check_user(validated)
     status = timestamp_status(timestampdir, timestampfile, user_name,
        TS_MAKE_DIRS);
     if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
-       lecture(status);
+       if (!ISSET(tgetpass_flags, TGP_ASKPASS))
+           lecture(status);
 
        /* Expand any escapes in the prompt. */
        prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
index ce1ddf9f2db4429612b16144fcac2b6c1155e5f2..73494ed0f8b074d4f6ff48d41a94e6cbf816584c 100755 (executable)
--- a/configure
+++ b/configure
@@ -1581,6 +1581,7 @@ Optional Packages:
   --with-secure-path      override the user's path with a built-in one
   --without-interfaces    don't try to read the ip addr of ether interfaces
   --with-stow             properly handle GNU stow packaging
+  --with-askpass=PATH     Fully qualified pathname of sudo-askpass
   --with-selinux          enable SELinux support
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
   --with-pic              try to use only PIC/non-PIC objects [default=use
@@ -3740,6 +3741,28 @@ echo "${ECHO_T}no" >&6; }
 fi
 
 
+{ echo "$as_me:$LINENO: checking path to sudo-askpass" >&5
+echo $ECHO_N "checking path to sudo-askpass... $ECHO_C" >&6; }
+
+# Check whether --with-askpass was given.
+if test "${with_askpass+set}" = set; then
+  withval=$with_askpass; case $with_askpass in
+    yes)       with_askpass="$libexecdir/sudo-askpass"
+               ;;
+    no)                ;;
+    *)         ;;
+esac
+else
+  with_askpass="$libexecdir/sudo-askpass"
+fi
+
+{ echo "$as_me:$LINENO: result: $with_askpass" >&5
+echo "${ECHO_T}$with_askpass" >&6; }
+cat >>confdefs.h <<EOF
+#define _PATH_SUDO_ASKPASS "$with_askpass"
+EOF
+
+
 
 { echo "$as_me:$LINENO: checking whether to do user authentication by default" >&5
 echo $ECHO_N "checking whether to do user authentication by default... $ECHO_C" >&6; }
@@ -6180,7 +6203,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6183 "configure"' > conftest.$ac_ext
+  echo '#line 6206 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -7724,11 +7747,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:7727: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:7750: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:7731: \$? = $ac_status" >&5
+   echo "$as_me:7754: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8014,11 +8037,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8017: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8040: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8021: \$? = $ac_status" >&5
+   echo "$as_me:8044: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8118,11 +8141,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8121: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8144: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8125: \$? = $ac_status" >&5
+   echo "$as_me:8148: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -10463,7 +10486,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 10466 "configure"
+#line 10489 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10563,7 +10586,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 10566 "configure"
+#line 10589 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
index 7f44069bcd104b3c7e9a63df6aa451b026ba963b..949f56a6ad82ff396b74d5c5281b00ae18e401e5 100644 (file)
@@ -1010,6 +1010,17 @@ AC_ARG_WITH(stow, [  --with-stow             properly handle GNU stow packaging]
                ;;
 esac], AC_MSG_RESULT(no))
 
+AC_MSG_CHECKING(path to sudo-askpass)
+AC_ARG_WITH(askpass, [  --with-askpass=PATH     Fully qualified pathname of sudo-askpass],
+[case $with_askpass in
+    yes)       with_askpass="$libexecdir/sudo-askpass"
+               ;;
+    no)                ;;
+    *)         ;;
+esac], [with_askpass="$libexecdir/sudo-askpass"])
+AC_MSG_RESULT($with_askpass)
+SUDO_DEFINE_UNQUOTED(_PATH_SUDO_ASKPASS, "$with_askpass")
+
 dnl
 dnl Options for --enable
 dnl
index 7d0dcadef979aab1d1894a1cfe70b4bfbd34015a..2a6f703a61f74d1c5eef39a2bbaad8bd741d62fb 100644 (file)
@@ -282,6 +282,10 @@ struct sudo_defs_types sudo_defs_table[] = {
        "type", T_STR,
        "SELinux type to use in the new security context: %s",
        NULL,
+    }, {
+       "askpass", T_STR|T_PATH,
+       "Path to the askpass helper program: %s",
+       NULL,
     }, {
        NULL, 0, NULL
     }
index 5f7c39ff0d77aeafcbaa362959933b2b6a21cf54..cc2ff70ec940251636351f48ed16aa184f2d2421 100644 (file)
 #define I_ROLE                  63
 #define def_type                (sudo_defs_table[64].sd_un.str)
 #define I_TYPE                  64
+#define def_askpass             (sudo_defs_table[65].sd_un.str)
+#define I_ASKPASS               65
 
 enum def_tupple {
        never,
index 16e457a920f5fa5d19435faedbc9f98a8e12a26c..cfc889222f099262ff4fa3c0afcd5417385870d5 100644 (file)
@@ -208,3 +208,6 @@ role
 type
        T_STR
        "SELinux type to use in the new security context: %s"
+askpass
+       T_STR|T_PATH
+       "Path to the askpass helper program: %s"
index a6a82d9f27e5326ee3ba170b2964b456346fac3f..5d0a0ffed08966d1951c7cb145e57fbfd24b845c 100644 (file)
@@ -422,6 +422,9 @@ init_defaults()
 #endif
 #ifdef ENV_EDITOR
     def_env_editor = TRUE;
+#endif
+#ifdef _PATH_SUDO_ASKPASS
+    def_askpass = _PATH_SUDO_ASKPASS;
 #endif
     def_env_reset = TRUE;
     def_set_logname = TRUE;
index b54877e22105573a1210eb23cbf6188728e25dbb..fa9ac48d44305858d02362cb54bb55f68768228f 100644 (file)
 #undef _PATH_SUDO_NOEXEC
 #endif /* _PATH_SUDO_NOEXEC */
 
+#ifndef _PATH_SUDO_ASKPASS
+#undef _PATH_SUDO_ASKPASS
+#endif /* _PATH_SUDO_ASKPASS */
+
 #ifndef _PATH_VI
 #undef _PATH_VI
 #endif /* _PATH_VI */
diff --git a/sudo.c b/sudo.c
index f36058be390a059cc9e9a5e927b8e6d7a1a3f3d6..c936d64b6fff04bf343dbe7f2b913a15483feb01 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -384,6 +384,15 @@ main(argc, argv, envp)
            (void) close(fd);
     }
 
+    /* Use askpass value from sudoers unless specified by the user. */
+    if (def_askpass && !user_askpass)
+       user_askpass = def_askpass;
+
+    /* If no tty is present but DISPLAY is set, use askpass if we have it. */
+    if (user_askpass && !ISSET(tgetpass_flags, TGP_STDIN) &&
+       user_ttypath == NULL && user_display != NULL && *user_display != '\0')
+       SET(tgetpass_flags, TGP_ASKPASS);
+
     /* User may have overriden environment resetting via the -E flag. */
     if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)
        def_env_reset = FALSE;
@@ -599,7 +608,12 @@ init_vars(sudo_mode, envp)
        user_tty = "unknown";
 
     for (ep = envp; *ep; ep++) {
+       /* XXX - don't fill in if empty string */
        switch (**ep) {
+           case 'D':
+               if (strncmp("DISPLAY=", *ep, 8) == 0)
+                   user_display = *ep + 8;
+               break;
            case 'K':
                if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
                    user_ccname = *ep + 11;
@@ -615,8 +629,9 @@ init_vars(sudo_mode, envp)
                    user_prompt = *ep + 12;
                else if (strncmp("SUDO_USER=", *ep, 10) == 0)
                    prev_user = *ep + 10;
+               else if (strncmp("SUDO_ASKPASS=", *ep, 13) == 0)
+                   user_askpass = *ep + 13;
                break;
-
            }
     }
 
@@ -810,6 +825,9 @@ parse_args(argc, argv)
            }
 
            switch (NewArgv[0][1]) {
+               case 'A':
+                   SET(tgetpass_flags, TGP_ASKPASS);
+                   break;
                case 'p':
                    /* Must have an associated prompt. */
                    if (NewArgv[1] == NULL)
diff --git a/sudo.h b/sudo.h
index 5b35d2bf993641b00590d7306fe2f5c38881980c..4c7daf396b02fd487752c4bfcfd982898936b89c 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996, 1998-2005, 2007
+ * Copyright (c) 1993-1996, 1998-2005, 2007-2008
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -54,6 +54,8 @@ struct sudo_user {
     char *cmnd_safe;
     char *class_name;
     char *krb5_ccname;
+    char *display;
+    char *askpass;
     int   ngroups;
     GETGROUPS_T *groups;
     struct list_member *env_vars;
@@ -147,6 +149,8 @@ struct sudo_user {
 #define user_host              (sudo_user.host)
 #define user_shost             (sudo_user.shost)
 #define user_ccname            (sudo_user.krb5_ccname)
+#define user_display           (sudo_user.display)
+#define user_askpass           (sudo_user.askpass)
 #define safe_cmnd              (sudo_user.cmnd_safe)
 #define login_class            (sudo_user.class_name)
 #define runas_pw               (sudo_user._runas_pw)
@@ -174,6 +178,7 @@ struct sudo_user {
  */
 #define TGP_ECHO       0x01            /* leave echo on when reading passwd */
 #define TGP_STDIN      0x02            /* read from stdin, not /dev/tty */
+#define TGP_ASKPASS    0x03            /* read from askpass helper program */
 
 struct lbuf;
 struct passwd;
index c48806ef6dfb8872769635014d4f5ac9e30ba9ea..e893e2d0e1e8ac0d03bdcafbbc209be57b85650d 100644 (file)
@@ -5,9 +5,9 @@
  * Usage strings for sudo.  These are here because we
  * need to be able to substitute values from configure.
  */
-#define SUDO_USAGE1 " -h | -K | -k | -L | -V | -v"
-#define SUDO_USAGE2 " -l[l] [-g groupname|#gid] [-U username] [-u username|#uid] [-g groupname|#gid] [command]"
-#define SUDO_USAGE3 " [-bEHPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]"
-#define SUDO_USAGE4 " -e [-S] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..."
+#define SUDO_USAGE1 " [-A] -h | -K | -k | -L | -V | -v"
+#define SUDO_USAGE2 " -l[l] [-A] [-g groupname|#gid] [-U username] [-u username|#uid] [-g groupname|#gid] [command]"
+#define SUDO_USAGE3 " [-AbEHPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]"
+#define SUDO_USAGE4 " -e [-AS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..."
 
 #endif /* _SUDO_USAGE_H */
index bb7cf3c27f127236222b5e6164a049bfe3e3e798..3b6031f6fd2fad9042775e53b62015fa1770be1d 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -122,6 +123,7 @@ static volatile sig_atomic_t signo;
 
 static void handler __P((int));
 static char *getln __P((int, char *, size_t));
+static char *sudo_askpass(const char *);
 
 /*
  * Like getpass(3) but with timeout and echo flags.
@@ -140,6 +142,11 @@ tgetpass(prompt, timeout, flags)
     int input, output, save_errno;
 
     (void) fflush(stdout);
+
+    /* If using a helper program to get the password, run it instead. */
+    if (ISSET(flags, TGP_ASKPASS) && user_askpass)
+       return(sudo_askpass(prompt));
+
 restart:
     signo = 0;
     pass = NULL;
@@ -232,6 +239,49 @@ restart:
     return(pass);
 }
 
+/*
+ * Fork a child and exec sudo-askpass to get the password from the user.
+ */
+static char *
+sudo_askpass(prompt)
+    const char *prompt;
+{
+    static char buf[SUDO_PASS_MAX + 1], *pass;
+    sigaction_t sa, saved_sa_pipe;
+    int pfd[2];
+    pid_t pid;
+
+    if (pipe(pfd) == -1)
+       error(1, "unable to create pipe");
+
+    if ((pid = fork()) == -1)
+       error(1, "unable to fork");
+
+    if (pid == 0) {
+       /* child, point stdout to output side of the pipe and exec askpass */
+       (void) dup2(pfd[1], STDOUT_FILENO);
+       set_perms(PERM_FULL_USER);
+       closefrom(STDERR_FILENO + 1);
+       execl(user_askpass, user_askpass, prompt, (char *)NULL);
+       warning("unable to run %s", user_askpass);
+       _exit(255);
+    }
+
+    /* Ignore SIGPIPE in case child exits prematurely */
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
+
+    /* Get response from child (askpass) and restore SIGPIPE handler */
+    (void) close(pfd[1]);
+    pass = getln(pfd[0], buf, sizeof(buf));
+    (void) close(pfd[0]);
+    (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
+
+    return(pass);
+}
+
 static char *
 getln(fd, buf, bufsiz)
     int fd;