Add support for preventing fds from getting clobbered by closefrom().

This commit is contained in:
Todd C. Miller
2013-12-20 11:14:32 -07:00
parent 388ad69f09
commit 1adeda54ef
14 changed files with 218 additions and 35 deletions

View File

@@ -407,6 +407,7 @@ src/locale_stub.c
src/net_ifs.c src/net_ifs.c
src/openbsd.c src/openbsd.c
src/parse_args.c src/parse_args.c
src/preserve_fds.c
src/po/README src/po/README
src/po/cs.mo src/po/cs.mo
src/po/cs.po src/po/cs.po

View File

@@ -563,18 +563,10 @@ sudo_debug_execve2(int level, const char *path, char *const argv[], char *const
} }
/* /*
* Dup sudo_debug_fd to the specified value so we don't * Getter for the debug descriptor.
* close it when calling closefrom().
*/ */
int int
sudo_debug_fd_set(int fd) sudo_debug_fd_get(void)
{ {
if (sudo_debug_fd != -1 && fd != sudo_debug_fd) {
if (dup2(sudo_debug_fd, fd) == -1)
return -1;
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
close(sudo_debug_fd);
sudo_debug_fd = fd;
}
return sudo_debug_fd; return sudo_debug_fd;
} }

View File

@@ -548,6 +548,11 @@ DDEESSCCRRIIPPTTIIOONN
If set, prevent the command from executing other If set, prevent the command from executing other
programs. programs.
preserve_fds=list
A comma-separated list of file descriptors that should
be preserved, regardless of the value of the _c_l_o_s_e_f_r_o_m
setting. Only available starting with API version 1.5.
preserve_groups=bool preserve_groups=bool
If set, ssuuddoo will preserve the user's group vector If set, ssuuddoo will preserve the user's group vector
instead of initializing the group vector based on instead of initializing the group vector based on
@@ -1437,6 +1442,9 @@ PPLLUUGGIINN AAPPII CCHHAANNGGEELLOOGG
Version 1.4 (sudo 1.8.8) Version 1.4 (sudo 1.8.8)
The _r_e_m_o_t_e___h_o_s_t entry was added to the settings list. The _r_e_m_o_t_e___h_o_s_t entry was added to the settings list.
Version 1.5 (sudo 1.8.9)
The entry was added to the command_info list.
SSEEEE AALLSSOO SSEEEE AALLSSOO
sudo.conf(4), sudoers(4), sudo(1m) sudo.conf(4), sudoers(4), sudo(1m)
@@ -1456,4 +1464,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or http://www.sudo.ws/sudo/license.html for file distributed with ssuuddoo or http://www.sudo.ws/sudo/license.html for
complete details. complete details.
Sudo 1.8.9 December 4, 2013 Sudo 1.8.9 Sudo 1.8.9 December 20, 2013 Sudo 1.8.9

View File

@@ -16,7 +16,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.TH "SUDO_PLUGIN" "5" "December 4, 2013" "Sudo @PACKAGE_VERSION@" "OpenBSD Programmer's Manual" .TH "SUDO_PLUGIN" "5" "December 20, 2013" "Sudo @PACKAGE_VERSION@" "OpenBSD Programmer's Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -914,6 +914,13 @@ on BSD systems.
noexec=bool noexec=bool
If set, prevent the command from executing other programs. If set, prevent the command from executing other programs.
.TP 6n .TP 6n
preserve_fds=list
A comma-separated list of file descriptors that should be
preserved, regardless of the value of the
\fIclosefrom\fR
setting.
Only available starting with API version 1.5.
.TP 6n
preserve_groups=bool preserve_groups=bool
If set, If set,
\fBsudo\fR \fBsudo\fR
@@ -2599,6 +2606,12 @@ The
entry was added to the entry was added to the
\fRsettings\fR \fRsettings\fR
list. list.
.TP 6n
Version 1.5 (sudo 1.8.9)
The
entry was added to the
\fRcommand_info\fR
list.
.SH "SEE ALSO" .SH "SEE ALSO"
sudo.conf(@mansectform@), sudo.conf(@mansectform@),
sudoers(@mansectform@), sudoers(@mansectform@),

