2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 01:49:11 +00:00

Add NOTBEFORE and NOTAFTER command options similar to what is

already available in LDAP.
This commit is contained in:
Todd C. Miller 2017-02-18 15:35:48 -07:00
parent 3b19d05fe9
commit e5dee1557e
29 changed files with 2719 additions and 1812 deletions

View File

@ -264,9 +264,11 @@ plugins/sudoers/editor.c
plugins/sudoers/env.c plugins/sudoers/env.c
plugins/sudoers/find_path.c plugins/sudoers/find_path.c
plugins/sudoers/gc.c plugins/sudoers/gc.c
plugins/sudoers/gentime.c
plugins/sudoers/getdate.c plugins/sudoers/getdate.c
plugins/sudoers/getdate.y plugins/sudoers/getdate.y
plugins/sudoers/getspwuid.c plugins/sudoers/getspwuid.c
plugins/sudoers/gmtoff.c
plugins/sudoers/goodpath.c plugins/sudoers/goodpath.c
plugins/sudoers/gram.c plugins/sudoers/gram.c
plugins/sudoers/gram.h plugins/sudoers/gram.h
@ -374,6 +376,7 @@ plugins/sudoers/regress/parser/check_base64.c
plugins/sudoers/regress/parser/check_digest.c plugins/sudoers/regress/parser/check_digest.c
plugins/sudoers/regress/parser/check_digest.out.ok plugins/sudoers/regress/parser/check_digest.out.ok
plugins/sudoers/regress/parser/check_fill.c plugins/sudoers/regress/parser/check_fill.c
plugins/sudoers/regress/parser/check_gentime.c
plugins/sudoers/regress/parser/check_hexchar.c plugins/sudoers/regress/parser/check_hexchar.c
plugins/sudoers/regress/sudoers/test1.in plugins/sudoers/regress/sudoers/test1.in
plugins/sudoers/regress/sudoers/test1.json.ok plugins/sudoers/regress/sudoers/test1.json.ok
@ -415,6 +418,10 @@ plugins/sudoers/regress/sudoers/test18.in
plugins/sudoers/regress/sudoers/test18.json.ok plugins/sudoers/regress/sudoers/test18.json.ok
plugins/sudoers/regress/sudoers/test18.out.ok plugins/sudoers/regress/sudoers/test18.out.ok
plugins/sudoers/regress/sudoers/test18.toke.ok plugins/sudoers/regress/sudoers/test18.toke.ok
plugins/sudoers/regress/sudoers/test19.in
plugins/sudoers/regress/sudoers/test19.json.ok
plugins/sudoers/regress/sudoers/test19.out.ok
plugins/sudoers/regress/sudoers/test19.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
@ -465,6 +472,8 @@ plugins/sudoers/regress/testsudoers/test7.out.ok
plugins/sudoers/regress/testsudoers/test7.sh plugins/sudoers/regress/testsudoers/test7.sh
plugins/sudoers/regress/visudo/test1.out.ok plugins/sudoers/regress/visudo/test1.out.ok
plugins/sudoers/regress/visudo/test1.sh plugins/sudoers/regress/visudo/test1.sh
plugins/sudoers/regress/visudo/test10.out.ok
plugins/sudoers/regress/visudo/test10.sh
plugins/sudoers/regress/visudo/test2.err.ok plugins/sudoers/regress/visudo/test2.err.ok
plugins/sudoers/regress/visudo/test2.out.ok plugins/sudoers/regress/visudo/test2.out.ok
plugins/sudoers/regress/visudo/test2.sh plugins/sudoers/regress/visudo/test2.sh

View File

@ -711,6 +711,9 @@
/* Define if your struct sockaddr has an sa_len field. */ /* Define if your struct sockaddr has an sa_len field. */
#undef HAVE_STRUCT_SOCKADDR_SA_LEN #undef HAVE_STRUCT_SOCKADDR_SA_LEN
/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
#undef HAVE_STRUCT_TM_TM_GMTOFF
/* Define to 1 if `ut_exit' is a member of `struct utmpx'. */ /* Define to 1 if `ut_exit' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_EXIT #undef HAVE_STRUCT_UTMPX_UT_EXIT
@ -1050,6 +1053,9 @@
/* The size of `long long', as computed by sizeof. */ /* The size of `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG #undef SIZEOF_LONG_LONG
/* The size of `time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
/* Define to 1 to compile the sudoers plugin statically into the sudo binary. /* Define to 1 to compile the sudoers plugin statically into the sudo binary.
*/ */
#undef STATIC_SUDOERS_PLUGIN #undef STATIC_SUDOERS_PLUGIN

47
configure vendored
View File

@ -18262,6 +18262,39 @@ cat >>confdefs.h <<_ACEOF
_ACEOF _ACEOF
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5
$as_echo_n "checking size of time_t... " >&6; }
if ${ac_cv_sizeof_time_t+:} false; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"; then :
else
if test "$ac_cv_type_time_t" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (time_t)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_time_t=0
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5
$as_echo "$ac_cv_sizeof_time_t" >&6; }
cat >>confdefs.h <<_ACEOF
#define SIZEOF_TIME_T $ac_cv_sizeof_time_t
_ACEOF
if test $ac_cv_header_utmpx_h = "yes"; then if test $ac_cv_header_utmpx_h = "yes"; then
ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_id" "ac_cv_member_struct_utmpx_ut_id" " ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_id" "ac_cv_member_struct_utmpx_ut_id" "
# include <sys/types.h> # include <sys/types.h>
@ -20356,6 +20389,20 @@ esac
" "
done done
ac_fn_c_check_member "$LINENO" "struct tm" "tm_gmtoff" "ac_cv_member_struct_tm_tm_gmtoff" "
$ac_includes_default
#include <errno.h>
"
if test "x$ac_cv_member_struct_tm_tm_gmtoff" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_TM_TM_GMTOFF 1
_ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default" ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then : if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then :
$as_echo "#define HAVE_ST_MTIM 1" >>confdefs.h $as_echo "#define HAVE_ST_MTIM 1" >>confdefs.h

