Implement memset_s() and use it instead of zero_bytes().

A new constant, SUDO_CONV_REPL_MAX, is defined by the plugin
API as the max conversation reply length.  This constant can be
used as a max value for memset_s() when clearing passwords
filled in by the conversation function.
This commit is contained in:
Todd C. Miller
2013-08-03 08:30:06 -06:00
parent 8c867be419
commit 1f3ea50afd
34 changed files with 371 additions and 233 deletions

View File

@@ -45,7 +45,6 @@ common/sudo_debug.c
common/sudo_printf.c common/sudo_printf.c
common/term.c common/term.c
common/ttysize.c common/ttysize.c
common/zero_bytes.c
compat/Makefile.in compat/Makefile.in
compat/charclass.h compat/charclass.h
compat/closefrom.c compat/closefrom.c
@@ -66,6 +65,7 @@ compat/glob.c
compat/glob.h compat/glob.h
compat/isblank.c compat/isblank.c
compat/memrchr.c compat/memrchr.c
compat/memset_s.c
compat/mksiglist.c compat/mksiglist.c
compat/mksiglist.h compat/mksiglist.h
compat/mksigname.c compat/mksigname.c

View File

@@ -68,7 +68,7 @@ SHELL = @SHELL@
LTOBJS = alloc.lo atobool.lo error.lo fileops.lo fmt_string.lo lbuf.lo list.lo \ LTOBJS = alloc.lo atobool.lo error.lo fileops.lo fmt_string.lo lbuf.lo list.lo \
secure_path.lo setgroups.lo sudo_conf.lo sudo_debug.lo sudo_printf.lo \ secure_path.lo setgroups.lo sudo_conf.lo sudo_debug.lo sudo_printf.lo \
term.lo ttysize.lo zero_bytes.lo @COMMON_OBJS@ term.lo ttysize.lo @COMMON_OBJS@
PARSELN_TEST_OBJS = parseln_test.lo PARSELN_TEST_OBJS = parseln_test.lo
@@ -218,6 +218,3 @@ term.lo: $(srcdir)/term.c $(top_builddir)/config.h $(incdir)/missing.h \
ttysize.lo: $(srcdir)/ttysize.c $(top_builddir)/config.h $(incdir)/missing.h \ ttysize.lo: $(srcdir)/ttysize.c $(top_builddir)/config.h $(incdir)/missing.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_debug.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/ttysize.c $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/ttysize.c
zero_bytes.lo: $(srcdir)/zero_bytes.c $(top_builddir)/config.h \
$(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/zero_bytes.c

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2003-2005, 2007, 2010
* 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <sys/types.h>
#include "missing.h"
/*
* Like bzero(3) but with a volatile pointer. The hope is that
* the compiler will not be able to optimize away this function.
*/
void
zero_bytes(volatile void *v, size_t n)
{
volatile char *p, *ep;
for (p = v, ep = p + n; p < ep; p++)
*p = 0;
return;
}

View File

@@ -199,6 +199,8 @@ isblank.lo: $(srcdir)/isblank.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/isblank.c $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/isblank.c
memrchr.lo: $(srcdir)/memrchr.c $(top_builddir)/config.h $(incdir)/missing.h memrchr.lo: $(srcdir)/memrchr.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/memrchr.c $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/memrchr.c
memset_s.lo: $(srcdir)/memset_s.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/memset_s.c
mksiglist.lo: $(srcdir)/mksiglist.c $(top_builddir)/config.h \ mksiglist.lo: $(srcdir)/mksiglist.c $(top_builddir)/config.h \
$(incdir)/missing.h $(top_srcdir)/compat/mksiglist.h $(incdir)/missing.h $(top_srcdir)/compat/mksiglist.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/mksiglist.c $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/mksiglist.c

71
compat/memset_s.c Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2013 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#if defined(HAVE_STDINT_H)
# include <stdint.h>
#elif defined(HAVE_INTTYPES_H)
# include <inttypes.h>
#endif
#include "missing.h"
#ifndef RSIZE_MAX
# if defined(SIZE_MAX)
# define RSIZE_MAX (SIZE_MAX >> 1)
# elif defined(__LP64__)
# define RSIZE_MAX 0x7fffffffffffffffUL
# else
# define RSIZE_MAX 0x7fffffffU
# endif
#endif
/*
* Simple implementation of C11 memset_s() function.
* We use a volatile pointer when updating the byte string.
* Most compilers will avoid optimizing away access to a
* volatile pointer, even if the pointer appears to be unused
* after the call.
*
* Note that C11 does not specify the return value on error, only
* that it be non-zero. We use EINVAL for all errors.
*/
errno_t
memset_s(void *v, rsize_t smax, int c, rsize_t n)
{
errno_t ret = 0;
volatile unsigned char *s = v;
/* Fatal runtime-constraint violations. */
if (s == NULL || smax > RSIZE_MAX) {
ret = errno = EINVAL;
goto done;
}
/* Non-fatal runtime-constraint violation, n must not exceed smax. */
if (n > smax) {
n = smax;
ret = errno = EINVAL;
}
/* Updating through a volatile pointer should not be optimized away. */
while (n--)
*s++ = (unsigned char)c;
done:
return ret;
}

View File

@@ -373,6 +373,9 @@
/* Define to 1 if you have the `memrchr' function. */ /* Define to 1 if you have the `memrchr' function. */
#undef HAVE_MEMRCHR #undef HAVE_MEMRCHR
/* Define to 1 if you have the `memset_s' function. */
#undef HAVE_MEMSET_S
/* Define to 1 if you have the `mkdtemp' function. */ /* Define to 1 if you have the `mkdtemp' function. */
#undef HAVE_MKDTEMP #undef HAVE_MKDTEMP
@@ -948,6 +951,9 @@
/* Define to `int' if <sys/types.h> does not define. */ /* Define to `int' if <sys/types.h> does not define. */
#undef dev_t #undef dev_t
/* Define to `int' if <sys/types.h> does not define. */
#undef errno_t
/* Define to `int' if <sys/types.h> doesn't define. */ /* Define to `int' if <sys/types.h> doesn't define. */
#undef gid_t #undef gid_t
@@ -960,6 +966,9 @@
/* Define to an OS-specific initialization function or `os_init_common'. */ /* Define to an OS-specific initialization function or `os_init_common'. */
#undef os_init #undef os_init
/* Define to `size_t' if <sys/types.h> does not define. */
#undef rsize_t
/* Define to `int' if <signal.h> does not define. */ /* Define to `int' if <signal.h> does not define. */
#undef sig_atomic_t #undef sig_atomic_t

48
configure vendored
View File

@@ -15979,6 +15979,19 @@ fi
fi fi
case "${CPPFLAGS}" in
*"-D__STDC_WANT_LIB_EXT1__=1"|*"-D__STDC_WANT_LIB_EXT1__=1 ")
;;
*)
if test X"${CPPFLAGS}" = X""; then
CPPFLAGS="-D__STDC_WANT_LIB_EXT1__=1"
else
CPPFLAGS="${CPPFLAGS} -D__STDC_WANT_LIB_EXT1__=1"
fi
;;
esac
ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default"
if test "x$ac_cv_type_mode_t" = xyes; then : if test "x$ac_cv_type_mode_t" = xyes; then :
@@ -16299,6 +16312,28 @@ else
fi fi
ac_fn_c_check_type "$LINENO" "rsize_t" "ac_cv_type_rsize_t" "$ac_includes_default"
if test "x$ac_cv_type_rsize_t" = xyes; then :
else
cat >>confdefs.h <<_ACEOF
#define rsize_t size_t
_ACEOF
fi
ac_fn_c_check_type "$LINENO" "errno_t" "ac_cv_type_errno_t" "$ac_includes_default"
if test "x$ac_cv_type_errno_t" = xyes; then :
else
cat >>confdefs.h <<_ACEOF
#define errno_t int
_ACEOF
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking max length of uid_t" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking max length of uid_t" >&5
$as_echo_n "checking max length of uid_t... " >&6; } $as_echo_n "checking max length of uid_t... " >&6; }
@@ -17543,6 +17578,19 @@ esac
fi fi
ac_fn_c_check_func "$LINENO" "memset_s" "ac_cv_func_memset_s"
if test "x$ac_cv_func_memset_s" = xyes; then :
$as_echo "#define HAVE_MEMSET_S 1" >>confdefs.h
else
case " $LIBOBJS " in
*" memset_s.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS memset_s.$ac_objext"
;;
esac
fi
ac_fn_c_check_func "$LINENO" "pw_dup" "ac_cv_func_pw_dup" ac_fn_c_check_func "$LINENO" "pw_dup" "ac_cv_func_pw_dup"
if test "x$ac_cv_func_pw_dup" = xyes; then : if test "x$ac_cv_func_pw_dup" = xyes; then :
$as_echo "#define HAVE_PW_DUP 1" >>confdefs.h $as_echo "#define HAVE_PW_DUP 1" >>confdefs.h