View File

@@ -14,7 +14,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd December 4, 2013 .Dd December 20, 2013
.Dt SUDO_PLUGIN @mansectform@ .Dt SUDO_PLUGIN @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -808,6 +808,12 @@ The nice value, if specified, overrides the priority associated with the
on BSD systems. on BSD systems.
.It noexec=bool .It noexec=bool
If set, prevent the command from executing other programs. If set, prevent the command from executing other programs.
.It preserve_fds=list
A comma-separated list of file descriptors that should be
preserved, regardless of the value of the
.Em closefrom
setting.
Only available starting with API version 1.5.
.It preserve_groups=bool .It preserve_groups=bool
If set, If set,
.Nm sudo .Nm sudo
@@ -2253,6 +2259,12 @@ The
entry was added to the entry was added to the
.Li settings .Li settings
list. list.
.It Version 1.5 (sudo 1.8.9)
The
.em preserve_fds
entry was added to the
.Li command_info
list.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sudo.conf @mansectform@ , .Xr sudo.conf @mansectform@ ,

View File

@@ -218,7 +218,7 @@ void sudo_debug_exit_bool(const char *func, const char *file, int line, int subs
void sudo_debug_exit_str(const char *func, const char *file, int line, int subsys, const char *rval); void sudo_debug_exit_str(const char *func, const char *file, int line, int subsys, const char *rval);
void sudo_debug_exit_str_masked(const char *func, const char *file, int line, int subsys, const char *rval); void sudo_debug_exit_str_masked(const char *func, const char *file, int line, int subsys, const char *rval);
void sudo_debug_exit_ptr(const char *func, const char *file, int line, int subsys, const void *rval); void sudo_debug_exit_ptr(const char *func, const char *file, int line, int subsys, const void *rval);
int sudo_debug_fd_set(int fd); int sudo_debug_fd_get(void);
int sudo_debug_init(const char *debugfile, const char *settings); int sudo_debug_init(const char *debugfile, const char *settings);
void sudo_debug_printf_nvm(int pri, const char *fmt, ...) __printf0like(2, 3); void sudo_debug_printf_nvm(int pri, const char *fmt, ...) __printf0like(2, 3);
void sudo_debug_printf2(const char *func, const char *file, int line, int level, const char *fmt, ...) __printf0like(5, 6); void sudo_debug_printf2(const char *func, const char *file, int line, int level, const char *fmt, ...) __printf0like(5, 6);

View File

@@ -19,7 +19,7 @@
/* API version major/minor */ /* API version major/minor */
#define SUDO_API_VERSION_MAJOR 1 #define SUDO_API_VERSION_MAJOR 1
#define SUDO_API_VERSION_MINOR 4 #define SUDO_API_VERSION_MINOR 5
#define SUDO_API_MKVERSION(x, y) ((x << 16) | y) #define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR) #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)

View File

@@ -90,8 +90,9 @@ SHELL = @SHELL@
PROGS = @PROGS@ PROGS = @PROGS@
OBJS = conversation.o env_hooks.o exec.o exec_common.o exec_pty.o \ OBJS = conversation.o env_hooks.o exec.o exec_common.o exec_pty.o \
get_pty.o hooks.o net_ifs.o load_plugins.o parse_args.o signal.o \ get_pty.o hooks.o net_ifs.o load_plugins.o parse_args.o \
sudo.o sudo_edit.o tgetpass.o ttyname.o utmp.o @SUDO_OBJS@ preserve_fds.o signal.o sudo.o sudo_edit.o tgetpass.o ttyname.o \
utmp.o @SUDO_OBJS@
SESH_OBJS = sesh.o locale_stub.o exec_common.o SESH_OBJS = sesh.o locale_stub.o exec_common.o
@@ -179,7 +180,8 @@ cleandir: realclean
# Autogenerated dependencies, do not modify # Autogenerated dependencies, do not modify
check_ttyname.o: $(srcdir)/regress/ttyname/check_ttyname.c $(incdir)/alloc.h \ check_ttyname.o: $(srcdir)/regress/ttyname/check_ttyname.c $(incdir)/alloc.h \
$(incdir)/fatal.h $(incdir)/missing.h $(top_builddir)/config.h $(incdir)/fatal.h $(incdir)/missing.h $(incdir)/sudo_util.h \
$(top_builddir)/config.h $(top_srcdir)/compat/stdbool.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/ttyname/check_ttyname.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/ttyname/check_ttyname.c
conversation.o: $(srcdir)/conversation.c $(incdir)/alloc.h $(incdir)/fatal.h \ conversation.o: $(srcdir)/conversation.c $(incdir)/alloc.h $(incdir)/fatal.h \
$(incdir)/fileops.h $(incdir)/gettext.h $(incdir)/missing.h \ $(incdir)/fileops.h $(incdir)/gettext.h $(incdir)/missing.h \
@@ -263,6 +265,13 @@ parse_args.o: $(srcdir)/parse_args.c $(incdir)/alloc.h $(incdir)/fatal.h \
preload.o: $(srcdir)/preload.c $(incdir)/sudo_dso.h $(incdir)/sudo_plugin.h \ preload.o: $(srcdir)/preload.c $(incdir)/sudo_dso.h $(incdir)/sudo_plugin.h \
$(top_builddir)/config.h $(top_builddir)/config.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/preload.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/preload.c
preserve_fds.o: $(srcdir)/preserve_fds.c $(incdir)/alloc.h $(incdir)/fatal.h \
$(incdir)/fileops.h $(incdir)/gettext.h $(incdir)/missing.h \
$(incdir)/queue.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_util.h $(srcdir)/sudo.h \
$(top_builddir)/config.h $(top_builddir)/pathnames.h \
$(top_srcdir)/compat/stdbool.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/preserve_fds.c
selinux.o: $(srcdir)/selinux.c $(incdir)/alloc.h $(incdir)/fatal.h \ selinux.o: $(srcdir)/selinux.c $(incdir)/alloc.h $(incdir)/fatal.h \
$(incdir)/fileops.h $(incdir)/gettext.h $(incdir)/missing.h \ $(incdir)/fileops.h $(incdir)/gettext.h $(incdir)/missing.h \
$(incdir)/queue.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ $(incdir)/queue.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \

View File

@@ -143,7 +143,7 @@ static int fork_cmnd(struct command_details *details, int sv[2])
close(signal_pipe[0]); close(signal_pipe[0]);
close(signal_pipe[1]); close(signal_pipe[1]);
fcntl(sv[1], F_SETFD, FD_CLOEXEC); fcntl(sv[1], F_SETFD, FD_CLOEXEC);
exec_cmnd(details, &cstat, &sv[1]); exec_cmnd(details, &cstat, sv[1]);
send(sv[1], &cstat, sizeof(cstat), 0); send(sv[1], &cstat, sizeof(cstat), 0);
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1); sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1);
_exit(1); _exit(1);
@@ -161,7 +161,7 @@ static int fork_cmnd(struct command_details *details, int sv[2])
*/ */
void void
exec_cmnd(struct command_details *details, struct command_status *cstat, exec_cmnd(struct command_details *details, struct command_status *cstat,
int *errfd) int errfd)
{ {
debug_decl(exec_cmnd, SUDO_DEBUG_EXEC) debug_decl(exec_cmnd, SUDO_DEBUG_EXEC)
@@ -171,16 +171,15 @@ exec_cmnd(struct command_details *details, struct command_status *cstat,
sudo_debug_execve(SUDO_DEBUG_INFO, details->command, sudo_debug_execve(SUDO_DEBUG_INFO, details->command,
details->argv, details->envp); details->argv, details->envp);
if (details->closefrom >= 0) { if (details->closefrom >= 0) {
int maxfd = details->closefrom; /* Preserve debug fd and error pipe as needed. */
/* Preserve back channel if present. */ int debug_fd = sudo_debug_fd_get();
if (errfd != NULL) { if (debug_fd != -1)
dup2(*errfd, maxfd); add_preserved_fd(&details->preserved_fds, debug_fd);
(void)fcntl(maxfd, F_SETFD, FD_CLOEXEC); if (errfd != -1)
*errfd = maxfd++; add_preserved_fd(&details->preserved_fds, errfd);
}
if (sudo_debug_fd_set(maxfd) != -1) /* Close all fds except those explicitly preserved. */
maxfd++; closefrom_except(details->closefrom, &details->preserved_fds);
closefrom(maxfd);
} }
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
if (ISSET(details->flags, CD_RBAC_ENABLED)) { if (ISSET(details->flags, CD_RBAC_ENABLED)) {
@@ -382,7 +381,7 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
} else if (!ISSET(details->flags, CD_SET_TIMEOUT) && } else if (!ISSET(details->flags, CD_SET_TIMEOUT) &&
policy_plugin.u.policy->close == NULL) { policy_plugin.u.policy->close == NULL) {
/* If no I/O logging, timeout or policy close we can exec directly. */ /* If no I/O logging, timeout or policy close we can exec directly. */
exec_cmnd(details, cstat, NULL); exec_cmnd(details, cstat, -1);
goto done; goto done;
} }

View File

@@ -99,7 +99,7 @@ static struct io_buffer_list iobufs;
static void del_io_events(void); static void del_io_events(void);
static int exec_monitor(struct command_details *details, int backchannel); static int exec_monitor(struct command_details *details, int backchannel);
static void exec_pty(struct command_details *details, static void exec_pty(struct command_details *details,
struct command_status *cstat, int *errfd); struct command_status *cstat, int errfd);
static void sigwinch(int s); static void sigwinch(int s);
static void sync_ttysize(int src, int dst); static void sync_ttysize(int src, int dst);
static void deliver_signal(pid_t pid, int signo, bool from_parent); static void deliver_signal(pid_t pid, int signo, bool from_parent);
@@ -1282,7 +1282,7 @@ exec_monitor(struct command_details *details, int backchannel)
restore_signals(); restore_signals();
/* setup tty and exec command */ /* setup tty and exec command */
exec_pty(details, &cstat, &errpipe[1]); exec_pty(details, &cstat, errpipe[1]);
ignore_result(write(errpipe[1], &cstat, sizeof(cstat))); ignore_result(write(errpipe[1], &cstat, sizeof(cstat)));
_exit(1); _exit(1);
} }
@@ -1375,7 +1375,7 @@ bad:
*/ */
static void static void
exec_pty(struct command_details *details, exec_pty(struct command_details *details,
struct command_status *cstat, int *errfd) struct command_status *cstat, int errfd)
{ {
pid_t self = getpid(); pid_t self = getpid();
debug_decl(exec_pty, SUDO_DEBUG_EXEC); debug_decl(exec_pty, SUDO_DEBUG_EXEC);

132
src/preserve_fds.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* 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/param.h> /* for howmany() on Linux */
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* for howmany() on Solaris */
#endif
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h> /* for FD_* macros */
#endif /* HAVE_SYS_SELECT_H */
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
# include <memory.h>
# endif
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include "sudo.h"
/*
* Add an fd to preserve.
*/
void
add_preserved_fd(struct preserved_fds *pfds, int fd)
{
debug_decl(add_preserved_fd, SUDO_DEBUG_UTIL)
/* Reallocate as needed before adding. */
if (fd > pfds->maxfd) {
int osize = howmany(pfds->maxfd + 1, NFDBITS);
int nsize = howmany(fd + 1, NFDBITS);
if (nsize > osize)
pfds->fds = erecalloc(pfds->fds, osize, nsize, sizeof(fd_mask));
pfds->maxfd = fd;
}
FD_SET(fd, pfds->fds);
debug_return;
}
/*
* Close all descriptors, startfd and higher except those listed
* in pfds.
*/
void
closefrom_except(int startfd, struct preserved_fds *pfds)
{
int fd;
debug_decl(closefrom_except, SUDO_DEBUG_UTIL)
/* First handle the preserved fds. */
if (startfd <= pfds->maxfd) {
for (fd = startfd; fd <= pfds->maxfd; fd++) {
if (!FD_ISSET(fd, pfds->fds)) {
#ifdef __APPLE__
/* Avoid potential libdispatch crash when we close its fds. */
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
#else
(void) close(fd);
#endif
}
}
startfd = pfds->maxfd + 1;
}
closefrom(startfd);
debug_return;
}
/*
* Parse a comma-separated list of fds and add them to preserved_fds.
*/
void
parse_preserved_fds(struct preserved_fds *pfds, const char *fdstr)
{
const char *cp = fdstr;
long lval;
char *ep;
debug_decl(parse_preserved_fds, SUDO_DEBUG_UTIL)
do {
errno = 0;
lval = strtol(cp, &ep, 10);
if (ep == cp || (*ep != ',' && *ep != '\0')) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to parse fd string %s", cp);
break;
}
if ((errno == ERANGE && lval == LONG_MAX) || lval < 0 || lval > INT_MAX) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"range error parsing fd string %s", cp);
} else {
add_preserved_fd(pfds, (int)lval);
}
cp = ep + 1;
} while (*ep != '\0');
debug_return;
}

