Add support for running a helper program to read the password when
no tty is present (or when specified with the -A flag). TODO: docs.
This commit is contained in:
@@ -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,6 +195,7 @@ verify_user(pw, prompt)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ISSET(tgetpass_flags, TGP_ASKPASS))
|
||||
pass_warn(stderr);
|
||||
}
|
||||
|
||||
|
4
check.c
4
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,6 +99,7 @@ check_user(validated)
|
||||
status = timestamp_status(timestampdir, timestampfile, user_name,
|
||||
TS_MAKE_DIRS);
|
||||
if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
|
||||
if (!ISSET(tgetpass_flags, TGP_ASKPASS))
|
||||
lecture(status);
|
||||
|
||||
/* Expand any escapes in the prompt. */
|
||||
|
41
configure
vendored
41
configure
vendored
@@ -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
|
||||
|
11
configure.in
11
configure.in
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -128,6 +128,8 @@
|
||||
#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,
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
|
@@ -84,6 +84,10 @@
|
||||
#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 */
|
||||
|
20
sudo.c
20
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)
|
||||
|
7
sudo.h
7
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;
|
||||
|
@@ -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 */
|
||||
|
52
tgetpass.c
52
tgetpass.c
@@ -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;
|
||||
|
Reference in New Issue
Block a user