View File

@ -2348,6 +2348,7 @@ SUDO_SOCK_SA_LEN
SUDO_SOCK_SIN_LEN SUDO_SOCK_SIN_LEN
AC_CHECK_SIZEOF([id_t]) AC_CHECK_SIZEOF([id_t])
AC_CHECK_SIZEOF([long long]) AC_CHECK_SIZEOF([long long])
AC_CHECK_SIZEOF([time_t])
dnl dnl
dnl Check for utmp/utmpx struct members. dnl Check for utmp/utmpx struct members.
dnl We need to have already defined _GNU_SOURCE on glibc which only has dnl We need to have already defined _GNU_SOURCE on glibc which only has
@ -2665,6 +2666,10 @@ fi
AC_CHECK_FUNCS([strtonum]) AC_CHECK_FUNCS([strtonum])
AC_LIBOBJ(strtonum) AC_LIBOBJ(strtonum)
SUDO_APPEND_COMPAT_EXP(sudo_strtonum) SUDO_APPEND_COMPAT_EXP(sudo_strtonum)
AC_CHECK_MEMBERS([struct tm.tm_gmtoff], [], [], [
AC_INCLUDES_DEFAULT
#include <errno.h>
])
AC_CHECK_MEMBER([struct stat.st_mtim], [AC_DEFINE(HAVE_ST_MTIM)] AC_CHECK_MEMBER([struct stat.st_mtim], [AC_DEFINE(HAVE_ST_MTIM)]
[AC_CHECK_MEMBER([struct stat.st_mtim.st__tim], AC_DEFINE(HAVE_ST__TIM))], [AC_CHECK_MEMBER([struct stat.st_mtim.st__tim], AC_DEFINE(HAVE_ST__TIM))],
[AC_CHECK_MEMBER([struct stat.st_mtimespec], AC_DEFINE([HAVE_ST_MTIMESPEC]))]) [AC_CHECK_MEMBER([struct stat.st_mtimespec], AC_DEFINE([HAVE_ST_MTIMESPEC]))])

View File