View File

@@ -2143,7 +2143,9 @@ if test ${with_project-'no'} != "no"; then
fi fi
dnl dnl
dnl typedef checks dnl typedef checks
dnl We need to define __STDC_WANT_LIB_EXT1__ for errno_t and rsize_t
dnl dnl
SUDO_APPEND_CPPFLAGS(-D__STDC_WANT_LIB_EXT1__=1)
AC_TYPE_MODE_T AC_TYPE_MODE_T
AC_TYPE_UID_T AC_TYPE_UID_T
AC_CHECK_TYPE([__signed char], [], [AC_CHECK_TYPE([signed char], [AC_DEFINE(__signed, signed)], [AC_DEFINE(__signed, [])])]) AC_CHECK_TYPE([__signed char], [], [AC_CHECK_TYPE([signed char], [AC_DEFINE(__signed, signed)], [AC_DEFINE(__signed, [])])])
@@ -2173,6 +2175,8 @@ AC_CHECK_TYPE(uint64_t, unsigned long long)
AC_CHECK_TYPE(socklen_t, [], [AC_DEFINE(socklen_t, unsigned int)], [ AC_CHECK_TYPE(socklen_t, [], [AC_DEFINE(socklen_t, unsigned int)], [
AC_INCLUDES_DEFAULT AC_INCLUDES_DEFAULT
#include <sys/socket.h>]) #include <sys/socket.h>])
AC_CHECK_TYPE(rsize_t, size_t)
AC_CHECK_TYPE(errno_t, int)
SUDO_UID_T_LEN SUDO_UID_T_LEN
SUDO_SOCK_SA_LEN SUDO_SOCK_SA_LEN
dnl dnl
@@ -2348,7 +2352,7 @@ SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch)
COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }fnm_test" COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }fnm_test"
]) ])
SUDO_FUNC_ISBLANK SUDO_FUNC_ISBLANK
AC_REPLACE_FUNCS(getopt_long memrchr pw_dup strlcpy strlcat) AC_REPLACE_FUNCS(getopt_long memrchr memset_s pw_dup strlcpy strlcat)
AC_CHECK_FUNCS(nanosleep, [], [ AC_CHECK_FUNCS(nanosleep, [], [
# On Solaris, nanosleep is in librt # On Solaris, nanosleep is in librt
AC_CHECK_LIB(rt, nanosleep, [REPLAY_LIBS="${REPLAY_LIBS} -lrt"], [AC_LIBOBJ(nanosleep)]) AC_CHECK_LIB(rt, nanosleep, [REPLAY_LIBS="${REPLAY_LIBS} -lrt"], [AC_LIBOBJ(nanosleep)])

View File

@@ -1229,6 +1229,8 @@ DDEESSCCRRIIPPTTIIOONN
const char *msg; const char *msg;
}; };
#define SUDO_CONV_REPL_MAX 255
struct sudo_conv_reply { struct sudo_conv_reply {
char *reply; char *reply;
}; };
@@ -1246,7 +1248,12 @@ DDEESSCCRRIIPPTTIIOONN
sudo_conv_message and sudo_conv_reply structures. There must be a struct sudo_conv_message and sudo_conv_reply structures. There must be a struct
sudo_conv_message and struct sudo_conv_reply for each message in the sudo_conv_message and struct sudo_conv_reply for each message in the
conversation. The plugin is responsible for freeing the reply buffer conversation. The plugin is responsible for freeing the reply buffer
filled in to the struct sudo_conv_reply, if any. located in each struct sudo_conv_reply, if it is not NULL.
SUDO_CONV_REPL_MAX represents the maximum length of the reply buffer (not
including the trailing NUL character). In practical terms, this is the
longest password ssuuddoo will support. It is also useful as a maximum value
for the mmeemmsseett__ss() function when clearing passwords filled in by the
conversation function.
The pprriinnttff()-style function uses the same underlying mechanism as the The pprriinnttff()-style function uses the same underlying mechanism as the
ccoonnvveerrssaattiioonn() function but only supports SUDO_CONV_INFO_MSG, ccoonnvveerrssaattiioonn() function but only supports SUDO_CONV_INFO_MSG,

View File

@@ -107,15 +107,15 @@ to determine the API version the plugin was
built against. built against.
.TP 6n .TP 6n
open open
.RS
.nf .nf
.RS 6n .RS 0n
int (*open)(unsigned int version, sudo_conv_t conversation, int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[], sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const user_env[], char * const user_info[], char * const user_env[],
char * const plugin_options[]); char * const plugin_options[]);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
Returns 1 on success, 0 on failure, \-1 if a general error occurred, Returns 1 on success, 0 on failure, \-1 if a general error occurred,
or \-2 if there was a usage error. or \-2 if there was a usage error.
@@ -156,7 +156,7 @@ settings
A vector of user-supplied A vector of user-supplied
\fBsudo\fR \fBsudo\fR
settings in the form of settings in the form of
\(lqname=value\(rq ``name=value''
strings. strings.
The vector is terminated by a The vector is terminated by a
\fRNULL\fR \fRNULL\fR
@@ -171,23 +171,20 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
itself but the itself but the
\fIvalue\fR \fIvalue\fR
might. might.
.PP .RS
.RS 6n
.PD 0
.TP 6n .TP 6n
bsdauth_type=string bsdauth_type=string
Authentication type, if specified by the Authentication type, if specified by the
\fB\-a\fR \fB\-a\fR
flag, to use on flag, to use on
systems where BSD authentication is supported. systems where BSD authentication is supported.
.PD
.TP 6n .TP 6n
closefrom=number closefrom=number
If specified, the user has requested via the If specified, the user has requested via the
@@ -218,7 +215,7 @@ plugin is
\fIsubsystem\fR@\fIpriority\fR \fIsubsystem\fR@\fIpriority\fR
but the plugin is free to use a different but the plugin is free to use a different
format so long as it does not include a comma format so long as it does not include a comma
(\(oq,\&\(cq). (`,\&').
There is not currently a way to specify a set of debug flags specific There is not currently a way to specify a set of debug flags specific
to the plugin--the flags are shared by to the plugin--the flags are shared by
\fBsudo\fR \fBsudo\fR
@@ -274,13 +271,13 @@ sudo.conf(@mansectform@).
network_addrs=list network_addrs=list
A space-separated list of IP network addresses and netmasks in the A space-separated list of IP network addresses and netmasks in the
form form
\(lqaddr/netmask\(rq, ``addr/netmask'',
e.g.\& e.g.\&
\(lq192.168.1.2/255.255.255.0\(rq. ``192.168.1.2/255.255.255.0''.
The address and netmask pairs may be either IPv4 or IPv6, depending on The address and netmask pairs may be either IPv4 or IPv6, depending on
what the operating system supports. what the operating system supports.
If the address contains a colon If the address contains a colon
(\(oq:\&\(cq), (`:\&'),
it is an IPv6 address, else it is IPv4. it is an IPv6 address, else it is IPv4.
.TP 6n .TP 6n
noninteractive=bool noninteractive=bool
@@ -315,9 +312,9 @@ based on the runas user.
.TP 6n .TP 6n
progname=string progname=string
The command name that sudo was run as, typically The command name that sudo was run as, typically
\(lqsudo\(rq ``sudo''
or or
\(lqsudoedit\(rq. ``sudoedit''.
.TP 6n .TP 6n
prompt=string prompt=string
The prompt to use when requesting a password, if specified via The prompt to use when requesting a password, if specified via
@@ -391,11 +388,13 @@ section.
.PP .PP
Additional settings may be added in the future so the plugin should Additional settings may be added in the future so the plugin should
silently ignore settings that it does not recognize. silently ignore settings that it does not recognize.
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
user_info user_info
A vector of information about the user running the command in the form of A vector of information about the user running the command in the form of
\(lqname=value\(rq ``name=value''
strings. strings.
The vector is terminated by a The vector is terminated by a
\fRNULL\fR \fRNULL\fR
@@ -406,21 +405,19 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
itself but the itself but the
\fIvalue\fR \fIvalue\fR
might. might.
.PP .RS
.RS 6n .PD
.PD 0
.TP 6n .TP 6n
cols=int cols=int
The number of columns the user's terminal supports. The number of columns the user's terminal supports.
If there is no terminal device available, a default value of 80 is used. If there is no terminal device available, a default value of 80 is used.
.PD
.TP 6n .TP 6n
cwd=string cwd=string
The user's current working directory. The user's current working directory.
@@ -516,7 +513,7 @@ tty=string
The path to the user's terminal device. The path to the user's terminal device.
If the user has no terminal device associated with the session, If the user has no terminal device associated with the session,
the value will be empty, as in the value will be empty, as in
\(lq\fRtty=\fR\(rq. ``\fRtty=\fR''.
.TP 6n .TP 6n
uid=uid_t uid=uid_t
The real user ID of the user invoking The real user ID of the user invoking
@@ -525,15 +522,14 @@ The real user ID of the user invoking
user=string user=string
The name of the user invoking The name of the user invoking
\fBsudo\fR. \fBsudo\fR.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
user_env user_env
The user's environment in the form of a The user's environment in the form of a
\fRNULL\fR-terminated vector of \fRNULL\fR-terminated vector of
\(lqname=value\(rq ``name=value''
strings. strings.
.sp .sp
When parsing When parsing
@@ -541,26 +537,26 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
itself but the itself but the
\fIvalue\fR \fIvalue\fR
might. might.
.PD 0 .PD
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
close close
.br .br
.RS
.nf .nf
.RS 6n .RS 0n
void (*close)(int exit_status, int error); void (*close)(int exit_status, int error);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBclose\fR() \fBclose\fR()
@@ -569,6 +565,7 @@ function is called when the command being run by
finishes. finishes.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
exit_status exit_status
The command's exit status, as returned by the The command's exit status, as returned by the
@@ -609,15 +606,17 @@ list, the
\fBsudo\fR \fBsudo\fR
front end may execute the command directly instead of running front end may execute the command directly instead of running
it as a child process. it as a child process.
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
show_version show_version
.RS
.nf .nf
.RS 6n .RS 0n
int (*show_version)(int verbose); int (*show_version)(int verbose);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBshow_version\fR() \fBshow_version\fR()
@@ -634,17 +633,20 @@ or
function using function using
\fRSUDO_CONV_INFO_MSG\fR. \fRSUDO_CONV_INFO_MSG\fR.
If the user requests detailed version information, the verbose flag will be set. If the user requests detailed version information, the verbose flag will be set.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
check_policy check_policy
.RS
.nf .nf
.RS 6n .RS 0n
int (*check_policy)(int argc, char * const argv[] int (*check_policy)(int argc, char * const argv[]
char *env_add[], char **command_info[], char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]); char **argv_out[], char **user_env_out[]);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBcheck_policy\fR() \fBcheck_policy\fR()
@@ -686,10 +688,10 @@ into
\fIargv_out\fR, \fIargv_out\fR,
separated from the separated from the
editor and its arguments by a editor and its arguments by a
\(lq\fR--\fR\(rq ``\fR--\fR''
element. element.
The The
\(lq\fR--\fR\(rq ``\fR--\fR''
will will
be removed by be removed by
\fBsudo\fR \fBsudo\fR
@@ -720,6 +722,7 @@ function with
to present additional error information to the user. to present additional error information to the user.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
argc argc
The number of elements in The number of elements in
@@ -742,7 +745,7 @@ Additional environment variables specified by the user on the command
line in the form of a line in the form of a
\fRNULL\fR-terminated \fRNULL\fR-terminated
vector of vector of
\(lqname=value\(rq ``name=value''
strings. strings.
The plugin may reject the command if one or more variables The plugin may reject the command if one or more variables
are not allowed to be set, or it may silently ignore such variables. are not allowed to be set, or it may silently ignore such variables.
@@ -752,7 +755,7 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
@@ -762,7 +765,7 @@ might.
.TP 6n .TP 6n
command_info command_info
Information about the command being run in the form of Information about the command being run in the form of
\(lqname=value\(rq ``name=value''
strings. strings.
These values are used by These values are used by
\fBsudo\fR \fBsudo\fR
@@ -774,13 +777,10 @@ which must be terminated with a
pointer. pointer.
The following values are recognized by The following values are recognized by
\fBsudo\fR: \fBsudo\fR:
.PP .RS
.RS 6n
.PD 0
.TP 6n .TP 6n
chroot=string chroot=string
The root directory to use when running the command. The root directory to use when running the command.
.PD
.TP 6n .TP 6n
closefrom=number closefrom=number
If specified, If specified,
@@ -995,7 +995,9 @@ will base the new entry on
the invoking user's existing entry. the invoking user's existing entry.
.PP .PP
Unsupported values will be ignored. Unsupported values will be ignored.
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
argv_out argv_out
The The
@@ -1004,25 +1006,25 @@ argument vector to pass to the
execve(2) execve(2)
system call when executing the command. system call when executing the command.
The plugin is responsible for allocating and populating the vector. The plugin is responsible for allocating and populating the vector.
.PD
.TP 6n .TP 6n
user_env_out user_env_out
The The
\fRNULL\fR-terminated \fRNULL\fR-terminated
environment vector to use when executing the command. environment vector to use when executing the command.
The plugin is responsible for allocating and populating the vector. The plugin is responsible for allocating and populating the vector.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
list list
.RS
.nf .nf
.RS 6n .RS 0n
int (*list)(int verbose, const char *list_user, int (*list)(int verbose, const char *list_user,
int argc, char * const argv[]); int argc, char * const argv[]);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
List available privileges for the invoking user. List available privileges for the invoking user.
Returns 1 on success, 0 on failure and \-1 on error. Returns 1 on success, 0 on failure and \-1 on error.
@@ -1041,6 +1043,7 @@ or
\fBplugin_printf\fR() \fBplugin_printf\fR()
function using function using
\fRSUDO_CONV_INFO_MSG\fR, \fRSUDO_CONV_INFO_MSG\fR,
.PD
.TP 6n .TP 6n
verbose verbose
Flag indicating whether to list in verbose mode or not. Flag indicating whether to list in verbose mode or not.
@@ -1069,18 +1072,17 @@ execve(2)
system call. system call.
If the command is permitted by the policy, the fully-qualified path If the command is permitted by the policy, the fully-qualified path
to the command should be displayed along with any command line arguments. to the command should be displayed along with any command line arguments.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
validate validate
.RS
.nf .nf
.RS 6n .RS 0n
int (*validate)(void); int (*validate)(void);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBvalidate\fR() \fBvalidate\fR()
@@ -1110,15 +1112,18 @@ function with
\fRSUDO_CONF_ERROR_MSG\fR \fRSUDO_CONF_ERROR_MSG\fR
to present additional to present additional
error information to the user. error information to the user.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
invalidate invalidate
.RS
.nf .nf
.RS 6n .RS 0n
void (*invalidate)(int remove); void (*invalidate)(int remove);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBinvalidate\fR() \fBinvalidate\fR()
@@ -1145,15 +1150,18 @@ The
function should be function should be
\fRNULL\fR \fRNULL\fR
if the plugin does not support credential caching. if the plugin does not support credential caching.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
init_session init_session
.RS
.nf .nf
.RS 6n .RS 0n
int (*init_session)(struct passwd *pwd, char **user_envp[); int (*init_session)(struct passwd *pwd, char **user_envp[);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBinit_session\fR() \fBinit_session\fR()
@@ -1186,7 +1194,7 @@ argument points to the environment the command will
run in, in the form of a run in, in the form of a
\fRNULL\fR-terminated \fRNULL\fR-terminated
vector of vector of
\(lqname=value\(rq ``name=value''
strings. strings.
This is the same string passed back to the front end via This is the same string passed back to the front end via
the Policy Plugin's the Policy Plugin's
@@ -1222,16 +1230,19 @@ function with
\fRSUDO_CONF_ERROR_MSG\fR \fRSUDO_CONF_ERROR_MSG\fR
to present additional to present additional
error information to the user. error information to the user.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
register_hooks register_hooks
.RS
.nf .nf
.RS 6n .RS 0n
void (*register_hooks)(int version, void (*register_hooks)(int version,
int (*register_hook)(struct sudo_hook *hook)); int (*register_hook)(struct sudo_hook *hook));
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBregister_hooks\fR() \fBregister_hooks\fR()
@@ -1274,16 +1285,19 @@ front end doesn't support API
version 1.2 or higher, version 1.2 or higher,
\fRregister_hooks\fR \fRregister_hooks\fR
will not be called. will not be called.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
deregister_hooks deregister_hooks
.RS
.nf .nf
.RS 6n .RS 0n
void (*deregister_hooks)(int version, void (*deregister_hooks)(int version,
int (*deregister_hook)(struct sudo_hook *hook)); int (*deregister_hook)(struct sudo_hook *hook));
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBderegister_hooks\fR() \fBderegister_hooks\fR()
@@ -1328,6 +1342,7 @@ version 1.2 or higher,
\fRderegister_hooks\fR \fRderegister_hooks\fR
will not be called. will not be called.
.RE .RE
.PD
.PP .PP
\fIPolicy Plugin Version Macros\fR \fIPolicy Plugin Version Macros\fR
.nf .nf
@@ -1428,15 +1443,15 @@ to determine the API version the plugin was
built against. built against.
.TP 6n .TP 6n
open open
.RS
.nf .nf
.RS 6n .RS 0n
int (*open)(unsigned int version, sudo_conv_t conversation, int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[], sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], int argc, char * const argv[], char * const user_info[], int argc, char * const argv[],
char * const user_env[], char * const plugin_options[]); char * const user_env[], char * const plugin_options[]);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBopen\fR() \fBopen\fR()
@@ -1506,7 +1521,7 @@ settings
A vector of user-supplied A vector of user-supplied
\fBsudo\fR \fBsudo\fR
settings in the form of settings in the form of
\(lqname=value\(rq ``name=value''
strings. strings.
The vector is terminated by a The vector is terminated by a
\fRNULL\fR \fRNULL\fR
@@ -1521,7 +1536,7 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
@@ -1535,7 +1550,7 @@ section for a list of all possible settings.
.TP 6n .TP 6n
user_info user_info
A vector of information about the user running the command in the form of A vector of information about the user running the command in the form of
\(lqname=value\(rq ``name=value''
strings. strings.
The vector is terminated by a The vector is terminated by a
\fRNULL\fR \fRNULL\fR
@@ -1546,7 +1561,7 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
@@ -1577,7 +1592,7 @@ user_env
The user's environment in the form of a The user's environment in the form of a
\fRNULL\fR-terminated \fRNULL\fR-terminated
vector of vector of
\(lqname=value\(rq ``name=value''
strings. strings.
.sp .sp
When parsing When parsing
@@ -1585,7 +1600,7 @@ When parsing
the plugin should split on the the plugin should split on the
\fBfirst\fR \fBfirst\fR
equal sign equal sign
(\(oq=\(cq) (`=')
since the since the
\fIname\fR \fIname\fR
field will never include one field will never include one
@@ -1618,19 +1633,18 @@ by the
front end before using front end before using
\fIplugin_options\fR. \fIplugin_options\fR.
Failure to do so may result in a crash. Failure to do so may result in a crash.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
close close
.br .br
.RS
.nf .nf
.RS 6n .RS 0n
void (*close)(int exit_status, int error); void (*close)(int exit_status, int error);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBclose\fR() \fBclose\fR()
@@ -1639,6 +1653,7 @@ function is called when the command being run by
finishes. finishes.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
exit_status exit_status
The command's exit status, as returned by the The command's exit status, as returned by the
@@ -1660,18 +1675,17 @@ system call.
If the command was successfully executed, the value of If the command was successfully executed, the value of
\fRerror\fR \fRerror\fR
is 0. is 0.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
show_version show_version
.RS
.nf .nf
.RS 6n .RS 0n
int (*show_version)(int verbose); int (*show_version)(int verbose);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBshow_version\fR() \fBshow_version\fR()
@@ -1688,15 +1702,18 @@ or
function using function using
\fRSUDO_CONV_INFO_MSG\fR. \fRSUDO_CONV_INFO_MSG\fR.
If the user requests detailed version information, the verbose flag will be set. If the user requests detailed version information, the verbose flag will be set.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
log_ttyin log_ttyin
.RS
.nf .nf
.RS 6n .RS 0n
int (*log_ttyin)(const char *buf, unsigned int len); int (*log_ttyin)(const char *buf, unsigned int len);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBlog_ttyin\fR() \fBlog_ttyin\fR()
@@ -1708,6 +1725,7 @@ Returns 1 if the data should be passed to the command, 0 if the data
is rejected (which will terminate the command) or \-1 if an error occurred. is rejected (which will terminate the command) or \-1 if an error occurred.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
buf buf
The buffer containing user input. The buffer containing user input.
@@ -1716,18 +1734,17 @@ len
The length of The length of
\fIbuf\fR \fIbuf\fR
in bytes. in bytes.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
log_ttyout log_ttyout
.RS
.nf .nf
.RS 6n .RS 0n
int (*log_ttyout)(const char *buf, unsigned int len); int (*log_ttyout)(const char *buf, unsigned int len);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBlog_ttyout\fR() \fBlog_ttyout\fR()
@@ -1739,6 +1756,7 @@ Returns 1 if the data should be passed to the user, 0 if the data is rejected
(which will terminate the command) or \-1 if an error occurred. (which will terminate the command) or \-1 if an error occurred.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
buf buf
The buffer containing command output. The buffer containing command output.
@@ -1747,18 +1765,17 @@ len
The length of The length of
\fIbuf\fR \fIbuf\fR
in bytes. in bytes.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
log_stdin log_stdin
.RS
.nf .nf
.RS 6n .RS 0n
int (*log_stdin)(const char *buf, unsigned int len); int (*log_stdin)(const char *buf, unsigned int len);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBlog_stdin\fR() \fBlog_stdin\fR()
@@ -1772,6 +1789,7 @@ Returns 1 if the data should be passed to the command, 0 if the data is
rejected (which will terminate the command) or \-1 if an error occurred. rejected (which will terminate the command) or \-1 if an error occurred.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
buf buf
The buffer containing user input. The buffer containing user input.
@@ -1780,18 +1798,17 @@ len
The length of The length of
\fIbuf\fR \fIbuf\fR
in bytes. in bytes.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
log_stdout log_stdout
.RS
.nf .nf
.RS 6n .RS 0n
int (*log_stdout)(const char *buf, unsigned int len); int (*log_stdout)(const char *buf, unsigned int len);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBlog_stdout\fR() \fBlog_stdout\fR()
@@ -1805,6 +1822,7 @@ Returns 1 if the data should be passed to the user, 0 if the data is
rejected (which will terminate the command) or \-1 if an error occurred. rejected (which will terminate the command) or \-1 if an error occurred.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
buf buf
The buffer containing command output. The buffer containing command output.
@@ -1813,18 +1831,17 @@ len
The length of The length of
\fIbuf\fR \fIbuf\fR
in bytes. in bytes.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
log_stderr log_stderr
.RS
.nf .nf
.RS 6n .RS 0n
int (*log_stderr)(const char *buf, unsigned int len); int (*log_stderr)(const char *buf, unsigned int len);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBlog_stderr\fR() \fBlog_stderr\fR()
@@ -1838,6 +1855,7 @@ Returns 1 if the data should be passed to the user, 0 if the data is
rejected (which will terminate the command) or \-1 if an error occurred. rejected (which will terminate the command) or \-1 if an error occurred.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
buf buf
The buffer containing command output. The buffer containing command output.
@@ -1846,16 +1864,16 @@ len
The length of The length of
\fIbuf\fR \fIbuf\fR
in bytes. in bytes.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
register_hooks register_hooks
See the See the
\fIPolicy plugin API\fR \fIPolicy plugin API\fR
section for a description of section for a description of
\fRregister_hooks\fR. \fRregister_hooks\fR.
.PD
.TP 6n .TP 6n
deregister_hooks deregister_hooks
See the See the
@@ -1962,9 +1980,7 @@ hook_type
The The
\fRhook_type\fR \fRhook_type\fR
field may be one of the following supported hook types: field may be one of the following supported hook types:
.PP .RS
.RS 6n
.PD 0
.TP 6n .TP 6n
\fRSUDO_HOOK_SETENV\fR \fRSUDO_HOOK_SETENV\fR
The C library The C library
@@ -1975,19 +1991,20 @@ The
\fRhook_fn\fR \fRhook_fn\fR
field should field should
be a function that matches the following typedef: be a function that matches the following typedef:
.RS
.nf .nf
.sp .sp
.RS 6n .RS 0n
typedef int (*sudo_hook_fn_setenv_t)(const char *name, typedef int (*sudo_hook_fn_setenv_t)(const char *name,
const char *value, int overwrite, void *closure); const char *value, int overwrite, void *closure);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
If the registered hook does not match the typedef the results are If the registered hook does not match the typedef the results are
unspecified. unspecified.
.PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
\fRSUDO_HOOK_UNSETENV\fR \fRSUDO_HOOK_UNSETENV\fR
The C library The C library
@@ -1998,13 +2015,18 @@ The
\fRhook_fn\fR \fRhook_fn\fR
field should field should
be a function that matches the following typedef: be a function that matches the following typedef:
.RS
.nf .nf
.sp .sp
.RS 6n .RS 0n
typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, typedef int (*sudo_hook_fn_unsetenv_t)(const char *name,
void *closure); void *closure);
.RE .RE
.fi .fi
.PD
.PP
.RE
.PD 0
.TP 6n .TP 6n
\fRSUDO_HOOK_GETENV\fR \fRSUDO_HOOK_GETENV\fR
The C library The C library
@@ -2015,18 +2037,21 @@ The
\fRhook_fn\fR \fRhook_fn\fR
field should field should
be a function that matches the following typedef: be a function that matches the following typedef:
.RS
.nf .nf
.sp .sp
.RS 6n .RS 0n
typedef int (*sudo_hook_fn_getenv_t)(const char *name, typedef int (*sudo_hook_fn_getenv_t)(const char *name,
char **value, void *closure); char **value, void *closure);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
If the registered hook does not match the typedef the results are If the registered hook does not match the typedef the results are
unspecified. unspecified.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
\fRSUDO_HOOK_PUTENV\fR \fRSUDO_HOOK_PUTENV\fR
The C library The C library
@@ -2037,22 +2062,22 @@ The
\fRhook_fn\fR \fRhook_fn\fR
field should field should
be a function that matches the following typedef: be a function that matches the following typedef:
.RS
.nf .nf
.sp .sp
.RS 6n .RS 0n
typedef int (*sudo_hook_fn_putenv_t)(char *string, typedef int (*sudo_hook_fn_putenv_t)(char *string,
void *closure); void *closure);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
If the registered hook does not match the typedef the results are If the registered hook does not match the typedef the results are
unspecified. unspecified.
.RE .RE
.PD 0 .PD
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
hook_fn hook_fn
sudo_hook_fn_t hook_fn; sudo_hook_fn_t hook_fn;
@@ -2073,13 +2098,11 @@ is passed as the last function parameter.
This can be used to pass arbitrary data to the plugin's hook implementation. This can be used to pass arbitrary data to the plugin's hook implementation.
.sp .sp
The function return value may be one of the following: The function return value may be one of the following:
.PP .RS
.RS 6n .PD
.PD 0
.TP 6n .TP 6n
\fRSUDO_HOOK_RET_ERROR\fR \fRSUDO_HOOK_RET_ERROR\fR
The hook function encountered an error. The hook function encountered an error.
.PD
.TP 6n .TP 6n
\fRSUDO_HOOK_RET_NEXT\fR \fRSUDO_HOOK_RET_NEXT\fR
The hook completed without error, go on to the next hook (including The hook completed without error, go on to the next hook (including
@@ -2099,10 +2122,7 @@ hook that operates on a private copy of
the environment but leaves the environment but leaves
\fRenviron\fR \fRenviron\fR
unchanged. unchanged.
.PD 0
.PP
.RE .RE
.PD
.PP .PP
Note that it is very easy to create an infinite loop when hooking Note that it is very easy to create an infinite loop when hooking
C library functions. C library functions.
@@ -2184,6 +2204,8 @@ struct sudo_conv_message {
const char *msg; const char *msg;
}; };
#define SUDO_CONV_REPL_MAX 255
struct sudo_conv_reply { struct sudo_conv_reply {
char *reply; char *reply;
}; };
@@ -2218,9 +2240,19 @@ and
\fRstruct sudo_conv_reply\fR \fRstruct sudo_conv_reply\fR
for for
each message in the conversation. each message in the conversation.
The plugin is responsible for freeing the reply buffer filled in to the The plugin is responsible for freeing the reply buffer located in each
\fRstruct sudo_conv_reply\fR, \fRstruct sudo_conv_reply\fR,
if any. if it is not
\fRNULL\fR.
\fRSUDO_CONV_REPL_MAX\fR
represents the maximum length of the reply buffer (not including
the trailing NUL character).
In practical terms, this is the longest password
\fBsudo\fR
will support.
It is also useful as a maximum value for the
\fBmemset_s\fR()
function when clearing passwords filled in by the conversation function.
.PP .PP
The The
\fBprintf\fR()-style \fBprintf\fR()-style
@@ -2313,13 +2345,13 @@ to determine the API version the group plugin
was built against. was built against.
.TP 6n .TP 6n
init init
.RS
.nf .nf
.RS 6n .RS 0n
int (*init)(int version, sudo_printf_t plugin_printf, int (*init)(int version, sudo_printf_t plugin_printf,
char *const argv[]); char *const argv[]);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBinit\fR() \fBinit\fR()
@@ -2362,18 +2394,17 @@ If no arguments were given,
\fIargv\fR \fIargv\fR
will be will be
\fRNULL\fR. \fRNULL\fR.
.PD 0
.PP .PP
.RE .RE
.PD .PD 0
.TP 6n .TP 6n
cleanup cleanup
.RS
.nf .nf
.RS 6n .RS 0n
void (*cleanup)(); void (*cleanup)();
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBcleanup\fR() \fBcleanup\fR()
@@ -2382,17 +2413,20 @@ function is called when
has finished its has finished its
group checks. group checks.
The plugin should free any memory it has allocated and close open file handles. The plugin should free any memory it has allocated and close open file handles.
.PD
.PP
.RE .RE
.PD 0
.TP 6n .TP 6n
query query
.br .br
.RS
.nf .nf
.RS 6n .RS 0n
int (*query)(const char *user, const char *group, int (*query)(const char *user, const char *group,
const struct passwd *pwd); const struct passwd *pwd);
.RE .RE
.fi .fi
.RS 6n
.sp .sp
The The
\fBquery\fR() \fBquery\fR()
@@ -2402,6 +2436,7 @@ is a member of
\fIgroup\fR. \fIgroup\fR.
.sp .sp
The function arguments are as follows: The function arguments are as follows:
.PD
.TP 6n .TP 6n
user user
The name of the user being looked up in the external group database. The name of the user being looked up in the external group database.
@@ -2421,10 +2456,7 @@ present in the password database,
\fIpwd\fR \fIpwd\fR
will be will be
\fRNULL\fR. \fRNULL\fR.
.PD 0
.PP
.RE .RE
.PD
.PP .PP
\fIGroup API Version Macros\fR \fIGroup API Version Macros\fR
.nf .nf
@@ -2537,7 +2569,7 @@ search the archives.
.SH "DISCLAIMER" .SH "DISCLAIMER"
\fBsudo\fR \fBsudo\fR
is provided is provided
\(lqAS IS\(rq ``AS IS''
and any express or implied warranties, including, but not limited and any express or implied warranties, including, but not limited
to, the implied warranties of merchantability and fitness for a to, the implied warranties of merchantability and fitness for a
particular purpose are disclaimed. particular purpose are disclaimed.

View File

@@ -1893,6 +1893,8 @@ struct sudo_conv_message {
const char *msg; const char *msg;
}; };
#define SUDO_CONV_REPL_MAX 255
struct sudo_conv_reply { struct sudo_conv_reply {
char *reply; char *reply;
}; };
@@ -1926,9 +1928,19 @@ and
.Li struct sudo_conv_reply .Li struct sudo_conv_reply
for for
each message in the conversation. each message in the conversation.
The plugin is responsible for freeing the reply buffer filled in to the The plugin is responsible for freeing the reply buffer located in each
.Li struct sudo_conv_reply , .Li struct sudo_conv_reply ,
if any. if it is not
.Dv NULL .
.Dv SUDO_CONV_REPL_MAX
represents the maximum length of the reply buffer (not including
the trailing NUL character).
In practical terms, this is the longest password
.Nm sudo
will support.
It is also useful as a maximum value for the
.Fn memset_s
function when clearing passwords filled in by the conversation function.
.Pp .Pp
The The
.Fn printf Ns No -style .Fn printf Ns No -style

View File

@@ -384,6 +384,9 @@ size_t strlcpy(char *, const char *, size_t);
#ifndef HAVE_MEMRCHR #ifndef HAVE_MEMRCHR
void *memrchr(const void *, int, size_t); void *memrchr(const void *, int, size_t);
#endif #endif
#ifndef HAVE_MEMSET_S
errno_t memset_s(void *, rsize_t, int, rsize_t);
#endif
#ifndef HAVE_MKDTEMP #ifndef HAVE_MKDTEMP
char *mkdtemp(char *); char *mkdtemp(char *);
#endif #endif

View File

@@ -47,6 +47,17 @@ struct sudo_conv_message {
const char *msg; const char *msg;
}; };
/*
* Maximum length of a reply (not including the trailing NUL) when
* conversing with the user. In practical terms, this is the longest
* password sudo will support. This means that a buffer of size
* SUDO_CONV_REPL_MAX+1 is guaranteed to be able to hold any reply
* from the conversation function. It is also useful as a max value
* for memset_s() when clearing passwords returned by the conversation
* function.
*/
#define SUDO_CONV_REPL_MAX 255
struct sudo_conv_reply { struct sudo_conv_reply {
char *reply; char *reply;
}; };

View File

@@ -70,7 +70,7 @@ sub mkdep {
$makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo sssd.lo:; $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo sssd.lo:;
# XXX - fill in AUTH_OBJS from contents of the auth dir instead # XXX - fill in AUTH_OBJS from contents of the auth dir instead
$makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:;
$makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo getopt_long.lo glob.lo isblank.lo memrchr.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo utimes.lo globtest.o fnm_test.o:; $makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo getopt_long.lo glob.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo utimes.lo globtest.o fnm_test.o:;
# Parse OBJS lines # Parse OBJS lines
my %objs; my %objs;

View File

@@ -786,7 +786,7 @@ set_perms.lo: $(srcdir)/set_perms.c $(top_builddir)/config.h \
$(incdir)/sudo_debug.h $(incdir)/gettext.h $(incdir)/sudo_debug.h $(incdir)/gettext.h
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/set_perms.c $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/set_perms.c
sha2.lo: $(srcdir)/sha2.c $(top_builddir)/config.h \ sha2.lo: $(srcdir)/sha2.c $(top_builddir)/config.h \
$(top_srcdir)/compat/endian.h $(srcdir)/sha2.h $(top_srcdir)/compat/endian.h $(incdir)/missing.h $(srcdir)/sha2.h
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sha2.c $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sha2.c
sha2.o: sha2.lo sha2.o: sha2.lo
sia.lo: $(authdir)/sia.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ sia.lo: $(authdir)/sia.c $(top_builddir)/config.h $(srcdir)/sudoers.h \

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2005, 2007-2012 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1999-2005, 2007-2013 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -65,7 +65,7 @@ sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
efree(message); efree(message);
message = NULL; message = NULL;
result = authenticate(pw->pw_name, pass, &reenter, &message); result = authenticate(pw->pw_name, pass, &reenter, &message);
zero_bytes(pass, strlen(pass)); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
prompt = message; prompt = message;
} while (reenter); } while (reenter);

View File

@@ -156,7 +156,7 @@ bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
if (pass) { if (pass) {
authok = auth_userresponse(as, pass, 1); authok = auth_userresponse(as, pass, 1);
zero_bytes(pass, strlen(pass)); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
} }
/* restore old signal handler */ /* restore old signal handler */

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2005, 2008, 2010-2012 * Copyright (c) 1999-2005, 2008, 2010-2013
* Todd C. Miller <Todd.Miller@courtesan.com> * Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@@ -82,7 +82,7 @@ int
sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth) sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
{ {
char *pass; /* Password from the user */ char *pass; /* Password from the user */
char buf[SUDO_PASS_MAX + 12]; /* General prupose buffer */ char buf[SUDO_CONV_REPL_MAX + 12]; /* General prupose buffer */
char resp[128]; /* Response from the server */ char resp[128]; /* Response from the server */
int error; int error;
debug_decl(sudo_fwtk_verify, SUDO_DEBUG_AUTH) debug_decl(sudo_fwtk_verify, SUDO_DEBUG_AUTH)
@@ -139,8 +139,8 @@ restart:
warningx("%s", resp); warningx("%s", resp);
error = AUTH_FAILURE; error = AUTH_FAILURE;
done: done:
zero_bytes(pass, strlen(pass)); memset_s(pass, SUDO_PASS_MAX, 0, strlen(pass));
zero_bytes(buf, strlen(buf)); memset_s(buf, sizeof(buf), 0, sizeof(buf));
debug_return_int(error); debug_return_int(error);
} }

View File

@@ -312,7 +312,7 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
debug_return_int(PAM_SYSTEM_ERR); debug_return_int(PAM_SYSTEM_ERR);
zero_bytes(*response, num_msg * sizeof(struct pam_response)); memset(*response, 0, num_msg * sizeof(struct pam_response));
for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
type = SUDO_CONV_PROMPT_ECHO_OFF; type = SUDO_CONV_PROMPT_ECHO_OFF;
@@ -356,7 +356,7 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
#endif #endif
} }
pr->resp = estrdup(pass); pr->resp = estrdup(pass);
zero_bytes(pass, strlen(pass)); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
break; break;
case PAM_TEXT_INFO: case PAM_TEXT_INFO:
if (pm->msg) if (pm->msg)
@@ -380,12 +380,11 @@ done:
/* Zero and free allocated memory and return an error. */ /* Zero and free allocated memory and return an error. */
for (pr = *response, n = num_msg; n--; pr++) { for (pr = *response, n = num_msg; n--; pr++) {
if (pr->resp != NULL) { if (pr->resp != NULL) {
zero_bytes(pr->resp, strlen(pr->resp)); memset_s(pr->resp, SUDO_CONV_REPL_MAX, 0, strlen(pr->resp));
free(pr->resp); free(pr->resp);
pr->resp = NULL; pr->resp = NULL;
} }
} }
zero_bytes(*response, num_msg * sizeof(struct pam_response));
free(*response); free(*response);
*response = NULL; *response = NULL;
} }

View File

@@ -114,7 +114,7 @@ sudo_passwd_cleanup(pw, auth)
debug_decl(sudo_passwd_cleanup, SUDO_DEBUG_AUTH) debug_decl(sudo_passwd_cleanup, SUDO_DEBUG_AUTH)
if (pw_epasswd != NULL) { if (pw_epasswd != NULL) {
zero_bytes(pw_epasswd, strlen(pw_epasswd)); memset_s(pw_epasswd, SUDO_CONV_REPL_MAX, 0, strlen(pw_epasswd));
efree(pw_epasswd); efree(pw_epasswd);
} }
debug_return_int(AUTH_SUCCESS); debug_return_int(AUTH_SUCCESS);

View File

@@ -106,7 +106,7 @@ sudo_secureware_cleanup(pw, auth)
debug_decl(sudo_secureware_cleanup, SUDO_DEBUG_AUTH) debug_decl(sudo_secureware_cleanup, SUDO_DEBUG_AUTH)
if (pw_epasswd != NULL) { if (pw_epasswd != NULL) {
zero_bytes(pw_epasswd, strlen(pw_epasswd)); memset_s(pw_epasswd, SUDO_CONV_REPL_MAX, 0, strlen(pw_epasswd));
efree(pw_epasswd); efree(pw_epasswd);
} }
debug_return_int(AUTH_SUCCESS); debug_return_int(AUTH_SUCCESS);

View File

@@ -254,7 +254,7 @@ verify_user(struct passwd *pw, char *prompt, int validated)
goto done; goto done;
} }
if (!standalone) if (!standalone)
zero_bytes(p, strlen(p)); memset_s(p, SUDO_CONV_REPL_MAX, 0, strlen(p));
pass_warn(); pass_warn();
} }

View File

@@ -356,7 +356,7 @@ init_defaults(void)
list_op(NULL, 0, def, freeall); list_op(NULL, 0, def, freeall);
break; break;
} }
zero_bytes(&def->sd_un, sizeof(def->sd_un)); memset(&def->sd_un, 0, sizeof(def->sd_un));
} }
} }

View File

@@ -609,7 +609,7 @@ send_mail(const char *fmt, ...)
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
/* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
zero_bytes(&sa, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_INTERRUPT; sa.sa_flags = SA_INTERRUPT;
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;

View File

@@ -58,6 +58,7 @@
# include "compat/endian.h" # include "compat/endian.h"
#endif #endif
#include "missing.h"
#include "sha2.h" #include "sha2.h"
/* /*
@@ -117,8 +118,6 @@
#define g(i) T[(6-i)&7] #define g(i) T[(6-i)&7]
#define h(i) T[(7-i)&7] #define h(i) T[(7-i)&7]
extern void zero_bytes(volatile void *, size_t);
void void
SHA224Init(SHA2_CTX *ctx) SHA224Init(SHA2_CTX *ctx)
{ {
@@ -249,8 +248,8 @@ SHA256Transform(uint32_t state[8], const uint8_t data[SHA256_BLOCK_LENGTH])
state[6] += g(0); state[6] += g(0);
state[7] += h(0); state[7] += h(0);
/* Cleanup */ /* Cleanup */
zero_bytes(T, sizeof(T)); memset_s(T, sizeof(T), 0, sizeof(T));
zero_bytes(W, sizeof(W)); memset_s(W, sizeof(W), 0, sizeof(W));
} }
#undef S0 #undef S0
@@ -466,8 +465,8 @@ SHA512Transform(uint64_t state[8], const uint8_t data[SHA512_BLOCK_LENGTH])
state[6] += g(0); state[6] += g(0);
state[7] += h(0); state[7] += h(0);
/* Cleanup. */ /* Cleanup. */
zero_bytes(T, sizeof(T)); memset_s(T, sizeof(T), 0, sizeof(T));
zero_bytes(W, sizeof(W)); memset_s(W, sizeof(W), 0, sizeof(W));
} }
void void

View File

@@ -807,7 +807,7 @@ set_fqdn(void)
char *p; char *p;
debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN) debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN)
zero_bytes(&hint, sizeof(hint)); memset(&hint, 0, sizeof(hint));
hint.ai_family = PF_UNSPEC; hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_FQDN; hint.ai_flags = AI_FQDN;
if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {

View File

@@ -210,14 +210,6 @@ struct sudo_user {
#endif #endif
#define ROOT_GID 0 #define ROOT_GID 0
/*
* We used to use the system definition of PASS_MAX or _PASSWD_LEN,
* but that caused problems with various alternate authentication
* methods. So, we just define our own and assume that it is >= the
* system max.
*/
#define SUDO_PASS_MAX 256
struct lbuf; struct lbuf;
struct passwd; struct passwd;
struct stat; struct stat;
@@ -287,9 +279,6 @@ void dump_auth_methods(void);
/* getspwuid.c */ /* getspwuid.c */
char *sudo_getepw(const struct passwd *); char *sudo_getepw(const struct passwd *);
/* zero_bytes.c */
void zero_bytes(volatile void *, size_t);
/* sudo_nss.c */ /* sudo_nss.c */
void display_privs(struct sudo_nss_list *, struct passwd *); void display_privs(struct sudo_nss_list *, struct passwd *);
bool display_cmnd(struct sudo_nss_list *, struct passwd *); bool display_cmnd(struct sudo_nss_list *, struct passwd *);

View File

@@ -130,7 +130,7 @@ next_entry:
if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL) if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL)
return NULL; return NULL;
zero_bytes(&pw, sizeof(pw)); memset(&pw, 0, sizeof(pw));
if ((colon = strchr(cp = colon, ':')) == NULL) if ((colon = strchr(cp = colon, ':')) == NULL)
goto next_entry; goto next_entry;
*colon++ = '\0'; *colon++ = '\0';
@@ -263,7 +263,7 @@ next_entry:
if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL) if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
return NULL; return NULL;
zero_bytes(&gr, sizeof(gr)); memset(&gr, 0, sizeof(gr));
if ((colon = strchr(cp = colon, ':')) == NULL) if ((colon = strchr(cp = colon, ':')) == NULL)
goto next_entry; goto next_entry;
*colon++ = '\0'; *colon++ = '\0';

View File

@@ -741,7 +741,7 @@ setup_signals(void)
/* /*
* Setup signal handlers to cleanup nicely. * Setup signal handlers to cleanup nicely.
*/ */
zero_bytes(&sa, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_handler = quit; sa.sa_handler = quit;

View File

@@ -311,7 +311,8 @@ tgetpass.o: $(srcdir)/tgetpass.c $(top_builddir)/config.h $(srcdir)/sudo.h \
$(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \
$(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \
$(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \
$(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \
$(incdir)/sudo_plugin.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/tgetpass.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/tgetpass.c
ttyname.o: $(srcdir)/ttyname.c $(top_builddir)/config.h $(srcdir)/sudo.h \ ttyname.o: $(srcdir)/ttyname.c $(top_builddir)/config.h $(srcdir)/sudo.h \
$(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \

View File

@@ -81,7 +81,7 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
if (pass == NULL) if (pass == NULL)
goto err; goto err;
repl->reply = estrdup(pass); repl->reply = estrdup(pass);
zero_bytes(pass, strlen(pass)); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
break; break;
case SUDO_CONV_INFO_MSG: case SUDO_CONV_INFO_MSG:
if (msg->msg) if (msg->msg)
@@ -107,7 +107,7 @@ err:
do { do {
repl = &replies[n]; repl = &replies[n];
if (repl->reply != NULL) { if (repl->reply != NULL) {
zero_bytes(repl->reply, strlen(repl->reply)); memset_s(repl->reply, SUDO_CONV_REPL_MAX, 0, strlen(repl->reply));
free(repl->reply); free(repl->reply);
repl->reply = NULL; repl->reply = NULL;
} }

View File

@@ -75,14 +75,6 @@
#define MODE_NONINTERACTIVE 0x00800000 #define MODE_NONINTERACTIVE 0x00800000
#define MODE_LONG_LIST 0x01000000 #define MODE_LONG_LIST 0x01000000
/*
* We used to use the system definition of PASS_MAX or _PASSWD_LEN,
* but that caused problems with various alternate authentication
* methods. So, we just define our own and assume that it is >= the
* system max.
*/
#define SUDO_PASS_MAX 256
/* /*
* Flags for tgetpass() * Flags for tgetpass()
*/ */
@@ -178,9 +170,6 @@ void cleanup(int);
char *tgetpass(const char *, int, int); char *tgetpass(const char *, int, int);
int tty_present(void); int tty_present(void);
/* zero_bytes.c */
void zero_bytes(volatile void *, size_t);
/* exec.c */ /* exec.c */
int pipe_nonblock(int fds[2]); int pipe_nonblock(int fds[2]);
int sudo_execute(struct command_details *details, struct command_status *cstat); int sudo_execute(struct command_details *details, struct command_status *cstat);

View File

@@ -148,14 +148,14 @@ sudo_edit(struct command_details *command_details)
* and copy the contents of the original to it. * and copy the contents of the original to it.
*/ */
tf = emalloc2(nfiles, sizeof(*tf)); tf = emalloc2(nfiles, sizeof(*tf));
zero_bytes(tf, nfiles * sizeof(*tf)); memset(tf, 0, nfiles * sizeof(*tf));
for (i = 0, j = 0; i < nfiles; i++) { for (i = 0, j = 0; i < nfiles; i++) {
rc = -1; rc = -1;
switch_user(command_details->euid, command_details->egid, switch_user(command_details->euid, command_details->egid,
command_details->ngroups, command_details->groups); command_details->ngroups, command_details->groups);
if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) { if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) {
if (ofd == -1) { if (ofd == -1) {
zero_bytes(&sb, sizeof(sb)); /* new file */ memset(&sb, 0, sizeof(sb)); /* new file */
rc = 0; rc = 0;
} else { } else {
rc = fstat(ofd, &sb); rc = fstat(ofd, &sb);

View File

@@ -53,6 +53,7 @@
#include <fcntl.h> #include <fcntl.h>
#include "sudo.h" #include "sudo.h"
#include "sudo_plugin.h"
static volatile sig_atomic_t signo[NSIG]; static volatile sig_atomic_t signo[NSIG];
@@ -70,7 +71,7 @@ tgetpass(const char *prompt, int timeout, int flags)
sigaction_t savetstp, savettin, savettou, savepipe; sigaction_t savetstp, savettin, savettou, savepipe;
char *pass; char *pass;
static const char *askpass; static const char *askpass;
static char buf[SUDO_PASS_MAX + 1]; static char buf[SUDO_CONV_REPL_MAX + 1];
int i, input, output, save_errno, neednl = 0, need_restart; int i, input, output, save_errno, neednl = 0, need_restart;
debug_decl(tgetpass, SUDO_DEBUG_CONV) debug_decl(tgetpass, SUDO_DEBUG_CONV)
@@ -127,7 +128,7 @@ restart:
* Catch signals that would otherwise cause the user to end * Catch signals that would otherwise cause the user to end
* up with echo turned off in the shell. * up with echo turned off in the shell.
*/ */
zero_bytes(&sa, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */ sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
sa.sa_handler = tgetpass_handler; sa.sa_handler = tgetpass_handler;
@@ -207,7 +208,7 @@ restore:
static char * static char *
sudo_askpass(const char *askpass, const char *prompt) sudo_askpass(const char *askpass, const char *prompt)
{ {
static char buf[SUDO_PASS_MAX + 1], *pass; static char buf[SUDO_CONV_REPL_MAX + 1], *pass;
sigaction_t sa, saved_sa_pipe; sigaction_t sa, saved_sa_pipe;
int pfd[2]; int pfd[2];
pid_t pid; pid_t pid;
@@ -242,7 +243,7 @@ sudo_askpass(const char *askpass, const char *prompt)
} }
/* Ignore SIGPIPE in case child exits prematurely */ /* Ignore SIGPIPE in case child exits prematurely */
zero_bytes(&sa, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_INTERRUPT; sa.sa_flags = SA_INTERRUPT;
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;