Add support for command timeouts in sudoers. After the timeout,
the command will be terminated.
This commit is contained in:
9
MANIFEST
9
MANIFEST
@@ -407,6 +407,14 @@ plugins/sudoers/regress/sudoers/test16.in
|
|||||||
plugins/sudoers/regress/sudoers/test16.json.ok
|
plugins/sudoers/regress/sudoers/test16.json.ok
|
||||||
plugins/sudoers/regress/sudoers/test16.out.ok
|
plugins/sudoers/regress/sudoers/test16.out.ok
|
||||||
plugins/sudoers/regress/sudoers/test16.toke.ok
|
plugins/sudoers/regress/sudoers/test16.toke.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test17.in
|
||||||
|
plugins/sudoers/regress/sudoers/test17.json.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test17.out.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test17.toke.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test18.in
|
||||||
|
plugins/sudoers/regress/sudoers/test18.json.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test18.out.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test18.toke.ok
|
||||||
plugins/sudoers/regress/sudoers/test2.in
|
plugins/sudoers/regress/sudoers/test2.in
|
||||||
plugins/sudoers/regress/sudoers/test2.json.ok
|
plugins/sudoers/regress/sudoers/test2.json.ok
|
||||||
plugins/sudoers/regress/sudoers/test2.out.ok
|
plugins/sudoers/regress/sudoers/test2.out.ok
|
||||||
@@ -493,6 +501,7 @@ plugins/sudoers/sudoers_debug.h
|
|||||||
plugins/sudoers/sudoers_version.h
|
plugins/sudoers/sudoers_version.h
|
||||||
plugins/sudoers/sudoreplay.c
|
plugins/sudoers/sudoreplay.c
|
||||||
plugins/sudoers/testsudoers.c
|
plugins/sudoers/testsudoers.c
|
||||||
|
plugins/sudoers/timeout.c
|
||||||
plugins/sudoers/timestamp.c
|
plugins/sudoers/timestamp.c
|
||||||
plugins/sudoers/timestr.c
|
plugins/sudoers/timestr.c
|
||||||
plugins/sudoers/toke.c
|
plugins/sudoers/toke.c
|
||||||
|
@@ -95,9 +95,9 @@ DDEESSCCRRIIPPTTIIOONN
|
|||||||
was used to authenticate, the terminal session ID, and a time stamp
|
was used to authenticate, the terminal session ID, and a time stamp
|
||||||
(using a monotonic clock if one is available). The user may then use
|
(using a monotonic clock if one is available). The user may then use
|
||||||
ssuuddoo without a password for a short period of time (5 minutes unless
|
ssuuddoo without a password for a short period of time (5 minutes unless
|
||||||
overridden by the _t_i_m_e_o_u_t option). By default, ssuuddooeerrss uses a separate
|
overridden by the _t_i_m_e_s_t_a_m_p___t_i_m_e_o_u_t option). By default, ssuuddooeerrss uses a
|
||||||
record for each tty, which means that a user's login sessions are
|
separate record for each tty, which means that a user's login sessions
|
||||||
authenticated separately. The _t_t_y___t_i_c_k_e_t_s option can be disabled to
|
are authenticated separately. The _t_t_y___t_i_c_k_e_t_s option can be disabled to
|
||||||
force the use of a single time stamp for all of a user's sessions.
|
force the use of a single time stamp for all of a user's sessions.
|
||||||
|
|
||||||
LLooggggiinngg
|
LLooggggiinngg
|
||||||
@@ -478,12 +478,15 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
|
|||||||
|
|
||||||
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
|
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
|
||||||
|
|
||||||
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Tag_Spec)
|
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Timeout_Spec |
|
||||||
|
Tag_Spec)
|
||||||
|
|
||||||
SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
|
SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
|
||||||
|
|
||||||
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
|
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
|
||||||
|
|
||||||
|
Timeout_Spec ::= 'TIMEOUT=timeout'
|
||||||
|
|
||||||
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
|
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
|
||||||
'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
|
'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
|
||||||
'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
|
'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
|
||||||
@@ -605,6 +608,16 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
|
|||||||
Privileges can be excluded from a set by prefixing the privilege name
|
Privileges can be excluded from a set by prefixing the privilege name
|
||||||
with either an `!' or `-' character.
|
with either an `!' or `-' character.
|
||||||
|
|
||||||
|
TTiimmeeoouutt__SSppeecc
|
||||||
|
A command may have a timeout associated with it. If the timeout expires
|
||||||
|
before the command has exited, the command will be terminated. The
|
||||||
|
timeout may be specified in combinations of days, hours, minutes and
|
||||||
|
seconds. For example, a timeout of 7 days, 8 hours, 30 minutes and 10
|
||||||
|
seconds would be written as 7d8h30m10s where the letter following a
|
||||||
|
number indicates the unit of time. Any of the days, minutes, hours or
|
||||||
|
seconds may be omitted. If a number is specified without a unit, seconds
|
||||||
|
is assumed.
|
||||||
|
|
||||||
TTaagg__SSppeecc
|
TTaagg__SSppeecc
|
||||||
A command may have zero or more tags associated with it. The following
|
A command may have zero or more tags associated with it. The following
|
||||||
tag values are supported: EXEC, NOEXEC, FOLLOW, NOFOLLOW, LOG_INPUT,
|
tag values are supported: EXEC, NOEXEC, FOLLOW, NOFOLLOW, LOG_INPUT,
|
||||||
@@ -1422,6 +1435,13 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
|
|||||||
file descriptor at which to start closing. The default
|
file descriptor at which to start closing. The default
|
||||||
is 3.
|
is 3.
|
||||||
|
|
||||||
|
command_timeout The maximum amount of time a command is allowed to run
|
||||||
|
before it is terminated. See the Timeout_Spec section
|
||||||
|
for a description of the timeout syntax.
|
||||||
|
|
||||||
|
This setting is only supported by version 1.8.19 or
|
||||||
|
higher.
|
||||||
|
|
||||||
maxseq The maximum sequence number that will be substituted
|
maxseq The maximum sequence number that will be substituted
|
||||||
for the ``%{seq}'' escape in the I/O log file (see the
|
for the ``%{seq}'' escape in the I/O log file (see the
|
||||||
_i_o_l_o_g___d_i_r description above for more information).
|
_i_o_l_o_g___d_i_r description above for more information).
|
||||||
|
@@ -224,7 +224,7 @@ The user may then use
|
|||||||
without a password for a short period of time
|
without a password for a short period of time
|
||||||
(\fR@timeout@\fR
|
(\fR@timeout@\fR
|
||||||
minutes unless overridden by the
|
minutes unless overridden by the
|
||||||
\fItimeout\fR
|
\fItimestamp_timeout\fR
|
||||||
option)
|
option)
|
||||||
\&.
|
\&.
|
||||||
By default,
|
By default,
|
||||||
@@ -986,12 +986,15 @@ Cmnd_Spec ::= Runas_Spec? Option_Spec* Cmnd
|
|||||||
|
|
||||||
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
|
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
|
||||||
|
|
||||||
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Tag_Spec)
|
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Timeout_Spec |
|
||||||
|
Tag_Spec)
|
||||||
|
|
||||||
SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
|
SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
|
||||||
|
|
||||||
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
|
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
|
||||||
|
|
||||||
|
Timeout_Spec ::= 'TIMEOUT=timeout'
|
||||||
|
|
||||||
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
|
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
|
||||||
'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
|
'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
|
||||||
'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
|
'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
|
||||||
@@ -1253,6 +1256,18 @@ name with either an
|
|||||||
or
|
or
|
||||||
\(oq\-\(cq
|
\(oq\-\(cq
|
||||||
character.
|
character.
|
||||||
|
.SS "Timeout_Spec"
|
||||||
|
A command may have a timeout associated with it.
|
||||||
|
If the timeout expires before the command has exited, the
|
||||||
|
command will be terminated.
|
||||||
|
The timeout may be specified in combinations of days, hours,
|
||||||
|
minutes and seconds.
|
||||||
|
For example, a timeout of 7 days, 8 hours, 30 minutes and
|
||||||
|
10 seconds would be written as
|
||||||
|
\fR7d8h30m10s\fR
|
||||||
|
where the letter following a number indicates the unit of time.
|
||||||
|
Any of the days, minutes, hours or seconds may be omitted.
|
||||||
|
If a number is specified without a unit, seconds is assumed.
|
||||||
.SS "Tag_Spec"
|
.SS "Tag_Spec"
|
||||||
A command may have zero or more tags associated with it.
|
A command may have zero or more tags associated with it.
|
||||||
The following tag values are supported:
|
The following tag values are supported:
|
||||||
@@ -2988,6 +3003,15 @@ to start closing.
|
|||||||
The default is
|
The default is
|
||||||
\fR3\fR.
|
\fR3\fR.
|
||||||
.TP 18n
|
.TP 18n
|
||||||
|
command_timeout
|
||||||
|
The maximum amount of time a command is allowed to run before
|
||||||
|
it is terminated.
|
||||||
|
See the
|
||||||
|
\fRTimeout_Spec\fR
|
||||||
|
section for a description of the timeout syntax.
|
||||||
|
.sp
|
||||||
|
This setting is only supported by version 1.8.19 or higher.
|
||||||
|
.TP 18n
|
||||||
maxseq
|
maxseq
|
||||||
The maximum sequence number that will be substituted for the
|
The maximum sequence number that will be substituted for the
|
||||||
\(Lq\fR%{seq}\fR\(Rq
|
\(Lq\fR%{seq}\fR\(Rq
|
||||||
|
@@ -213,7 +213,7 @@ without a password for a short period of time
|
|||||||
.Po
|
.Po
|
||||||
.Li @timeout@
|
.Li @timeout@
|
||||||
minutes unless overridden by the
|
minutes unless overridden by the
|
||||||
.Em timeout
|
.Em timestamp_timeout
|
||||||
option
|
option
|
||||||
.Pc .
|
.Pc .
|
||||||
By default,
|
By default,
|
||||||
@@ -939,12 +939,15 @@ Cmnd_Spec ::= Runas_Spec? Option_Spec* Cmnd
|
|||||||
|
|
||||||
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
|
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
|
||||||
|
|
||||||
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Tag_Spec)
|
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Timeout_Spec |
|
||||||
|
Tag_Spec)
|
||||||
|
|
||||||
SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
|
SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
|
||||||
|
|
||||||
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
|
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
|
||||||
|
|
||||||
|
Timeout_Spec ::= 'TIMEOUT=timeout'
|
||||||
|
|
||||||
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
|
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
|
||||||
'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
|
'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
|
||||||
'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
|
'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
|
||||||
@@ -1176,6 +1179,18 @@ name with either an
|
|||||||
or
|
or
|
||||||
.Ql \-
|
.Ql \-
|
||||||
character.
|
character.
|
||||||
|
.Ss Timeout_Spec
|
||||||
|
A command may have a timeout associated with it.
|
||||||
|
If the timeout expires before the command has exited, the
|
||||||
|
command will be terminated.
|
||||||
|
The timeout may be specified in combinations of days, hours,
|
||||||
|
minutes and seconds.
|
||||||
|
For example, a timeout of 7 days, 8 hours, 30 minutes and
|
||||||
|
10 seconds would be written as
|
||||||
|
.Li 7d8h30m10s
|
||||||
|
where the letter following a number indicates the unit of time.
|
||||||
|
Any of the days, minutes, hours or seconds may be omitted.
|
||||||
|
If a number is specified without a unit, seconds is assumed.
|
||||||
.Ss Tag_Spec
|
.Ss Tag_Spec
|
||||||
A command may have zero or more tags associated with it.
|
A command may have zero or more tags associated with it.
|
||||||
The following tag values are supported:
|
The following tag values are supported:
|
||||||
@@ -2804,6 +2819,14 @@ option can be used to specify a different file descriptor at which
|
|||||||
to start closing.
|
to start closing.
|
||||||
The default is
|
The default is
|
||||||
.Li 3 .
|
.Li 3 .
|
||||||
|
.It command_timeout
|
||||||
|
The maximum amount of time a command is allowed to run before
|
||||||
|
it is terminated.
|
||||||
|
See the
|
||||||
|
.Li Timeout_Spec
|
||||||
|
section for a description of the timeout syntax.
|
||||||
|
.Pp
|
||||||
|
This setting is only supported by version 1.8.20 or higher.
|
||||||
.It maxseq
|
.It maxseq
|
||||||
The maximum sequence number that will be substituted for the
|
The maximum sequence number that will be substituted for the
|
||||||
.Dq Li %{seq}
|
.Dq Li %{seq}
|
||||||
|
@@ -152,8 +152,8 @@ AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@
|
|||||||
|
|
||||||
LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo hexchar.lo \
|
LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo hexchar.lo \
|
||||||
gram.lo match.lo match_addr.lo pwutil.lo pwutil_impl.lo \
|
gram.lo match.lo match_addr.lo pwutil.lo pwutil_impl.lo \
|
||||||
rcstr.lo redblack.lo sudoers_debug.lo timestr.lo \
|
rcstr.lo redblack.lo sudoers_debug.lo timeout.lo \
|
||||||
toke.lo toke_util.lo
|
timestr.lo toke.lo toke_util.lo
|
||||||
|
|
||||||
SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo find_path.lo \
|
SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo find_path.lo \
|
||||||
gc.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
|
gc.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
|
||||||
@@ -1077,6 +1077,16 @@ testsudoers.o: $(srcdir)/testsudoers.c $(devdir)/def_data.h $(devdir)/gram.h \
|
|||||||
$(srcdir)/sudoers_debug.h $(srcdir)/tsgetgrpw.h \
|
$(srcdir)/sudoers_debug.h $(srcdir)/tsgetgrpw.h \
|
||||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/testsudoers.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/testsudoers.c
|
||||||
|
timeout.lo: $(srcdir)/timeout.c $(devdir)/def_data.h \
|
||||||
|
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||||
|
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||||
|
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||||
|
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||||
|
$(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||||
|
$(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||||
|
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||||
|
$(top_builddir)/pathnames.h
|
||||||
|
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/timeout.c
|
||||||
timestamp.lo: $(srcdir)/timestamp.c $(devdir)/def_data.h \
|
timestamp.lo: $(srcdir)/timestamp.c $(devdir)/def_data.h \
|
||||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||||
|
@@ -449,6 +449,10 @@ struct sudo_defs_types sudo_defs_table[] = {
|
|||||||
"ignore_unknown_defaults", T_FLAG,
|
"ignore_unknown_defaults", T_FLAG,
|
||||||
N_("Ignore unknown Defaults entries in sudoers instead of producing a warning"),
|
N_("Ignore unknown Defaults entries in sudoers instead of producing a warning"),
|
||||||
NULL,
|
NULL,
|
||||||
|
}, {
|
||||||
|
"command_timeout", T_TIMEOUT|T_BOOL,
|
||||||
|
N_("Time in seconds after which the command will be terminated: %u"),
|
||||||
|
NULL,
|
||||||
}, {
|
}, {
|
||||||
NULL, 0, NULL
|
NULL, 0, NULL
|
||||||
}
|
}
|
||||||
|
@@ -208,6 +208,8 @@
|
|||||||
#define def_fdexec (sudo_defs_table[I_FDEXEC].sd_un.tuple)
|
#define def_fdexec (sudo_defs_table[I_FDEXEC].sd_un.tuple)
|
||||||
#define I_IGNORE_UNKNOWN_DEFAULTS 104
|
#define I_IGNORE_UNKNOWN_DEFAULTS 104
|
||||||
#define def_ignore_unknown_defaults (sudo_defs_table[I_IGNORE_UNKNOWN_DEFAULTS].sd_un.flag)
|
#define def_ignore_unknown_defaults (sudo_defs_table[I_IGNORE_UNKNOWN_DEFAULTS].sd_un.flag)
|
||||||
|
#define I_COMMAND_TIMEOUT 105
|
||||||
|
#define def_command_timeout (sudo_defs_table[I_COMMAND_TIMEOUT].sd_un.ival)
|
||||||
|
|
||||||
enum def_tuple {
|
enum def_tuple {
|
||||||
never,
|
never,
|
||||||
|
@@ -329,3 +329,6 @@ fdexec
|
|||||||
ignore_unknown_defaults
|
ignore_unknown_defaults
|
||||||
T_FLAG
|
T_FLAG
|
||||||
"Ignore unknown Defaults entries in sudoers instead of producing a warning"
|
"Ignore unknown Defaults entries in sudoers instead of producing a warning"
|
||||||
|
command_timeout
|
||||||
|
T_TIMEOUT|T_BOOL
|
||||||
|
"Time in seconds after which the command will be terminated: %u"
|
||||||
|
@@ -101,6 +101,7 @@ static bool store_mode(const char *str, union sudo_defs_val *sd_un);
|
|||||||
static int store_str(const char *str, union sudo_defs_val *sd_un);
|
static int store_str(const char *str, union sudo_defs_val *sd_un);
|
||||||
static bool store_syslogfac(const char *str, union sudo_defs_val *sd_un);
|
static bool store_syslogfac(const char *str, union sudo_defs_val *sd_un);
|
||||||
static bool store_syslogpri(const char *str, union sudo_defs_val *sd_un);
|
static bool store_syslogpri(const char *str, union sudo_defs_val *sd_un);
|
||||||
|
static bool store_timeout(const char *str, union sudo_defs_val *sd_un);
|
||||||
static bool store_tuple(const char *str, union sudo_defs_val *sd_un, struct def_values *tuple_vals);
|
static bool store_tuple(const char *str, union sudo_defs_val *sd_un, struct def_values *tuple_vals);
|
||||||
static bool store_uint(const char *str, union sudo_defs_val *sd_un);
|
static bool store_uint(const char *str, union sudo_defs_val *sd_un);
|
||||||
static bool store_float(const char *str, union sudo_defs_val *sd_un);
|
static bool store_float(const char *str, union sudo_defs_val *sd_un);
|
||||||
@@ -178,6 +179,13 @@ dump_defaults(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case T_TIMEOUT:
|
||||||
|
if (cur->sd_un.ival) {
|
||||||
|
sudo_printf(SUDO_CONV_INFO_MSG, desc,
|
||||||
|
cur->sd_un.ival);
|
||||||
|
sudo_printf(SUDO_CONV_INFO_MSG, "\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case T_TUPLE:
|
case T_TUPLE:
|
||||||
for (def = cur->values; def->sval; def++) {
|
for (def = cur->values; def->sval; def++) {
|
||||||
if (cur->sd_un.tuple == def->nval) {
|
if (cur->sd_un.tuple == def->nval) {
|
||||||
@@ -301,6 +309,9 @@ parse_default_entry(struct sudo_defs_types *def, const char *val, int op,
|
|||||||
case T_LIST:
|
case T_LIST:
|
||||||
rc = store_list(val, sd_un, op);
|
rc = store_list(val, sd_un, op);
|
||||||
break;
|
break;
|
||||||
|
case T_TIMEOUT:
|
||||||
|
rc = store_timeout(val, sd_un);
|
||||||
|
break;
|
||||||
case T_TUPLE:
|
case T_TUPLE:
|
||||||
rc = store_tuple(val, sd_un, def->values);
|
rc = store_tuple(val, sd_un, def->values);
|
||||||
break;
|
break;
|
||||||
@@ -986,6 +997,25 @@ store_mode(const char *str, union sudo_defs_val *sd_un)
|
|||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
store_timeout(const char *str, union sudo_defs_val *sd_un)
|
||||||
|
{
|
||||||
|
debug_decl(store_mode, SUDOERS_DEBUG_DEFAULTS)
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
sd_un->ival = 0;
|
||||||
|
} else {
|
||||||
|
int seconds = parse_timeout(str);
|
||||||
|
if (seconds == -1) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
|
||||||
|
"%s", str);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
sd_un->ival = seconds;
|
||||||
|
}
|
||||||
|
debug_return_bool(true);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
list_op(const char *str, size_t len, union sudo_defs_val *sd_un,
|
list_op(const char *str, size_t len, union sudo_defs_val *sd_un,
|
||||||
enum list_ops op)
|
enum list_ops op)
|
||||||
|
@@ -99,6 +99,8 @@ struct early_default {
|
|||||||
#define T_TUPLE 0x009
|
#define T_TUPLE 0x009
|
||||||
#undef T_FLOAT
|
#undef T_FLOAT
|
||||||
#define T_FLOAT 0x010
|
#define T_FLOAT 0x010
|
||||||
|
#undef T_TIMEOUT
|
||||||
|
#define T_TIMEOUT 0x020
|
||||||
#undef T_MASK
|
#undef T_MASK
|
||||||
#define T_MASK 0x0FF
|
#define T_MASK 0x0FF
|
||||||
#undef T_BOOL
|
#undef T_BOOL
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -36,11 +36,12 @@
|
|||||||
#define ROLE 292
|
#define ROLE 292
|
||||||
#define PRIVS 293
|
#define PRIVS 293
|
||||||
#define LIMITPRIVS 294
|
#define LIMITPRIVS 294
|
||||||
#define MYSELF 295
|
#define CMND_TIMEOUT 295
|
||||||
#define SHA224_TOK 296
|
#define MYSELF 296
|
||||||
#define SHA256_TOK 297
|
#define SHA224_TOK 297
|
||||||
#define SHA384_TOK 298
|
#define SHA256_TOK 298
|
||||||
#define SHA512_TOK 299
|
#define SHA384_TOK 299
|
||||||
|
#define SHA512_TOK 300
|
||||||
#ifndef YYSTYPE_DEFINED
|
#ifndef YYSTYPE_DEFINED
|
||||||
#define YYSTYPE_DEFINED
|
#define YYSTYPE_DEFINED
|
||||||
typedef union {
|
typedef union {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
%{
|
%{
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2016
|
* Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2017
|
||||||
* 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
|
||||||
@@ -43,6 +43,8 @@
|
|||||||
#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
|
#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
|
||||||
# include <alloca.h>
|
# include <alloca.h>
|
||||||
#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
|
#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include "sudoers.h" /* XXX */
|
#include "sudoers.h" /* XXX */
|
||||||
@@ -66,6 +68,7 @@ struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs);
|
|||||||
/*
|
/*
|
||||||
* Local protoypes
|
* Local protoypes
|
||||||
*/
|
*/
|
||||||
|
static void init_options(struct command_options *opts);
|
||||||
static bool add_defaults(int, struct member *, struct defaults *);
|
static bool add_defaults(int, struct member *, struct defaults *);
|
||||||
static bool add_userspec(struct member *, struct privilege *);
|
static bool add_userspec(struct member *, struct privilege *);
|
||||||
static struct defaults *new_default(char *, char *, short);
|
static struct defaults *new_default(char *, char *, short);
|
||||||
@@ -127,6 +130,7 @@ static struct sudo_digest *new_digest(int, const char *);
|
|||||||
%token <tok> ROLE /* SELinux role */
|
%token <tok> ROLE /* SELinux role */
|
||||||
%token <tok> PRIVS /* Solaris privileges */
|
%token <tok> PRIVS /* Solaris privileges */
|
||||||
%token <tok> LIMITPRIVS /* Solaris limit privileges */
|
%token <tok> LIMITPRIVS /* Solaris limit privileges */
|
||||||
|
%token <tok> CMND_TIMEOUT /* command timeout */
|
||||||
%token <tok> MYSELF /* run as myself, not another user */
|
%token <tok> MYSELF /* run as myself, not another user */
|
||||||
%token <tok> SHA224_TOK /* sha224 token */
|
%token <tok> SHA224_TOK /* sha224 token */
|
||||||
%token <tok> SHA256_TOK /* sha256 token */
|
%token <tok> SHA256_TOK /* sha256 token */
|
||||||
@@ -159,7 +163,9 @@ static struct sudo_digest *new_digest(int, const char *);
|
|||||||
%type <string> typespec
|
%type <string> typespec
|
||||||
%type <string> privsspec
|
%type <string> privsspec
|
||||||
%type <string> limitprivsspec
|
%type <string> limitprivsspec
|
||||||
|
%type <string> timeoutspec
|
||||||
%type <digest> digest
|
%type <digest> digest
|
||||||
|
%type <options> options
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@@ -347,6 +353,9 @@ cmndspeclist : cmndspec
|
|||||||
if ($3->limitprivs == NULL)
|
if ($3->limitprivs == NULL)
|
||||||
$3->limitprivs = prev->limitprivs;
|
$3->limitprivs = prev->limitprivs;
|
||||||
#endif /* HAVE_PRIV_SET */
|
#endif /* HAVE_PRIV_SET */
|
||||||
|
/* propagate command timeout */
|
||||||
|
if ($3->timeout == UNSPEC)
|
||||||
|
$3->timeout = prev->timeout;
|
||||||
/* propagate tags and runas list */
|
/* propagate tags and runas list */
|
||||||
if ($3->tags.nopasswd == UNSPEC)
|
if ($3->tags.nopasswd == UNSPEC)
|
||||||
$3->tags.nopasswd = prev->tags.nopasswd;
|
$3->tags.nopasswd = prev->tags.nopasswd;
|
||||||
@@ -411,6 +420,7 @@ cmndspec : runasspec options digcmnd {
|
|||||||
cs->privs = $2.privs;
|
cs->privs = $2.privs;
|
||||||
cs->limitprivs = $2.limitprivs;
|
cs->limitprivs = $2.limitprivs;
|
||||||
#endif
|
#endif
|
||||||
|
cs->timeout = $2.timeout;
|
||||||
cs->tags = $2.tags;
|
cs->tags = $2.tags;
|
||||||
cs->cmnd = $3;
|
cs->cmnd = $3;
|
||||||
HLTQ_INIT(cs, entries);
|
HLTQ_INIT(cs, entries);
|
||||||
@@ -476,6 +486,11 @@ opcmnd : cmnd {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
timeoutspec : CMND_TIMEOUT '=' WORD {
|
||||||
|
$$ = $3;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
rolespec : ROLE '=' WORD {
|
rolespec : ROLE '=' WORD {
|
||||||
$$ = $3;
|
$$ = $3;
|
||||||
}
|
}
|
||||||
@@ -563,13 +578,14 @@ runaslist : /* empty */ {
|
|||||||
;
|
;
|
||||||
|
|
||||||
options : /* empty */ {
|
options : /* empty */ {
|
||||||
TAGS_INIT($$.tags);
|
init_options(&$$);
|
||||||
#ifdef HAVE_SELINUX
|
}
|
||||||
$$.role = NULL, $$.type = NULL;
|
| options timeoutspec {
|
||||||
#endif
|
$$.timeout = parse_timeout($2);
|
||||||
#ifdef HAVE_PRIV_SET
|
if ($$.timeout == -1) {
|
||||||
$$.privs = NULL, $$.limitprivs = NULL;
|
sudoerserror(N_("unable parse timeout value"));
|
||||||
#endif
|
YYERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
| options NOPASSWD {
|
| options NOPASSWD {
|
||||||
$$.tags.nopasswd = true;
|
$$.tags.nopasswd = true;
|
||||||
@@ -1145,3 +1161,21 @@ init_parser(const char *path, bool quiet)
|
|||||||
|
|
||||||
debug_return_bool(ret);
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize all options in a cmndspec.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
init_options(struct command_options *opts)
|
||||||
|
{
|
||||||
|
TAGS_INIT(opts->tags);
|
||||||
|
opts->timeout = UNSPEC;
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
opts->role = NULL;
|
||||||
|
opts->type = NULL;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_PRIV_SET
|
||||||
|
opts->privs = NULL;
|
||||||
|
opts->limitprivs = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@@ -2479,6 +2479,8 @@ sudo_ldap_display_entry_short(LDAP *ld, LDAPMessage *entry, struct passwd *pw,
|
|||||||
sudo_lbuf_append(lbuf, negated ? "NOSETENV: " : "SETENV: ");
|
sudo_lbuf_append(lbuf, negated ? "NOSETENV: " : "SETENV: ");
|
||||||
else if (strcmp(val, "mail_all_cmnds") == 0 || strcmp(val, "mail_always") == 0)
|
else if (strcmp(val, "mail_all_cmnds") == 0 || strcmp(val, "mail_always") == 0)
|
||||||
sudo_lbuf_append(lbuf, negated ? "NOMAIL: " : "MAIL: ");
|
sudo_lbuf_append(lbuf, negated ? "NOMAIL: " : "MAIL: ");
|
||||||
|
else if (!negated && strcmp(val, "command_timeout") == 0)
|
||||||
|
sudo_lbuf_append(lbuf, "TIMEOUT=%s", val);
|
||||||
}
|
}
|
||||||
ldap_value_free_len(bv);
|
ldap_value_free_len(bv);
|
||||||
}
|
}
|
||||||
|
@@ -147,6 +147,7 @@ sub print_record {
|
|||||||
elsif (/^T_LOGPRI/) { $v = "ival"; }
|
elsif (/^T_LOGPRI/) { $v = "ival"; }
|
||||||
elsif (/^T_TUPLE/) { $v = "tuple"; }
|
elsif (/^T_TUPLE/) { $v = "tuple"; }
|
||||||
elsif (/^T_FLOAT/) { $v = "fval"; }
|
elsif (/^T_FLOAT/) { $v = "fval"; }
|
||||||
|
elsif (/^T_TIMEOUT/) { $v = "ival"; }
|
||||||
else { die "$0: unknown defaults type: $_\n"; }
|
else { die "$0: unknown defaults type: $_\n"; }
|
||||||
}
|
}
|
||||||
printf HEADER "#define %-23s (sudo_defs_table[$defname].sd_un.${v})\n",
|
printf HEADER "#define %-23s (sudo_defs_table[$defname].sd_un.${v})\n",
|
||||||
|
@@ -145,7 +145,7 @@ sudo_file_setdefs(struct sudo_nss *nss)
|
|||||||
int
|
int
|
||||||
sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
|
sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
|
||||||
{
|
{
|
||||||
int match, host_match, runas_match, cmnd_match;
|
int match, host_match, runas_match, cmnd_match, timeout;
|
||||||
struct cmndspec *cs;
|
struct cmndspec *cs;
|
||||||
struct cmndtag *tags = NULL;
|
struct cmndtag *tags = NULL;
|
||||||
struct privilege *priv;
|
struct privilege *priv;
|
||||||
@@ -227,6 +227,7 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
|
|||||||
if (cmnd_match != UNSPEC) {
|
if (cmnd_match != UNSPEC) {
|
||||||
match = cmnd_match;
|
match = cmnd_match;
|
||||||
tags = &cs->tags;
|
tags = &cs->tags;
|
||||||
|
timeout = cs->timeout;
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
/* Set role and type if not specified on command line. */
|
/* Set role and type if not specified on command line. */
|
||||||
if (user_role == NULL) {
|
if (user_role == NULL) {
|
||||||
@@ -301,6 +302,8 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
|
|||||||
if (match == ALLOW) {
|
if (match == ALLOW) {
|
||||||
SET(validated, VALIDATE_SUCCESS);
|
SET(validated, VALIDATE_SUCCESS);
|
||||||
CLR(validated, VALIDATE_FAILURE);
|
CLR(validated, VALIDATE_FAILURE);
|
||||||
|
if (timeout > 0)
|
||||||
|
def_command_timeout = timeout;
|
||||||
if (tags != NULL) {
|
if (tags != NULL) {
|
||||||
if (tags->nopasswd != UNSPEC)
|
if (tags->nopasswd != UNSPEC)
|
||||||
def_authenticate = !tags->nopasswd;
|
def_authenticate = !tags->nopasswd;
|
||||||
@@ -370,6 +373,11 @@ sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
|
|||||||
if (cs->type)
|
if (cs->type)
|
||||||
sudo_lbuf_append(lbuf, "TYPE=%s ", cs->type);
|
sudo_lbuf_append(lbuf, "TYPE=%s ", cs->type);
|
||||||
#endif /* HAVE_SELINUX */
|
#endif /* HAVE_SELINUX */
|
||||||
|
if (cs->timeout > 0) {
|
||||||
|
char numbuf[(((sizeof(int) * 8) + 2) / 3) + 2];
|
||||||
|
snprintf(numbuf, sizeof(numbuf), "%d", cs->timeout);
|
||||||
|
sudo_lbuf_append(lbuf, "TIMEOUT=%s ", numbuf);
|
||||||
|
}
|
||||||
if (TAG_CHANGED(setenv)) {
|
if (TAG_CHANGED(setenv)) {
|
||||||
tags->setenv = cs->tags.setenv;
|
tags->setenv = cs->tags.setenv;
|
||||||
sudo_lbuf_append(lbuf, tags->setenv ? "SETENV: " : "NOSETENV: ");
|
sudo_lbuf_append(lbuf, tags->setenv ? "SETENV: " : "NOSETENV: ");
|
||||||
@@ -481,6 +489,8 @@ new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs)
|
|||||||
if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0))
|
if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0))
|
||||||
return true;
|
return true;
|
||||||
#endif /* HAVE_SELINUX */
|
#endif /* HAVE_SELINUX */
|
||||||
|
if (cs->timeout != prev_cs->timeout)
|
||||||
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,6 +563,11 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
|
|||||||
if (cs->type)
|
if (cs->type)
|
||||||
sudo_lbuf_append(lbuf, " Type: %s\n", cs->type);
|
sudo_lbuf_append(lbuf, " Type: %s\n", cs->type);
|
||||||
#endif /* HAVE_SELINUX */
|
#endif /* HAVE_SELINUX */
|
||||||
|
if (cs->timeout > 0) {
|
||||||
|
char numbuf[(((sizeof(int) * 8) + 2) / 3) + 2];
|
||||||
|
snprintf(numbuf, sizeof(numbuf), "%d", cs->timeout);
|
||||||
|
sudo_lbuf_append(lbuf, " Timeout: %s\n", numbuf);
|
||||||
|
}
|
||||||
sudo_lbuf_append(lbuf, _(" Commands:\n"));
|
sudo_lbuf_append(lbuf, _(" Commands:\n"));
|
||||||
}
|
}
|
||||||
sudo_lbuf_append(lbuf, "\t");
|
sudo_lbuf_append(lbuf, "\t");
|
||||||
|
@@ -113,7 +113,8 @@ struct cmndtag {
|
|||||||
* Per-command option container struct.
|
* Per-command option container struct.
|
||||||
*/
|
*/
|
||||||
struct command_options {
|
struct command_options {
|
||||||
struct cmndtag tags; /* Command tags */
|
struct cmndtag tags; /* tag specificaion */
|
||||||
|
int timeout; /* command timeout */
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
char *role, *type; /* SELinux role and type */
|
char *role, *type; /* SELinux role and type */
|
||||||
#endif
|
#endif
|
||||||
@@ -168,6 +169,7 @@ struct privilege {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure describing a linked list of Cmnd_Specs.
|
* Structure describing a linked list of Cmnd_Specs.
|
||||||
|
* XXX - include struct command_options instad of its contents inline
|
||||||
*/
|
*/
|
||||||
struct cmndspec {
|
struct cmndspec {
|
||||||
TAILQ_ENTRY(cmndspec) entries;
|
TAILQ_ENTRY(cmndspec) entries;
|
||||||
@@ -175,6 +177,7 @@ struct cmndspec {
|
|||||||
struct member_list *runasgrouplist; /* list of runas groups */
|
struct member_list *runasgrouplist; /* list of runas groups */
|
||||||
struct member *cmnd; /* command to allow/deny */
|
struct member *cmnd; /* command to allow/deny */
|
||||||
struct cmndtag tags; /* tag specificaion */
|
struct cmndtag tags; /* tag specificaion */
|
||||||
|
int timeout; /* command timeout */
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
char *role, *type; /* SELinux role and type */
|
char *role, *type; /* SELinux role and type */
|
||||||
#endif
|
#endif
|
||||||
@@ -275,4 +278,7 @@ int hexchar(const char *s);
|
|||||||
/* base64.c */
|
/* base64.c */
|
||||||
size_t base64_decode(const char *str, unsigned char *dst, size_t dsize);
|
size_t base64_decode(const char *str, unsigned char *dst, size_t dsize);
|
||||||
|
|
||||||
|
/* timeout.c */
|
||||||
|
int parse_timeout(const char *timestr);
|
||||||
|
|
||||||
#endif /* SUDOERS_PARSE_H */
|
#endif /* SUDOERS_PARSE_H */
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@courtesan.com>
|
* Copyright (c) 2010-2017 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
|
||||||
@@ -580,6 +580,10 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
|
|||||||
if ((command_info[info_len++] = sudo_new_key_val("iolog_group", def_iolog_group)) == NULL)
|
if ((command_info[info_len++] = sudo_new_key_val("iolog_group", def_iolog_group)) == NULL)
|
||||||
goto oom;
|
goto oom;
|
||||||
}
|
}
|
||||||
|
if (def_command_timeout != 0) {
|
||||||
|
if (asprintf(&command_info[info_len++], "timeout=%u", def_command_timeout) == -1)
|
||||||
|
goto oom;
|
||||||
|
}
|
||||||
if (cmnd_umask != ACCESSPERMS) {
|
if (cmnd_umask != ACCESSPERMS) {
|
||||||
if (asprintf(&command_info[info_len++], "umask=0%o", (unsigned int)cmnd_umask) == -1)
|
if (asprintf(&command_info[info_len++], "umask=0%o", (unsigned int)cmnd_umask) == -1)
|
||||||
goto oom;
|
goto oom;
|
||||||
|
13
plugins/sudoers/regress/sudoers/test17.in
Normal file
13
plugins/sudoers/regress/sudoers/test17.in
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Test parsing of command_timeout and TIMEOUT syntax
|
||||||
|
Defaults command_timeout=2d8h10m59s
|
||||||
|
user0 ALL = TIMEOUT=7D4H10M30S /usr/bin/id, /usr/bin/who, TIMEOUT=0 /bin/ls
|
||||||
|
user1 ALL = TIMEOUT=7d4h10m30s /usr/bin/id
|
||||||
|
user2 ALL = TIMEOUT=4h10m30s /usr/bin/id
|
||||||
|
user3 ALL = TIMEOUT=10m30s /usr/bin/id
|
||||||
|
user4 ALL = TIMEOUT=14d /usr/bin/id
|
||||||
|
user5 ALL = TIMEOUT=5m /usr/bin/id
|
||||||
|
user6 ALL = TIMEOUT=30s /usr/bin/id
|
||||||
|
user7 ALL = TIMEOUT=45 /usr/bin/id
|
||||||
|
user8 ALL = TIMEOUT=7d4h10m30s /usr/bin/id, TIMEOUT=4h10m30s /usr/bin/id, \
|
||||||
|
TIMEOUT=10m30s /usr/bin/id, TIMEOUT=14d /usr/bin/id, \
|
||||||
|
TIMEOUT=5m /usr/bin/id, TIMEOUT=30s /usr/bin/id
|
180
plugins/sudoers/regress/sudoers/test17.json.ok
Normal file
180
plugins/sudoers/regress/sudoers/test17.json.ok
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
"Defaults": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": "2d8h10m59s" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"User_Specs": [
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user0" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 619830 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" },
|
||||||
|
{ "command": "/usr/bin/who" },
|
||||||
|
{ "command": "/bin/ls" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user1" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 619830 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user2" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 15030 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user3" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 630 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user4" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 1209600 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user5" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 300 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user6" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 30 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user7" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 45 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user8" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostalias": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Options": [
|
||||||
|
{ "command_timeout": 619830 }
|
||||||
|
],
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/id" },
|
||||||
|
{ "command": "/usr/bin/id" },
|
||||||
|
{ "command": "/usr/bin/id" },
|
||||||
|
{ "command": "/usr/bin/id" },
|
||||||
|
{ "command": "/usr/bin/id" },
|
||||||
|
{ "command": "/usr/bin/id" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
14
plugins/sudoers/regress/sudoers/test17.out.ok
Normal file
14
plugins/sudoers/regress/sudoers/test17.out.ok
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Parses OK.
|
||||||
|
|
||||||
|
Defaults command_timeout=2d8h10m59s
|
||||||
|
|
||||||
|
|
||||||
|
user0 ALL = TIMEOUT=619830 /usr/bin/id, TIMEOUT=619830 /usr/bin/who, /bin/ls
|
||||||
|
user1 ALL = TIMEOUT=619830 /usr/bin/id
|
||||||
|
user2 ALL = TIMEOUT=15030 /usr/bin/id
|
||||||
|
user3 ALL = TIMEOUT=630 /usr/bin/id
|
||||||
|
user4 ALL = TIMEOUT=1209600 /usr/bin/id
|
||||||
|
user5 ALL = TIMEOUT=300 /usr/bin/id
|
||||||
|
user6 ALL = TIMEOUT=30 /usr/bin/id
|
||||||
|
user7 ALL = TIMEOUT=45 /usr/bin/id
|
||||||
|
user8 ALL = TIMEOUT=619830 /usr/bin/id, TIMEOUT=15030 /usr/bin/id, TIMEOUT=630 /usr/bin/id, TIMEOUT=1209600 /usr/bin/id, TIMEOUT=300 /usr/bin/id, TIMEOUT=30 /usr/bin/id
|
11
plugins/sudoers/regress/sudoers/test17.toke.ok
Normal file
11
plugins/sudoers/regress/sudoers/test17.toke.ok
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
DEFAULTS DEFVAR = WORD(2)
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND , COMMAND , CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) COMMAND , CMND_TIMEOUT = WORD(5) COMMAND , CMND_TIMEOUT = WORD(5) COMMAND , CMND_TIMEOUT = WORD(5) COMMAND , CMND_TIMEOUT = WORD(5) COMMAND , CMND_TIMEOUT = WORD(5) COMMAND
|
8
plugins/sudoers/regress/sudoers/test18.in
Normal file
8
plugins/sudoers/regress/sudoers/test18.in
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Test command_timeout and TIMEOUT syntax errors
|
||||||
|
Defaults command_timeout=2d8h10m59ss
|
||||||
|
Defaults:root command_timeout=15f
|
||||||
|
user0 ALL = TIMEOUT=7dd4h10m30s /usr/bin/id, /usr/bin/who, TIMEOUT=0 /bin/ls
|
||||||
|
user1 ALL = TIMEOUT=7d4h10mm30s /usr/bin/id
|
||||||
|
user2 ALL = TIMEOUT=4hg10m30s /usr/bin/id
|
||||||
|
user3 ALL = TIMEOUT=10m30ss /usr/bin/id
|
||||||
|
user4 ALL = TIMEOUT=14g /usr/bin/id
|
0
plugins/sudoers/regress/sudoers/test18.json.ok
Normal file
0
plugins/sudoers/regress/sudoers/test18.json.ok
Normal file
6
plugins/sudoers/regress/sudoers/test18.out.ok
Normal file
6
plugins/sudoers/regress/sudoers/test18.out.ok
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Parse error in sudoers near line 4 (problem with defaults entries).
|
||||||
|
|
||||||
|
Defaults command_timeout=2d8h10m59ss
|
||||||
|
Defaults:root command_timeout=15f
|
||||||
|
|
||||||
|
|
10
plugins/sudoers/regress/sudoers/test18.toke.ok
Normal file
10
plugins/sudoers/regress/sudoers/test18.toke.ok
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
DEFAULTS DEFVAR = WORD(2)
|
||||||
|
DEFAULTS_USER WORD(5) DEFVAR = WORD(2)
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) <*> COMMAND , COMMAND , CMND_TIMEOUT = WORD(5) COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) <*> COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) <*> COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) <*> COMMAND
|
||||||
|
WORD(5) ALL = CMND_TIMEOUT = WORD(5) <*> COMMAND
|
||||||
|
testsudoers: sudoers:2 value "2d8h10m59ss" is invalid for option "command_timeout"
|
||||||
|
testsudoers: sudoers:3 value "15f" is invalid for option "command_timeout"
|
@@ -634,6 +634,8 @@ print_privilege(struct privilege *priv)
|
|||||||
if (cs->limitprivs)
|
if (cs->limitprivs)
|
||||||
printf("LIMITPRIVS=%s ", cs->limitprivs);
|
printf("LIMITPRIVS=%s ", cs->limitprivs);
|
||||||
#endif /* HAVE_PRIV_SET */
|
#endif /* HAVE_PRIV_SET */
|
||||||
|
if (cs->timeout > 0)
|
||||||
|
printf("TIMEOUT=%d ", cs->timeout);
|
||||||
if (TAG_CHANGED(follow))
|
if (TAG_CHANGED(follow))
|
||||||
printf("%sFOLLOW: ", cs->tags.follow ? "" : "NO");
|
printf("%sFOLLOW: ", cs->tags.follow ? "" : "NO");
|
||||||
if (TAG_CHANGED(log_input))
|
if (TAG_CHANGED(log_input))
|
||||||
|
113
plugins/sudoers/timeout.c
Normal file
113
plugins/sudoers/timeout.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 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.
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# include <string.h>
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
#endif /* HAVE_STRINGS_H */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "sudo_compat.h"
|
||||||
|
#include "sudoers_debug.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a command timeout in sudoers in the format 1d2h3m4s
|
||||||
|
* (days, hours, minutes, seconds) or a number of seconds with no suffix.
|
||||||
|
* Returns the number of seconds or -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parse_timeout(const char *timestr)
|
||||||
|
{
|
||||||
|
debug_decl(parse_timeout, SUDOERS_DEBUG_PARSER)
|
||||||
|
const char digits[] = "0123456789";
|
||||||
|
const char suffixes[] = "dhms";
|
||||||
|
const char *cp;
|
||||||
|
int timeout = 0;
|
||||||
|
size_t len = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
for (cp = timestr; *cp != '\0'; cp += len) {
|
||||||
|
char ch;
|
||||||
|
long l;
|
||||||
|
|
||||||
|
if ((len = strspn(cp, digits)) == 0) {
|
||||||
|
/* parse error */
|
||||||
|
errno = EINVAL;
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
if (cp[len] == '\0') {
|
||||||
|
/* no suffix, assume seconds. */
|
||||||
|
ch = 's';
|
||||||
|
} else {
|
||||||
|
ch = tolower(cp[len]);
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a matching suffix or return an error. */
|
||||||
|
while (suffixes[idx] != ch) {
|
||||||
|
if (suffixes[idx] == '\0') {
|
||||||
|
/* parse error */
|
||||||
|
errno = EINVAL;
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
l = strtol(cp, NULL, 10);
|
||||||
|
if (errno == ERANGE || l > INT_MAX)
|
||||||
|
goto overflow;
|
||||||
|
switch (ch) {
|
||||||
|
case 'd':
|
||||||
|
if (l > INT_MAX / (24 * 60 * 60))
|
||||||
|
goto overflow;
|
||||||
|
l *= 24 * 60 * 60;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
if (l > INT_MAX / (60 * 60))
|
||||||
|
goto overflow;
|
||||||
|
l *= 60 * 60;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (l > INT_MAX / 60)
|
||||||
|
goto overflow;
|
||||||
|
l *= 60;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (l > INT_MAX - timeout)
|
||||||
|
goto overflow;
|
||||||
|
|
||||||
|
timeout += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_int(timeout);
|
||||||
|
overflow:
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -530,6 +530,11 @@ ALL {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<INITIAL>TIMEOUT {
|
||||||
|
LEXTRACE("CMND_TIMEOUT ");
|
||||||
|
LEXRETURN(CMND_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
<INITIAL>ROLE {
|
<INITIAL>ROLE {
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
LEXTRACE("ROLE ");
|
LEXTRACE("ROLE ");
|
||||||
|
@@ -781,11 +781,17 @@ print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Print tags */
|
/* Print tags */
|
||||||
if (TAGS_SET(cs->tags)) {
|
if (cs->timeout > 0 || TAGS_SET(cs->tags)) {
|
||||||
struct cmndtag tag = cs->tags;
|
struct cmndtag tag = cs->tags;
|
||||||
|
|
||||||
fprintf(fp, "%*s\"Options\": [\n", indent, "");
|
fprintf(fp, "%*s\"Options\": [\n", indent, "");
|
||||||
indent += 4;
|
indent += 4;
|
||||||
|
if (cs->timeout > 0) {
|
||||||
|
value.type = JSON_NUMBER;
|
||||||
|
value.u.number = cs->timeout;
|
||||||
|
print_pair_json(fp, "{ ", "command_timeout", &value,
|
||||||
|
TAGS_SET(tag) ? " },\n" : " }\n", indent);
|
||||||
|
}
|
||||||
if (tag.nopasswd != UNSPEC) {
|
if (tag.nopasswd != UNSPEC) {
|
||||||
value.type = JSON_BOOL;
|
value.type = JSON_BOOL;
|
||||||
value.u.boolean = !tag.nopasswd;
|
value.u.boolean = !tag.nopasswd;
|
||||||
|
Reference in New Issue
Block a user