@ -478,12 +478,14 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Timeout_Spec) Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_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')
Date_Spec ::= ('NOTBEFORE=timestamp' | 'NOTAFTER=timestamp')
Timeout_Spec ::= 'TIMEOUT=timeout' Timeout_Spec ::= 'TIMEOUT=timeout'
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' | Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
@ -608,6 +610,24 @@ 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.
DDaattee__SSppeecc
ssuuddooeerrss rules can be specified with a start and end date via the
NOTBEFORE and NOTAFTER settings. The time stamp must be specified in
_G_e_n_e_r_a_l_i_z_e_d _T_i_m_e as defined by RFC 4517. The format is effectively
yyyymmddHHMMSSZ where the minutes and seconds are optional. The `Z'
suffix indicates that the time stamp is in Coordinated Universal Time
(UTC). It is also possible to specify a timezone offset from UTC in
hours and minutes instead of a `Z'. For example, `-0500' would
correspond to Eastern Standard time in the US. As an extension, if no
`Z' or timezone offset is specified, local time will be used.
The following are all valid time stamps:
20170214083000Z
2017021408Z
20160315220000-0500
20151201235900
TTiimmeeoouutt__SSppeecc TTiimmeeoouutt__SSppeecc
A command may have a timeout associated with it. If the timeout expires A command may have a timeout associated with it. If the timeout expires
before the command has exited, the command will be terminated. The before the command has exited, the command will be terminated. The

View File

@ -986,12 +986,14 @@ Cmnd_Spec ::= Runas_Spec? Option_Spec* Tag_Spec* Cmnd
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Timeout_Spec) Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_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')
Date_Spec ::= ('NOTBEFORE=timestamp' | 'NOTAFTER=timestamp')
Timeout_Spec ::= 'TIMEOUT=timeout' Timeout_Spec ::= 'TIMEOUT=timeout'
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' | Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
@ -1257,6 +1259,42 @@ name with either an
or or
\(oq\-\(cq \(oq\-\(cq
character. character.
.SS "Date_Spec"
\fBsudoers\fR
rules can be specified with a start and end date via the
\fRNOTBEFORE\fR
and
\fRNOTAFTER\fR
settings.
The time stamp must be specified in
\fIGeneralized Time\fR
as defined by RFC 4517.
The format is effectively
\fRyyyymmddHHMMSSZ\fR
where the minutes and seconds are optional.
The
\(oqZ\(cq
suffix indicates that the time stamp is in Coordinated Universal Time (UTC).
It is also possible to specify a timezone offset from UTC in hours
and minutes instead of a
\(oqZ\(cq.
For example,
\(oq-0500\(cq
would correspond to Eastern Standard time in the US.
As an extension, if no
\(oqZ\(cq
or timezone offset is specified, local time will be used.
.PP
The following are all valid time stamps:
.nf
.sp
.RS 4n
20170214083000Z
2017021408Z
20160315220000-0500
20151201235900
.RE
.fi
.SS "Timeout_Spec" .SS "Timeout_Spec"
A command may have a timeout associated with it. A command may have a timeout associated with it.
If the timeout expires before the command has exited, the If the timeout expires before the command has exited, the

View File

@ -939,12 +939,14 @@ Cmnd_Spec ::= Runas_Spec? Option_Spec* Tag_Spec* Cmnd
Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Timeout_Spec) Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_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')
Date_Spec ::= ('NOTBEFORE=timestamp' | 'NOTAFTER=timestamp')
Timeout_Spec ::= 'TIMEOUT=timeout' Timeout_Spec ::= 'TIMEOUT=timeout'
Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' | Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
@ -1180,6 +1182,39 @@ name with either an
or or
.Ql \- .Ql \-
character. character.
.Ss Date_Spec
.Nm sudoers
rules can be specified with a start and end date via the
.Li NOTBEFORE
and
.Li NOTAFTER
settings.
The time stamp must be specified in
.Em Generalized Time
as defined by RFC 4517.
The format is effectively
.Li yyyymmddHHMMSSZ
where the minutes and seconds are optional.
The
.Ql Z
suffix indicates that the time stamp is in Coordinated Universal Time (UTC).
It is also possible to specify a timezone offset from UTC in hours
and minutes instead of a
.Ql Z .
For example,
.Ql -0500
would correspond to Eastern Standard time in the US.
As an extension, if no
.Ql Z
or timezone offset is specified, local time will be used.
.Pp
The following are all valid time stamps:
.Bd -literal -offset 4n
20170214083000Z
2017021408Z
20160315220000-0500
20151201235900
.Ed
.Ss Timeout_Spec .Ss Timeout_Spec
A command may have a timeout associated with it. A command may have a timeout associated with it.
If the timeout expires before the command has exited, the If the timeout expires before the command has exited, the

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011-2016 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2011-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
@ -156,6 +156,14 @@ struct sudo_conf_debug_file_list;
return sudo_debug_ret; \ return sudo_debug_ret; \
} while (0) } while (0)
#define debug_return_time_t(ret) \
do { \
time_t sudo_debug_ret = (ret); \
sudo_debug_exit_time_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\
sudo_debug_ret); \
return sudo_debug_ret; \
} while (0)
#define debug_return_long(ret) \ #define debug_return_long(ret) \
do { \ do { \
long sudo_debug_ret = (ret); \ long sudo_debug_ret = (ret); \
@ -247,6 +255,7 @@ __dso_public void sudo_debug_exit_size_t_v1(const char *func, const char *file,
__dso_public void sudo_debug_exit_ssize_t_v1(const char *func, const char *file, int line, int subsys, ssize_t ret); __dso_public void sudo_debug_exit_ssize_t_v1(const char *func, const char *file, int line, int subsys, ssize_t ret);
__dso_public void sudo_debug_exit_str_v1(const char *func, const char *file, int line, int subsys, const char *ret); __dso_public void sudo_debug_exit_str_v1(const char *func, const char *file, int line, int subsys, const char *ret);
__dso_public void sudo_debug_exit_str_masked_v1(const char *func, const char *file, int line, int subsys, const char *ret); __dso_public void sudo_debug_exit_str_masked_v1(const char *func, const char *file, int line, int subsys, const char *ret);
__dso_public void sudo_debug_exit_time_t_v1(const char *func, const char *file, int line, int subsys, time_t ret);
__dso_public pid_t sudo_debug_fork_v1(void); __dso_public pid_t sudo_debug_fork_v1(void);
__dso_public int sudo_debug_get_active_instance_v1(void); __dso_public int sudo_debug_get_active_instance_v1(void);
__dso_public int sudo_debug_get_fds_v1(unsigned char **fds); __dso_public int sudo_debug_get_fds_v1(unsigned char **fds);
@ -272,6 +281,7 @@ __dso_public void sudo_debug_write2_v1(int fd, const char *func, const char *fil
#define sudo_debug_exit_ssize_t(_a, _b, _c, _d, _e) sudo_debug_exit_ssize_t_v1((_a), (_b), (_c), (_d), (_e)) #define sudo_debug_exit_ssize_t(_a, _b, _c, _d, _e) sudo_debug_exit_ssize_t_v1((_a), (_b), (_c), (_d), (_e))
#define sudo_debug_exit_str(_a, _b, _c, _d, _e) sudo_debug_exit_str_v1((_a), (_b), (_c), (_d), (_e)) #define sudo_debug_exit_str(_a, _b, _c, _d, _e) sudo_debug_exit_str_v1((_a), (_b), (_c), (_d), (_e))
#define sudo_debug_exit_str_masked(_a, _b, _c, _d, _e) sudo_debug_exit_str_masked_v1((_a), (_b), (_c), (_d), (_e)) #define sudo_debug_exit_str_masked(_a, _b, _c, _d, _e) sudo_debug_exit_str_masked_v1((_a), (_b), (_c), (_d), (_e))
#define sudo_debug_exit_time_t(_a, _b, _c, _d, _e) sudo_debug_exit_time_t_v1((_a), (_b), (_c), (_d), (_e))
#define sudo_debug_fork() sudo_debug_fork_v1() #define sudo_debug_fork() sudo_debug_fork_v1()
#define sudo_debug_get_active_instance() sudo_debug_get_active_instance_v1() #define sudo_debug_get_active_instance() sudo_debug_get_active_instance_v1()
#define sudo_debug_get_fds(_a) sudo_debug_get_fds_v1((_a)) #define sudo_debug_get_fds(_a) sudo_debug_get_fds_v1((_a))

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011-2016 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2011-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
@ -481,6 +481,19 @@ sudo_debug_exit_ssize_t_v1(const char *func, const char *file, int line,
"<- %s @ %s:%d := %zd", func, file, line, ret); "<- %s @ %s:%d := %zd", func, file, line, ret);
} }
void
sudo_debug_exit_time_t_v1(const char *func, const char *file, int line,
int subsys, time_t ret)
{
#if SIZEOF_TIME_T == 8
sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
"<- %s @ %s:%d := %lld", func, file, line, (long long)ret);
#else
sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
"<- %s @ %s:%d := %d", func, file, line, (int)ret);
#endif
}
void void
sudo_debug_exit_bool_v1(const char *func, const char *file, int line, sudo_debug_exit_bool_v1(const char *func, const char *file, int line,
int subsys, bool ret) int subsys, bool ret)

View File

@ -25,6 +25,7 @@ sudo_debug_exit_size_t_v1
sudo_debug_exit_ssize_t_v1 sudo_debug_exit_ssize_t_v1
sudo_debug_exit_str_v1 sudo_debug_exit_str_v1
sudo_debug_exit_str_masked_v1 sudo_debug_exit_str_masked_v1
sudo_debug_exit_time_t_v1
sudo_debug_fork_v1 sudo_debug_fork_v1
sudo_debug_get_active_instance_v1 sudo_debug_get_active_instance_v1
sudo_debug_get_fds_v1 sudo_debug_get_fds_v1

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 1996, 1998-2005, 2007-2015 # Copyright (c) 1996, 1998-2005, 2007-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
@ -146,14 +146,15 @@ SHELL = @SHELL@
PROGS = sudoers.la visudo sudoreplay testsudoers PROGS = sudoers.la visudo sudoreplay testsudoers
TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_digest \ TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_digest \
check_base64 check_hexchar @SUDOERS_TEST_PROGS@ check_base64 check_gentime check_hexchar @SUDOERS_TEST_PROGS@
AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@ 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 gentime.lo \
gram.lo match.lo match_addr.lo pwutil.lo pwutil_impl.lo \ hexchar.lo gmtoff.lo gram.lo match.lo match_addr.lo \
rcstr.lo redblack.lo sudoers_debug.lo timeout.lo \ pwutil.lo pwutil_impl.lo rcstr.lo redblack.lo \
timestr.lo toke.lo toke_util.lo sudoers_debug.lo timeout.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 \
@ -178,6 +179,8 @@ CHECK_DIGEST_OBJS = check_digest.o
CHECK_FILL_OBJS = check_fill.o hexchar.o toke_util.o sudoers_debug.o CHECK_FILL_OBJS = check_fill.o hexchar.o toke_util.o sudoers_debug.o
CHECK_GENTIME_OBJS = check_gentime.o gentime.o gmtoff.o sudoers_debug.o
CHECK_HEXCHAR_OBJS = check_hexchar.o hexchar.o sudoers_debug.o CHECK_HEXCHAR_OBJS = check_hexchar.o hexchar.o sudoers_debug.o
CHECK_IOLOG_PATH_OBJS = check_iolog_path.o iolog_path.o locale.o \ CHECK_IOLOG_PATH_OBJS = check_iolog_path.o iolog_path.o locale.o \
@ -248,6 +251,9 @@ check_digest: $(CHECK_DIGEST_OBJS) $(LT_LIBS)
check_fill: $(CHECK_FILL_OBJS) $(LT_LIBS) check_fill: $(CHECK_FILL_OBJS) $(LT_LIBS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_FILL_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_FILL_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
check_gentime: $(CHECK_GENTIME_OBJS) $(LT_LIBS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_GENTIME_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
check_hexchar: $(CHECK_HEXCHAR_OBJS) $(LT_LIBS) check_hexchar: $(CHECK_HEXCHAR_OBJS) $(LT_LIBS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_HEXCHAR_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_HEXCHAR_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
@ -374,6 +380,7 @@ check: $(TEST_PROGS) visudo testsudoers
./check_digest > regress/parser/check_digest.out; \ ./check_digest > regress/parser/check_digest.out; \
diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \ diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \
./check_fill || rval=`expr $$rval + $$?`; \ ./check_fill || rval=`expr $$rval + $$?`; \
./check_gentime || rval=`expr $$rval + $$?`; \
./check_hexchar || rval=`expr $$rval + $$?`; \ ./check_hexchar || rval=`expr $$rval + $$?`; \
./check_iolog_path $(srcdir)/regress/iolog_path/data || rval=`expr $$rval + $$?`; \ ./check_iolog_path $(srcdir)/regress/iolog_path/data || rval=`expr $$rval + $$?`; \
case "$(TEST_PROGS)" in \ case "$(TEST_PROGS)" in \
@ -601,6 +608,12 @@ check_fill.o: $(srcdir)/regress/parser/check_fill.c $(devdir)/gram.h \
$(incdir)/sudo_util.h $(srcdir)/parse.h $(srcdir)/toke.h \ $(incdir)/sudo_util.h $(srcdir)/parse.h $(srcdir)/toke.h \
$(top_builddir)/config.h $(top_builddir)/config.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_fill.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_fill.c
check_gentime.o: $(srcdir)/regress/parser/check_gentime.c \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_queue.h \
$(srcdir)/parse.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/config.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_gentime.c
check_hexchar.o: $(srcdir)/regress/parser/check_hexchar.c \ check_hexchar.o: $(srcdir)/regress/parser/check_hexchar.c \
$(incdir)/sudo_compat.h $(top_builddir)/config.h $(incdir)/sudo_compat.h $(top_builddir)/config.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_hexchar.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_hexchar.c
@ -688,6 +701,12 @@ gc.lo: $(srcdir)/gc.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/gc.c $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/gc.c
gentime.lo: $(srcdir)/gentime.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_queue.h $(srcdir)/parse.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/config.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/gentime.c
gentime.o: gentime.lo
getdate.o: $(devdir)/getdate.c $(incdir)/sudo_compat.h $(top_builddir)/config.h getdate.o: $(devdir)/getdate.c $(incdir)/sudo_compat.h $(top_builddir)/config.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(devdir)/getdate.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(devdir)/getdate.c
getspwuid.lo: $(srcdir)/getspwuid.c $(devdir)/def_data.h \ getspwuid.lo: $(srcdir)/getspwuid.c $(devdir)/def_data.h \
@ -700,6 +719,12 @@ getspwuid.lo: $(srcdir)/getspwuid.c $(devdir)/def_data.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/getspwuid.c $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/getspwuid.c
gmtoff.lo: $(srcdir)/gmtoff.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_queue.h $(srcdir)/parse.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/config.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/gmtoff.c
gmtoff.o: gmtoff.lo
goodpath.lo: $(srcdir)/goodpath.c $(devdir)/def_data.h \ goodpath.lo: $(srcdir)/goodpath.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 \
@ -892,8 +917,8 @@ policy.lo: $(srcdir)/policy.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \
$(srcdir)/interfaces.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ $(srcdir)/interfaces.h $(srcdir)/logging.h $(srcdir)/parse.h \
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
$(srcdir)/sudoers_version.h $(top_builddir)/config.h \ $(srcdir)/sudoers_version.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/policy.c $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/policy.c

158
plugins/sudoers/gentime.c Normal file
View File

@ -0,0 +1,158 @@
/*
* 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>
#ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#else
# include "compat/stdbool.h"
#endif /* HAVE_STDBOOL_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 <time.h>
#include "sudo_compat.h"
#include "sudoers_debug.h"
#include "parse.h"
/*
* Parse a timestamp in Generalized Time format as per RFC4517.
* E.g. yyyymmddHHMMSS.FZ or yyyymmddHHMMSS.F[+-]TZOFF
* where minutes, seconds and fraction are optional.
* Returns the time in Unix time format or -1 on error.
*/
time_t
parse_gentime(const char *timestr)
{
char tcopy[sizeof("yyyymmddHHMMSS.F")];
const char *cp;
time_t result;
struct tm tm;
size_t len;
int items, tzoff = 0;
bool islocal = false;
debug_decl(parse_gentime, SUDOERS_DEBUG_PARSER)
/* Make a copy of the time without time zone for easy parsing. */
len = strspn(timestr, "0123456789.,");
if (len >= sizeof(tcopy)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to parse general time string %s", timestr);
debug_return_time_t(-1);
}
memcpy(tcopy, timestr, len);
tcopy[len] = '\0';
/* Parse general time, ignoring the timezone for now. */
memset(&tm, 0, sizeof(tm));
items = sscanf(tcopy, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon,
&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
if (items == EOF || items < 4) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"only parsed %d items in general time string %s", items, timestr);
debug_return_time_t(-1);
}
cp = timestr + ((items + 1) * 2);
/* Parse optional fractional hours/minute/second if present. */
if ((cp[0] == '.' || cp[0] == ',') && isdigit((unsigned char)cp[1])) {
int frac = cp[1] - '0';
switch (items) {
case 4:
/* convert fractional hour -> minutes */
tm.tm_min += 60 / 10 * frac;
break;
case 5:
/* convert fractional minute -> seconds */
tm.tm_sec += 60 / 10 * frac;
break;
case 6:
/* ignore fractional second */
break;
}
cp += 2; /* skip over radix and fraction */
}
switch (*cp) {
case '-':
case '+': {
int hour = 0, min = 0;
/* No DST */
tm.tm_isdst = 0;
/* parse time zone offset */
items = sscanf(cp + 1, "%2d%2d", &hour, &min);
if (items == EOF || items < 1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to parse time zone offset in %s, items %d",
timestr, items);
debug_return_time_t(-1);
}
if (*cp == '-')
tzoff = -((hour * 60) + min) * 60;
else
tzoff = ((hour * 60) + min) * 60;
cp += 1 + (items * 2);
break;
}
case 'Z':
/* GMT/UTC, no DST */
tm.tm_isdst = 0;
cp++;
break;
case '\0':
/* no zone specified, use local time */
tm.tm_isdst = -1;
islocal = true;
break;
default:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to parse general time string %s", timestr);
debug_return_time_t(-1);
}
if (*cp != '\0') {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"trailing garbage in general time string %s", timestr);
debug_return_time_t(-1);
}
/* Adjust from Generalized Time to struct tm */
tm.tm_year -= 1900;
tm.tm_mon--;
result = mktime(&tm);
if (result != -1) {
if (!islocal) {
/* Not local time, convert to GMT */
result += get_gmtoff(&result);
/* Adjust time based on supplied GMT offset. */
result -= tzoff;
}
}
debug_return_time_t(result);
}

67
plugins/sudoers/gmtoff.c Normal file
View File

@ -0,0 +1,67 @@
/*
* 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.
*/
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "sudo_compat.h"
#include "sudoers_debug.h"
#include "parse.h"
/*
* Returns the offset from GMT in seconds (algorithm taken from sendmail).
* Warning: clobbers the static storage used by localtime() and gmtime().
*/
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
long
get_gmtoff(time_t *clock)
{
struct tm *local;
local = localtime(clock);
return local->tm_gmtoff;
}
#else
long
get_gmtoff(time_t *clock)
{
struct tm gmt, *local;
long offset;
gmt = *gmtime(clock);
local = localtime(clock);
offset = (local->tm_sec - gmt.tm_sec) +
((local->tm_min - gmt.tm_min) * 60) +
((local->tm_hour - gmt.tm_hour) * 3600);
/* Timezone may cause year rollover to happen on a different day. */
if (local->tm_year < gmt.tm_year)
offset -= 24 * 3600;
else if (local->tm_year > gmt.tm_year)
offset -= 24 * 3600;
else if (local->tm_yday < gmt.tm_yday)
offset -= 24 * 3600;
else if (local->tm_yday > gmt.tm_yday)
offset += 24 * 3600;
return offset;
}
#endif /* HAVE_TM_GMTOFF */

File diff suppressed because it is too large Load Diff

View File

@ -37,11 +37,13 @@
#define PRIVS 293 #define PRIVS 293
#define LIMITPRIVS 294 #define LIMITPRIVS 294
#define CMND_TIMEOUT 295 #define CMND_TIMEOUT 295
#define MYSELF 296 #define NOTBEFORE 296
#define SHA224_TOK 297 #define NOTAFTER 297
#define SHA256_TOK 298 #define MYSELF 298
#define SHA384_TOK 299 #define SHA224_TOK 299
#define SHA512_TOK 300 #define SHA256_TOK 300
#define SHA384_TOK 301
#define SHA512_TOK 302
#ifndef YYSTYPE_DEFINED #ifndef YYSTYPE_DEFINED
#define YYSTYPE_DEFINED #define YYSTYPE_DEFINED
typedef union { typedef union {

View File

@ -130,6 +130,8 @@ static struct sudo_digest *new_digest(int, char *);
%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> CMND_TIMEOUT /* command timeout */
%token <tok> NOTBEFORE /* time restriction */
%token <tok> NOTAFTER /* time restriction */
%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 */
@ -164,6 +166,8 @@ static struct sudo_digest *new_digest(int, char *);
%type <string> privsspec %type <string> privsspec
%type <string> limitprivsspec %type <string> limitprivsspec
%type <string> timeoutspec %type <string> timeoutspec
%type <string> notbeforespec
%type <string> notafterspec
%type <digest> digest %type <digest> digest
%type <options> options %type <options> options
@ -353,6 +357,11 @@ cmndspeclist : cmndspec
$3->limitprivs = prev->limitprivs; $3->limitprivs = prev->limitprivs;
} }
#endif /* HAVE_PRIV_SET */ #endif /* HAVE_PRIV_SET */
/* propagate command time restrictions */
if ($3->notbefore == UNSPEC)
$3->notbefore = prev->notbefore;
if ($3->notafter == UNSPEC)
$3->notafter = prev->notafter;
/* propagate command timeout */ /* propagate command timeout */
if ($3->timeout == UNSPEC) if ($3->timeout == UNSPEC)
$3->timeout = prev->timeout; $3->timeout = prev->timeout;
@ -420,6 +429,8 @@ cmndspec : runasspec options cmndtag digcmnd {
cs->privs = $2.privs; cs->privs = $2.privs;
cs->limitprivs = $2.limitprivs; cs->limitprivs = $2.limitprivs;
#endif #endif
cs->notbefore = $2.notbefore;
cs->notafter = $2.notafter;
cs->timeout = $2.timeout; cs->timeout = $2.timeout;
cs->tags = $3; cs->tags = $3;
cs->cmnd = $4; cs->cmnd = $4;
@ -491,6 +502,15 @@ timeoutspec : CMND_TIMEOUT '=' WORD {
} }
; ;
notbeforespec : NOTBEFORE '=' WORD {
$$ = $3;
}
notafterspec : NOTAFTER '=' WORD {
$$ = $3;
}
;
rolespec : ROLE '=' WORD { rolespec : ROLE '=' WORD {
$$ = $3; $$ = $3;
} }
@ -580,6 +600,22 @@ runaslist : /* empty */ {
options : /* empty */ { options : /* empty */ {
init_options(&$$); init_options(&$$);
} }
| options notbeforespec {
$$.notbefore = parse_gentime($2);
free($2);
if ($$.notbefore == -1) {
sudoerserror(N_("invalid notbefore value"));
YYERROR;
}
}
| options notafterspec {
$$.notafter = parse_gentime($2);
free($2);
if ($$.notafter == -1) {
sudoerserror(N_("invalid notafter value"));
YYERROR;
}
}
| options timeoutspec { | options timeoutspec {
$$.timeout = parse_timeout($2); $$.timeout = parse_timeout($2);
free($2); free($2);
@ -1185,6 +1221,8 @@ init_parser(const char *path, bool quiet)
static void static void
init_options(struct command_options *opts) init_options(struct command_options *opts)
{ {
opts->notbefore = UNSPEC;
opts->notafter = UNSPEC;
opts->timeout = UNSPEC; opts->timeout = UNSPEC;
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
opts->role = NULL; opts->role = NULL;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004-2005, 2007-2016 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2004-2005, 2007-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
@ -29,8 +29,9 @@
#endif /* HAVE_STRINGS_H */ #endif /* HAVE_STRINGS_H */
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <ctype.h>
#include <pwd.h>
#include <grp.h> #include <grp.h>
#include <pwd.h>
#include <time.h>
#include "sudoers.h" #include "sudoers.h"
#include "parse.h" #include "parse.h"
@ -151,6 +152,7 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
struct privilege *priv; struct privilege *priv;
struct userspec *us; struct userspec *us;
struct member *matching_user; struct member *matching_user;
time_t now;
debug_decl(sudo_file_lookup, SUDOERS_DEBUG_NSS) debug_decl(sudo_file_lookup, SUDOERS_DEBUG_NSS)
if (nss->handle == NULL) if (nss->handle == NULL)
@ -207,6 +209,7 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
if (!set_perms(PERM_RUNAS)) if (!set_perms(PERM_RUNAS))
debug_return_int(validated); debug_return_int(validated);
time(&now);
match = UNSPEC; match = UNSPEC;
TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) { TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
@ -219,6 +222,14 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
else else
continue; continue;
TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) { TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
if (cs->notbefore != UNSPEC) {
if (now < cs->notbefore)
continue;
}
if (cs->notafter != UNSPEC) {
if (now > cs->notafter)
continue;
}
matching_user = NULL; matching_user = NULL;
runas_match = runaslist_matches(cs->runasuserlist, runas_match = runaslist_matches(cs->runasuserlist,
cs->runasgrouplist, &matching_user, NULL); cs->runasgrouplist, &matching_user, NULL);
@ -378,6 +389,22 @@ sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
snprintf(numbuf, sizeof(numbuf), "%d", cs->timeout); snprintf(numbuf, sizeof(numbuf), "%d", cs->timeout);
sudo_lbuf_append(lbuf, "TIMEOUT=%s ", numbuf); sudo_lbuf_append(lbuf, "TIMEOUT=%s ", numbuf);
} }
if (cs->notbefore != UNSPEC) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
struct tm *tm = gmtime(&cs->notbefore);
snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
sudo_lbuf_append(lbuf, "NOTBEFORE=%s ", buf);
}
if (cs->notafter != UNSPEC) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
struct tm *tm = gmtime(&cs->notafter);
snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
sudo_lbuf_append(lbuf, "NOTAFTER=%s ", buf);
}
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: ");
@ -568,6 +595,22 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
snprintf(numbuf, sizeof(numbuf), "%d", cs->timeout); snprintf(numbuf, sizeof(numbuf), "%d", cs->timeout);
sudo_lbuf_append(lbuf, " Timeout: %s\n", numbuf); sudo_lbuf_append(lbuf, " Timeout: %s\n", numbuf);
} }
if (cs->notbefore != UNSPEC) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
struct tm *tm = gmtime(&cs->notbefore);
snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
sudo_lbuf_append(lbuf, " NotBefore: %s\n", buf);
}
if (cs->notafter != UNSPEC) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
struct tm *tm = gmtime(&cs->notafter);
snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
sudo_lbuf_append(lbuf, " NotAfter: %s\n", buf);
}
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,6 +113,8 @@ struct cmndtag {
* Per-command option container struct. * Per-command option container struct.
*/ */
struct command_options { struct command_options {
time_t notbefore; /* time restriction */
time_t notafter; /* time restriction */
int timeout; /* command timeout */ int timeout; /* command timeout */
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
char *role, *type; /* SELinux role and type */ char *role, *type; /* SELinux role and type */
@ -176,6 +178,8 @@ 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 */
time_t notbefore; /* time restriction */
time_t notafter; /* time restriction */
int timeout; /* command timeout */ int timeout; /* command timeout */
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
char *role, *type; /* SELinux role and type */ char *role, *type; /* SELinux role and type */
@ -280,4 +284,10 @@ size_t base64_decode(const char *str, unsigned char *dst, size_t dsize);
/* timeout.c */ /* timeout.c */
int parse_timeout(const char *timestr); int parse_timeout(const char *timestr);
/* gmtoff.c */
long get_gmtoff(time_t *clock);
/* gentime.c */
time_t parse_gentime(const char *expstr);
#endif /* SUDOERS_PARSE_H */ #endif /* SUDOERS_PARSE_H */

View File

@ -0,0 +1,84 @@
/*
* 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.
*/
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include <time.h>
#define SUDO_ERROR_WRAP 0
#include "sudo_compat.h"
#include "sudoers_debug.h"
#include "parse.h"
__dso_public int main(int argc, char *argv[]);
struct gentime_test {
char *gentime;
time_t unixtime;
} tests[] = {
{ "199412161032ZZ", -1 },
{ "199412161032Z", 787573920 },
{ "199412160532-0500", 787573920 },
{ "199412160532-05000", -1 },
{ "199412160532", 787573920 }, /* local time is EST */
{ "20170214083000-0500", 1487079000 },
{ "201702140830-0500", 1487079000 },
{ "201702140830", 1487079000 }, /* local time is EST */
{ "201702140830.3-0500", 1487079018 },
{ "201702140830,3-0500", 1487079018 },
{ "20170214083000.5Z", 1487061000 },
{ "20170214083000,5Z", 1487061000 },
{ "201702142359.4Z", 1487116764 },
{ "201702142359,4Z", 1487116764 },
{ "2017021408.5Z", 1487061000 },
{ "2017021408,5Z", 1487061000 },
{ "20170214Z", -1 },
{ NULL, -1 }
};
int
main(int argc, char *argv[])
{
int ntests, errors = 0;
time_t result;
/* Do local time tests in Eastern Standard Time. */
putenv("TZ=EST5EST5");
tzset();
for (ntests = 0; tests[ntests].gentime != NULL; ntests++) {
result = parse_gentime(tests[ntests].gentime);
if (result != tests[ntests].unixtime) {
fprintf(stderr, "check_gentime[%d]: %s: expected %lld, got %lld\n",
ntests, tests[ntests].gentime,
(long long)tests[ntests].unixtime, (long long)result);
errors++;
}
}
printf("check_gentime: %d tests run, %d errors, %d%% success rate\n",
ntests, errors, (ntests - errors) * 100 / ntests);
exit(errors);
}

View File

@ -0,0 +1,12 @@
# Test parsing of NOTBEFORE and NOTAFTER syntax
# Local time zone parsing is checked in visudo/test10.sh
user0 ALL = NOTBEFORE=20170214083000Z NOTAFTER=20170301083000Z /usr/bin/id, /bin/ls
user1 ALL = NOTBEFORE=201702140830Z /usr/bin/id, NOTAFTER=20170301083000Z /bin/ls
user2 ALL = NOTBEFORE=201702140830.3Z /usr/bin/id
user3 ALL = NOTBEFORE=2017021408Z /usr/bin/id
user4 ALL = NOTBEFORE=2017021408.4Z /usr/bin/id
user5 ALL = NOTBEFORE=20170214083000.5Z /usr/bin/id
user6 ALL = NOTBEFORE=20170214083000\,5Z /usr/bin/id
user7 ALL = NOTBEFORE=20170214033000-0500 /usr/bin/id
user8 ALL = NOTBEFORE=20170214033000.0-0500 /usr/bin/id
user9 ALL = NOTBEFORE=20170214033000\,0-0500 /usr/bin/id

View File

@ -0,0 +1,156 @@
{
"User_Specs": [
{
"User_List": [
{ "username": "user0" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" },
{ "command": "/bin/ls" }
]
}
]
},
{
"User_List": [
{ "username": "user1" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" },
{ "command": "/bin/ls" }
]
}
]
},
{
"User_List": [
{ "username": "user2" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user3" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user4" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user5" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user6" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user7" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user8" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
},
{
"User_List": [
{ "username": "user9" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Commands": [
{ "command": "/usr/bin/id" }
]
}
]
}
]
}

View File

@ -0,0 +1,14 @@
Parses OK.
user0 ALL = NOTBEFORE=20170214083000Z NOTAFTER=20170301083000Z /usr/bin/id, NOTBEFORE=20170214083000Z NOTAFTER=20170301083000Z /bin/ls
user1 ALL = NOTBEFORE=20170214083000Z /usr/bin/id, NOTBEFORE=20170214083000Z NOTAFTER=20170301083000Z /bin/ls
user2 ALL = NOTBEFORE=20170214083018Z /usr/bin/id
user3 ALL = NOTBEFORE=20170214080000Z /usr/bin/id
user4 ALL = NOTBEFORE=20170214082400Z /usr/bin/id
user5 ALL = NOTBEFORE=20170214083000Z /usr/bin/id
user6 ALL = NOTBEFORE=20170214083000Z /usr/bin/id
user7 ALL = NOTBEFORE=20170214083000Z /usr/bin/id
user8 ALL = NOTBEFORE=20170214083000Z /usr/bin/id
user9 ALL = NOTBEFORE=20170214083000Z /usr/bin/id

View File

@ -0,0 +1,12 @@
#
#
WORD(5) ALL = NOTBEFORE = WORD(5) NOTAFTER = WORD(5) COMMAND , COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND , NOTAFTER = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND
WORD(5) ALL = NOTBEFORE = WORD(5) COMMAND

View File

@ -0,0 +1 @@
stdin: parsed OK

View File

@ -0,0 +1,11 @@
#!/bin/sh
#
# Test parsing of NOTBEFORE/NOTAFTER using local time zone
#
./visudo -cf - <<-EOF
user1 ALL = NOTBEFORE=20151201235900 /usr/bin/id
user2 ALL = NOTBEFORE=20151201235900.2 /usr/bin/id
user3 ALL = NOTBEFORE=20151201235900\,2 /usr/bin/id
user4 ALL = NOTBEFORE=2015120123 /usr/bin/id
EOF

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2011-2013 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2011-2013, 2015, 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
@ -17,7 +18,6 @@
/* /*
* Major sudoers grammar changes are documented here. * Major sudoers grammar changes are documented here.
* Note that minor changes such as added Defaults options are not listed here. * Note that minor changes such as added Defaults options are not listed here.
* This file placed in the public domain by Todd C. Miller on Apr 5, 2011.
* *
* 1 sudo 1.1 * 1 sudo 1.1
* 2 sudo 1.3, adds support specifying a directory instead of a command. * 2 sudo 1.3, adds support specifying a directory instead of a command.
@ -64,11 +64,12 @@
* 43 sudo 1.8.7, Support for specifying a digest along with the command. * 43 sudo 1.8.7, Support for specifying a digest along with the command.
* 44 sudo 1.8.13, added MAIL/NOMAIL tags. * 44 sudo 1.8.13, added MAIL/NOMAIL tags.
* 45 sudo 1.8.15, added FOLLOW/NOFOLLOW tags as well as sudoedit_follow and sudoedit_checkdir Defaults. * 45 sudo 1.8.15, added FOLLOW/NOFOLLOW tags as well as sudoedit_follow and sudoedit_checkdir Defaults.
*/ * 46 sudo 1.8.20, added TIMEOUT, NOTBEFORE and NOTAFTER options.
*/
#ifndef SUDOERS_VERSION_H #ifndef SUDOERS_VERSION_H
#define SUDOERS_VERSION_H #define SUDOERS_VERSION_H
#define SUDOERS_GRAMMAR_VERSION 45 #define SUDOERS_GRAMMAR_VERSION 46
#endif /* SUDOERS_VERSION_H */ #endif /* SUDOERS_VERSION_H */

View File

@ -38,6 +38,7 @@
#ifdef HAVE_NETGROUP_H #ifdef HAVE_NETGROUP_H
# include <netgroup.h> # include <netgroup.h>
#endif /* HAVE_NETGROUP_H */ #endif /* HAVE_NETGROUP_H */
#include <time.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -636,6 +637,18 @@ print_privilege(struct privilege *priv)
#endif /* HAVE_PRIV_SET */ #endif /* HAVE_PRIV_SET */
if (cs->timeout > 0) if (cs->timeout > 0)
printf("TIMEOUT=%d ", cs->timeout); printf("TIMEOUT=%d ", cs->timeout);
if (cs->notbefore != UNSPEC) {
struct tm *tm = gmtime(&cs->notbefore);
printf("NOTBEFORE=%04d%02d%02d%02d%02d%02dZ ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
if (cs->notafter != UNSPEC) {
struct tm *tm = gmtime(&cs->notafter);
printf("NOTAFTER=%04d%02d%02d%02d%02d%02dZ ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
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))

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
%{ %{
/* /*
* Copyright (c) 1996, 1998-2005, 2007-2016 * Copyright (c) 1996, 1998-2005, 2007-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
@ -535,6 +535,16 @@ ALL {
LEXRETURN(CMND_TIMEOUT); LEXRETURN(CMND_TIMEOUT);
} }
<INITIAL>NOTBEFORE {
LEXTRACE("NOTBEFORE ");
LEXRETURN(NOTBEFORE);
}
<INITIAL>NOTAFTER {
LEXTRACE("NOTAFTER ");
LEXRETURN(NOTAFTER);
}
<INITIAL>ROLE { <INITIAL>ROLE {
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
LEXTRACE("ROLE "); LEXTRACE("ROLE ");