View File

@@ -536,6 +536,7 @@ command_info_to_details(char * const info[], struct command_details *details)
memset(details, 0, sizeof(*details)); memset(details, 0, sizeof(*details));
details->closefrom = -1; details->closefrom = -1;
details->preserved_fds.maxfd = -1;
#define SET_STRING(s, n) \ #define SET_STRING(s, n) \
if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \ if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
@@ -590,6 +591,11 @@ command_info_to_details(char * const info[], struct command_details *details)
SET(details->flags, CD_PRESERVE_GROUPS); SET(details->flags, CD_PRESERVE_GROUPS);
break; break;
} }
if (strncmp("preserve_fds=", info[i], sizeof("preserve_fds=") - 1) == 0) {
parse_preserved_fds(&details->preserved_fds,
info[i] + sizeof("preserve_fds=") - 1);
break;
}
break; break;
case 'r': case 'r':
if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) { if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {

View File

@@ -122,6 +122,11 @@ struct user_details {
#define CD_SET_UTMP 0x2000 #define CD_SET_UTMP 0x2000
#define CD_EXEC_BG 0x4000 #define CD_EXEC_BG 0x4000
struct preserved_fds {
int maxfd;
fd_set *fds;
};
struct command_details { struct command_details {
uid_t uid; uid_t uid;
uid_t euid; uid_t euid;
@@ -133,6 +138,7 @@ struct command_details {
int ngroups; int ngroups;
int closefrom; int closefrom;
int flags; int flags;
struct preserved_fds preserved_fds;
struct passwd *pw; struct passwd *pw;
GETGROUPS_T *groups; GETGROUPS_T *groups;
const char *command; const char *command;
@@ -240,4 +246,9 @@ void save_signals(void);
/* preload.c */ /* preload.c */
void preload_static_symbols(void); void preload_static_symbols(void);
/* preserve_fds.c */
void add_preserved_fd(struct preserved_fds *pfds, int fd);
void closefrom_except(int startfd, struct preserved_fds *pfds);
void parse_preserved_fds(struct preserved_fds *pfds, const char *fdstr);
#endif /* _SUDO_SUDO_H */ #endif /* _SUDO_SUDO_H */

View File

@@ -62,7 +62,7 @@ struct command_status;
int fork_pty(struct command_details *details, int sv[], sigset_t *omask); int fork_pty(struct command_details *details, int sv[], sigset_t *omask);
int suspend_parent(int signo); int suspend_parent(int signo);
void exec_cmnd(struct command_details *details, struct command_status *cstat, void exec_cmnd(struct command_details *details, struct command_status *cstat,
int *errfd); int errfd);
void add_io_events(struct sudo_event_base *evbase); void add_io_events(struct sudo_event_base *evbase);
#ifdef SA_SIGINFO #ifdef SA_SIGINFO
void handler(int s, siginfo_t *info, void *context); void handler(int s, siginfo_t *info, void *context);