Add support for command timeouts in sudoers. After the timeout,

the command will be terminated.
This commit is contained in:
Todd C. Miller
2017-02-14 15:56:34 -07:00
parent 4f9dcd7264
commit 3980f1531b
31 changed files with 2367 additions and 1749 deletions

View File

@@ -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

View File

@@ -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).

View File

@@ -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

View File

@@ -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}

View File

@@ -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 \

View File

@@ -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
} }

View File

@@ -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,

View File

@@ -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"

View File

@@ -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)

View File

@@ -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

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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);
} }

View File

@@ -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",

View File

@@ -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");

View File

@@ -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 */

View File

@@ -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;

View 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

View 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" }
]
}
]
}
]
}

View 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

View 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

View 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

View 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

View 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"

View File

@@ -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
View 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

View File

@@ -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 ");

View File

@@ -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;