2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-09-04 16:25:25 +00:00

Add a new sudoers settings log_passwords and passprompt_regex.

When logging terminal input, if log_passwords is disabled and any
of the regular expressions in the passprompt_regex list are found
in the terminal output, terminal input will be replaced with '*'
characters until a newline or carriage return is found in the input
or an output character is received.
This commit is contained in:
Todd C. Miller
2022-01-28 08:52:41 -07:00
parent 946404434e
commit 0efe280037
11 changed files with 255 additions and 16 deletions

View File

@@ -25,7 +25,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.TH "SUDOERS" "@mansectform@" "January 20, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDOERS" "@mansectform@" "January 27, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -2660,6 +2660,43 @@ This flag is
\fIoff\fR \fIoff\fR
by default. by default.
.TP 18n .TP 18n
log_passwords
Most programs that require a user's password will disable echo before
reading the password to avoid displaying the plaintext password on
the screen.
However, if terminal input is being logged (see
\fIlog_input\fR),
the password will still be present in the I/O log.
If the
\fIlog_passwords\fR
option is disabled,
\fBsudoers\fR
will attempt to prevent passwords from being logged.
It does this by using the regular expressions in
\fIpassprompt_regex\fR
to match a password prompt in the terminal output buffer.
When a match is found, input characters in the I/O log will be replaced with
\(oq*\(cq
until either a line feed or carriage return is found in the terminal input
or a new terminal output buffer is received.
If, however, a program displays characters as the user types
(such as
\fBsudo\fR
when
\fIpwfeedback\fR
is set), only the
first character of the password will be replaced in the I/O log.
This option has no effect unless
\fIlog_input\fR
and
\fIlog_input\fR
are also set.
This flag is
\fIon\fR
by default.
.sp
This setting is only supported by version 1.9.10 or higher.
.TP 18n
fqdn fqdn
Set this flag if you want to put fully qualified host names in the Set this flag if you want to put fully qualified host names in the
\fIsudoers\fR \fIsudoers\fR
@@ -5261,6 +5298,17 @@ flag (I/O logging enabled) or the
flag (I/O logging disabled) is set. flag (I/O logging disabled) is set.
.sp .sp
This setting is only supported by version 1.9.0 or higher. This setting is only supported by version 1.9.0 or higher.
.TP 18n
passprompt_regex
A list of POSIX extended regular expressions used to
match password prompts in the terminal output.
This option is only used when
\fIlog_passwords\fR
has been disabled.
The default value is
\(lq[Pp]assword[: ]*\(rq
.sp
This setting is only supported by version 1.9.10 or higher.
.SH "GROUP PROVIDER PLUGINS" .SH "GROUP PROVIDER PLUGINS"
The The
\fBsudoers\fR \fBsudoers\fR

View File

@@ -24,7 +24,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.Dd January 20, 2022 .Dd January 27, 2022
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -2507,6 +2507,42 @@ characters.
This flag is This flag is
.Em off .Em off
by default. by default.
.It log_passwords
Most programs that require a user's password will disable echo before
reading the password to avoid displaying the plaintext password on
the screen.
However, if terminal input is being logged (see
.Em log_input ) ,
the password will still be present in the I/O log.
If the
.Em log_passwords
option is disabled,
.Nm
will attempt to prevent passwords from being logged.
It does this by using the regular expressions in
.Em passprompt_regex
to match a password prompt in the terminal output buffer.
When a match is found, input characters in the I/O log will be replaced with
.Ql *
until either a line feed or carriage return is found in the terminal input
or a new terminal output buffer is received.
If, however, a program displays characters as the user types
(such as
.Nm sudo
when
.Em pwfeedback
is set), only the
first character of the password will be replaced in the I/O log.
This option has no effect unless
.Em log_input
and
.Em log_input
are also set.
This flag is
.Em on
by default.
.Pp
This setting is only supported by version 1.9.10 or higher.
.It fqdn .It fqdn
Set this flag if you want to put fully qualified host names in the Set this flag if you want to put fully qualified host names in the
.Em sudoers .Em sudoers
@@ -4908,6 +4944,16 @@ flag (I/O logging enabled) or the
flag (I/O logging disabled) is set. flag (I/O logging disabled) is set.
.Pp .Pp
This setting is only supported by version 1.9.0 or higher. This setting is only supported by version 1.9.0 or higher.
.It passprompt_regex
A list of POSIX extended regular expressions used to
match password prompts in the terminal output.
This option is only used when
.Em log_passwords
has been disabled.
The default value is
.Dq [Pp]assword[: ]*
.Pp
This setting is only supported by version 1.9.10 or higher.
.El .El
.Sh GROUP PROVIDER PLUGINS .Sh GROUP PROVIDER PLUGINS
The The

View File

@@ -1,7 +1,7 @@
# #
# SPDX-License-Identifier: ISC # SPDX-License-Identifier: ISC
# #
# Copyright (c) 1996, 1998-2005, 2007-2021 # Copyright (c) 1996, 1998-2005, 2007-2022
# Todd C. Miller <Todd.Miller@sudo.ws> # Todd C. Miller <Todd.Miller@sudo.ws>
# #
# Permission to use, copy, modify, and distribute this software for any # Permission to use, copy, modify, and distribute this software for any
@@ -1504,22 +1504,22 @@ defaults.lo: $(srcdir)/defaults.c $(devdir)/def_data.c $(devdir)/def_data.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_eventlog.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_eventlog.h \
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \
$(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ $(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/pathnames.h $(top_builddir)/config.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/defaults.c $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/defaults.c
defaults.i: $(srcdir)/defaults.c $(devdir)/def_data.c $(devdir)/def_data.h \ defaults.i: $(srcdir)/defaults.c $(devdir)/def_data.c $(devdir)/def_data.h \
$(devdir)/gram.h $(incdir)/compat/stdbool.h \ $(devdir)/gram.h $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_eventlog.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_eventlog.h \
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \
$(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ $(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/pathnames.h $(top_builddir)/config.h $(top_builddir)/pathnames.h
$(CC) -E -o $@ $(CPPFLAGS) $< $(CC) -E -o $@ $(CPPFLAGS) $<
defaults.plog: defaults.i defaults.plog: defaults.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/defaults.c --i-file $< --output-file $@ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/defaults.c --i-file $< --output-file $@

View File

@@ -645,6 +645,14 @@ struct sudo_defs_types sudo_defs_table[] = {
"rlimit_stack", T_RLIMIT|T_BOOL, "rlimit_stack", T_RLIMIT|T_BOOL,
N_("The maximum size to which the process's stack may grow (in bytes): %s"), N_("The maximum size to which the process's stack may grow (in bytes): %s"),
NULL, NULL,
}, {
"log_passwords", T_FLAG,
N_("Store plaintext passwords in I/O log input"),
NULL,
}, {
"passprompt_regex", T_LIST|T_BOOL,
N_("List of regular expressions to use when matching a password prompt"),
NULL,
}, { }, {
NULL, 0, NULL NULL, 0, NULL
} }

View File

@@ -300,6 +300,10 @@
#define def_rlimit_rss (sudo_defs_table[I_RLIMIT_RSS].sd_un.str) #define def_rlimit_rss (sudo_defs_table[I_RLIMIT_RSS].sd_un.str)
#define I_RLIMIT_STACK 149 #define I_RLIMIT_STACK 149
#define def_rlimit_stack (sudo_defs_table[I_RLIMIT_STACK].sd_un.str) #define def_rlimit_stack (sudo_defs_table[I_RLIMIT_STACK].sd_un.str)
#define I_LOG_PASSWORDS 150
#define def_log_passwords (sudo_defs_table[I_LOG_PASSWORDS].sd_un.flag)
#define I_PASSPROMPT_REGEX 151
#define def_passprompt_regex (sudo_defs_table[I_PASSPROMPT_REGEX].sd_un.list)
enum def_tuple { enum def_tuple {
never, never,

View File

@@ -466,3 +466,9 @@ rlimit_rss
rlimit_stack rlimit_stack
T_RLIMIT|T_BOOL T_RLIMIT|T_BOOL
"The maximum size to which the process's stack may grow (in bytes): %s" "The maximum size to which the process's stack may grow (in bytes): %s"
log_passwords
T_FLAG
"Store plaintext passwords in I/O log input"
passprompt_regex
T_LIST|T_BOOL
"List of regular expressions to use when matching a password prompt"

View File

@@ -36,10 +36,12 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <regex.h>
#include <syslog.h> #include <syslog.h>
#include "sudoers.h" #include "sudoers.h"
#include "sudo_eventlog.h" #include "sudo_eventlog.h"
#include "sudo_iolog.h"
#include <gram.h> #include <gram.h>
static struct early_default early_defaults[] = { static struct early_default early_defaults[] = {
@@ -454,6 +456,24 @@ free_defs_val(int type, union sudo_defs_val *sd_un)
memset(sd_un, 0, sizeof(*sd_un)); memset(sd_un, 0, sizeof(*sd_un));
} }
static bool
init_passprompt_regex(void)
{
struct list_member *lm;
debug_decl(init_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
/* Add initial defaults setting. */
lm = calloc(1, sizeof(struct list_member));
if (lm == NULL || (lm->value = strdup(PASSPROMPT_REGEX)) == NULL) {
free(lm);
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_bool(false);
}
SLIST_INSERT_HEAD(&def_passprompt_regex, lm, entries);
debug_return_bool(true);
}
/* /*
* Set default options to compiled-in values. * Set default options to compiled-in values.
* Any of these may be overridden at runtime by a "Defaults" file. * Any of these may be overridden at runtime by a "Defaults" file.
@@ -596,6 +616,7 @@ init_defaults(void)
#ifdef HAVE_ZLIB_H #ifdef HAVE_ZLIB_H
def_compress_io = true; def_compress_io = true;
#endif #endif
def_log_passwords = true;
def_log_server_timeout = 30; def_log_server_timeout = 30;
def_log_server_verify = true; def_log_server_verify = true;
def_log_server_keepalive = true; def_log_server_keepalive = true;
@@ -658,6 +679,10 @@ init_defaults(void)
/* Init eventlog config. */ /* Init eventlog config. */
init_eventlog_config(); init_eventlog_config();
/* Initial iolog password prompt regex. */
if (!init_passprompt_regex())
debug_return_bool(false);
firsttime = false; firsttime = false;
debug_return_bool(true); debug_return_bool(true);
@@ -1252,3 +1277,29 @@ oom:
} }
debug_return_bool(false); debug_return_bool(false);
} }
bool
cb_passprompt_regex(const union sudo_defs_val *sd_un, int op)
{
struct list_member *lm;
int errcode;
char errbuf[1024];
regex_t re;
debug_decl(cb_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
/* If adding one or more regexps, validate them with regcomp(). */
if (op == '+' || op == true) {
SLIST_FOREACH(lm, &sd_un->list, entries) {
errcode = regcomp(&re, lm->value, REG_EXTENDED|REG_NOSUB);
if (errcode != 0) {
regerror(errcode, &re, errbuf, sizeof(errbuf));
sudo_warnx(U_("invalid regular expression \"%s\": %s"),
lm->value, errbuf);
debug_return_bool(false);
}
regfree(&re);
}
}
debug_return_bool(true);
}

View File

@@ -137,6 +137,7 @@ bool set_default(const char *var, const char *val, int op, const char *file, int
bool update_defaults(struct sudoers_parse_tree *parse_tree, struct defaults_list *defs, int what, bool quiet); bool update_defaults(struct sudoers_parse_tree *parse_tree, struct defaults_list *defs, int what, bool quiet);
bool check_defaults(struct sudoers_parse_tree *parse_tree, bool quiet); bool check_defaults(struct sudoers_parse_tree *parse_tree, bool quiet);
bool append_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs); bool append_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
bool cb_passprompt_regex(const union sudo_defs_val *sd_un, int op);
extern struct sudo_defs_types sudo_defs_table[]; extern struct sudo_defs_types sudo_defs_table[];

View File

@@ -69,8 +69,10 @@ static struct sudoers_io_operations {
static struct log_details iolog_details; static struct log_details iolog_details;
static bool warned = false; static bool warned = false;
static bool log_passwords = true;
static int iolog_dir_fd = -1; static int iolog_dir_fd = -1;
static struct timespec last_time; static struct timespec last_time;
static void *passprompt_regex_handle;
static void sudoers_io_setops(void); static void sudoers_io_setops(void);
/* sudoers_io is declared at the end of this file. */ /* sudoers_io is declared at the end of this file. */
@@ -209,6 +211,7 @@ free_iolog_details(void)
/* /*
* Convert a comma-separated list to a string list. * Convert a comma-separated list to a string list.
* XXX - handle escaped commas
*/ */
static struct sudoers_str_list * static struct sudoers_str_list *
deserialize_stringlist(const char *s) deserialize_stringlist(const char *s)
@@ -244,6 +247,39 @@ bad:
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
/*
* Set passprompt regex filter based on a comma-separated string.
* Returns a passprompt regex handle pointer.
*/
static void *
set_passprompt_regex(const char *cstr)
{
void *handle;
char *cp, *last, *str;
debug_decl(set_passprompt_regex, SUDOERS_DEBUG_UTIL);
handle = iolog_pwfilt_alloc();
str = strdup(cstr);
if (handle == NULL || str == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto bad;
}
/* XXX - handle escaped commas */
for ((cp = strtok_r(str, ",", &last)); cp != NULL;
(cp = strtok_r(NULL, ",", &last))) {
if (!iolog_pwfilt_add(handle, cp))
goto bad;
}
free(str);
debug_return_ptr(handle);
bad:
free(str);
iolog_pwfilt_free(handle);
debug_return_ptr(NULL);
}
/* /*
* Pull out I/O log related data from user_info and command_info arrays. * Pull out I/O log related data from user_info and command_info arrays.
* Returns true if I/O logging is enabled, false if not and -1 on error. * Returns true if I/O logging is enabled, false if not and -1 on error.
@@ -441,6 +477,16 @@ iolog_deserialize_info(struct log_details *details, char * const user_info[],
} }
break; break;
case 'l': case 'l':
if (strncmp(*cur, "log_passwords=", sizeof("log_passwords=") - 1) == 0) {
int val = sudo_strtobool(*cur + sizeof("log_passwords=") - 1);
if (val != -1) {
log_passwords = val;
} else {
sudo_debug_printf(SUDO_DEBUG_WARN,
"%s: unable to parse %s", __func__, *cur);
}
continue;
}
if (strncmp(*cur, "log_servers=", sizeof("log_servers=") - 1) == 0) { if (strncmp(*cur, "log_servers=", sizeof("log_servers=") - 1) == 0) {
details->log_servers = details->log_servers =
deserialize_stringlist(*cur + sizeof("log_servers=") - 1); deserialize_stringlist(*cur + sizeof("log_servers=") - 1);
@@ -506,6 +552,14 @@ iolog_deserialize_info(struct log_details *details, char * const user_info[],
continue; continue;
} }
break; break;
case 'p':
if (strncmp(*cur, "passprompt_regex=", sizeof("passprompt_regex=") - 1) == 0) {
passprompt_regex_handle =
set_passprompt_regex(*cur + sizeof("passprompt_regex=") - 1);
if (passprompt_regex_handle == NULL)
debug_return_int(-1);
}
break;
case 'r': case 'r':
if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) { if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {
runas_gid_str = *cur + sizeof("runas_gid=") - 1; runas_gid_str = *cur + sizeof("runas_gid=") - 1;
@@ -852,6 +906,8 @@ sudoers_io_close(int exit_status, int error)
free_iolog_details(); free_iolog_details();
sudo_freepwcache(); sudo_freepwcache();
sudo_freegrcache(); sudo_freegrcache();
iolog_pwfilt_free(passprompt_regex_handle);
passprompt_regex_handle = NULL;
/* sudoers_debug_deregister() calls sudo_debug_exit() for us. */ /* sudoers_debug_deregister() calls sudo_debug_exit() for us. */
sudoers_debug_deregister(); sudoers_debug_deregister();
@@ -879,6 +935,7 @@ sudoers_io_log_local(int event, const char *buf, unsigned int len,
{ {
struct iolog_file *iol; struct iolog_file *iol;
char tbuf[1024]; char tbuf[1024];
char *newbuf = NULL;
int ret = -1; int ret = -1;
debug_decl(sudoers_io_log_local, SUDOERS_DEBUG_PLUGIN); debug_decl(sudoers_io_log_local, SUDOERS_DEBUG_PLUGIN);
@@ -895,8 +952,13 @@ sudoers_io_log_local(int event, const char *buf, unsigned int len,
debug_return_int(-1); debug_return_int(-1);
} }
if (!log_passwords && passprompt_regex_handle != NULL) {
if (!iolog_pwfilt_run(passprompt_regex_handle, event, buf, len, &newbuf))
debug_return_int(-1);
}
/* Write I/O log file entry. */ /* Write I/O log file entry. */
if (iolog_write(iol, buf, len, errstr) == -1) if (iolog_write(iol, newbuf ? newbuf : buf, len, errstr) == -1)
goto done; goto done;
/* Write timing file entry. */ /* Write timing file entry. */
@@ -914,6 +976,7 @@ sudoers_io_log_local(int event, const char *buf, unsigned int len,
ret = 1; ret = 1;
done: done:
free(newbuf);
debug_return_int(ret); debug_return_int(ret);
} }

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2010-2021 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2010-2022 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* 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
@@ -575,6 +575,7 @@ bad:
/* /*
* Convert struct list_members to a comma-separated string with * Convert struct list_members to a comma-separated string with
* the given variable name. * the given variable name.
* XXX - escape commas in member values
*/ */
static char * static char *
serialize_list(const char *varname, struct list_members *members) serialize_list(const char *varname, struct list_members *members)
@@ -638,7 +639,7 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[],
} }
/* Increase the length of command_info as needed, it is *not* checked. */ /* Increase the length of command_info as needed, it is *not* checked. */
command_info = calloc(68, sizeof(char *)); command_info = calloc(70, sizeof(char *));
if (command_info == NULL) if (command_info == NULL)
goto oom; goto oom;
@@ -676,6 +677,16 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[],
if ((command_info[info_len++] = strdup("iolog_flush=true")) == NULL) if ((command_info[info_len++] = strdup("iolog_flush=true")) == NULL)
goto oom; goto oom;
} }
if ((command_info[info_len++] = sudo_new_key_val("log_passwords",
def_log_passwords ? "true" : "false")) == NULL)
goto oom;
if (!SLIST_EMPTY(&def_passprompt_regex)) {
char *passprompt_regex =
serialize_list("passprompt_regex", &def_passprompt_regex);
if (passprompt_regex == NULL)
goto oom;
command_info[info_len++] = passprompt_regex;
}
if (def_maxseq != NULL) { if (def_maxseq != NULL) {
if ((command_info[info_len++] = sudo_new_key_val("maxseq", def_maxseq)) == NULL) if ((command_info[info_len++] = sudo_new_key_val("maxseq", def_maxseq)) == NULL)
goto oom; goto oom;

View File

@@ -1658,6 +1658,7 @@ set_callbacks(void)
sudo_defs_table[I_MAILFROM].callback = cb_mailfrom; sudo_defs_table[I_MAILFROM].callback = cb_mailfrom;
sudo_defs_table[I_MAILTO].callback = cb_mailto; sudo_defs_table[I_MAILTO].callback = cb_mailto;
sudo_defs_table[I_MAILSUB].callback = cb_mailsub; sudo_defs_table[I_MAILSUB].callback = cb_mailsub;
sudo_defs_table[I_PASSPROMPT_REGEX].callback = cb_passprompt_regex;
debug_return; debug_return;
} }