In the timestamp record, include the start time of the terminal
session leader for tty-based timestamps or the start time of the parent process for ppid-based timestamps. Idea from Duncan Overbruck.
This commit is contained in:
1
MANIFEST
1
MANIFEST
@@ -515,6 +515,7 @@ plugins/sudoers/set_perms.c
|
|||||||
plugins/sudoers/solaris_audit.c
|
plugins/sudoers/solaris_audit.c
|
||||||
plugins/sudoers/solaris_audit.h
|
plugins/sudoers/solaris_audit.h
|
||||||
plugins/sudoers/sssd.c
|
plugins/sudoers/sssd.c
|
||||||
|
plugins/sudoers/starttime.c
|
||||||
plugins/sudoers/sudo_nss.c
|
plugins/sudoers/sudo_nss.c
|
||||||
plugins/sudoers/sudo_nss.h
|
plugins/sudoers/sudo_nss.h
|
||||||
plugins/sudoers/sudo_printf.c
|
plugins/sudoers/sudo_printf.c
|
||||||
|
@@ -2772,19 +2772,21 @@ SSEECCUURRIITTYY NNOOTTEESS
|
|||||||
with a date greater than current_time + 2 * TIMEOUT will be ignored and
|
with a date greater than current_time + 2 * TIMEOUT will be ignored and
|
||||||
ssuuddooeerrss will log and complain.
|
ssuuddooeerrss will log and complain.
|
||||||
|
|
||||||
Since time stamp files live in the file system, they can outlive a user's
|
If the _t_i_m_e_s_t_a_m_p___t_y_p_e option is set to "tty", the time stamp record
|
||||||
login session. As a result, a user may be able to login, run a command
|
includes the device number of the terminal the user authenticated with.
|
||||||
with ssuuddoo after authenticating, logout, login again, and run ssuuddoo without
|
This provides per-terminal granularity but time stamp records may still
|
||||||
authenticating so long as the record's time stamp is within 5 minutes (or
|
outlive the user's session.
|
||||||
whatever value the timeout is set to in the _s_u_d_o_e_r_s file). When the
|
|
||||||
_t_t_y___t_i_c_k_e_t_s option is enabled, the time stamp record includes the device
|
Unless the _t_i_m_e_s_t_a_m_p___t_y_p_e option is set to "global", the time stamp
|
||||||
number of the terminal the user authenticated with. This provides per-
|
record also includes the session ID of the process that last
|
||||||
tty granularity but time stamp records still may outlive the user's
|
authenticated. This prevents processes in different terminal sessions
|
||||||
session. The time stamp record also includes the session ID of the
|
from using the same time stamp record. On systems where a process's
|
||||||
process that last authenticated. This prevents processes in different
|
start time can be queried, the start time of the session leader is
|
||||||
terminal sessions from using the same time stamp record. It also helps
|
recorded in the time stamp record. If no terminal is present or the
|
||||||
reduce the chance that a user will be able to run ssuuddoo without entering a
|
_t_i_m_e_s_t_a_m_p___t_y_p_e option is set to "ppid", the start time of the parent
|
||||||
password when logging out and back in again on the same terminal.
|
process is used instead. In most cases this will prevent a time stamp
|
||||||
|
record from being re-used without the user entering a password when
|
||||||
|
logging out and back in again.
|
||||||
|
|
||||||
DDEEBBUUGGGGIINNGG
|
DDEEBBUUGGGGIINNGG
|
||||||
Versions 1.8.4 and higher of the ssuuddooeerrss plugin support a flexible
|
Versions 1.8.4 and higher of the ssuuddooeerrss plugin support a flexible
|
||||||
@@ -2886,4 +2888,4 @@ DDIISSCCLLAAIIMMEERR
|
|||||||
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
||||||
complete details.
|
complete details.
|
||||||
|
|
||||||
Sudo 1.8.22 December 11, 2017 Sudo 1.8.22
|
Sudo 1.8.22 December 15, 2017 Sudo 1.8.22
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
|
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
.\"
|
.\"
|
||||||
.TH "SUDOERS" "5" "December 11, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
.TH "SUDOERS" "5" "December 15, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||||
.nh
|
.nh
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
@@ -5497,31 +5497,33 @@ will be ignored and
|
|||||||
\fBsudoers\fR
|
\fBsudoers\fR
|
||||||
will log and complain.
|
will log and complain.
|
||||||
.PP
|
.PP
|
||||||
Since time stamp files live in the file system, they can outlive a
|
If the
|
||||||
user's login session.
|
\fItimestamp_type\fR
|
||||||
As a result, a user may be able to login, run a command with
|
option is set to
|
||||||
\fBsudo\fR
|
\(Lqtty\(Rq,
|
||||||
after authenticating, logout, login again, and run
|
the time stamp record includes the device number of the terminal
|
||||||
\fBsudo\fR
|
the user authenticated with.
|
||||||
without authenticating so long as the record's time stamp is within
|
This provides per-terminal granularity but time stamp records may still
|
||||||
\fR@timeout@\fR
|
outlive the user's session.
|
||||||
minutes (or whatever value the timeout is set to in the
|
.PP
|
||||||
\fIsudoers\fR
|
Unless the
|
||||||
file).
|
\fItimestamp_type\fR
|
||||||
When the
|
option is set to
|
||||||
\fItty_tickets\fR
|
\(Lqglobal\(Rq,
|
||||||
option is enabled, the time stamp record includes the device
|
the time stamp record also includes the session ID of the process
|
||||||
number of the terminal the user authenticated with.
|
|
||||||
This provides per-tty granularity but time stamp records still
|
|
||||||
may outlive the user's session.
|
|
||||||
The time stamp record also includes the session ID of the process
|
|
||||||
that last authenticated.
|
that last authenticated.
|
||||||
This prevents processes in different terminal sessions from using
|
This prevents processes in different terminal sessions from using
|
||||||
the same time stamp record.
|
the same time stamp record.
|
||||||
It also helps reduce the chance that a user will be able to run
|
On systems where a process's start time can be queried,
|
||||||
\fBsudo\fR
|
the start time of the session leader
|
||||||
without entering a password when logging out and back in again
|
is recorded in the time stamp record.
|
||||||
on the same terminal.
|
If no terminal is present or the
|
||||||
|
\fItimestamp_type\fR
|
||||||
|
option is set to
|
||||||
|
\(Lqppid\(Rq,
|
||||||
|
the start time of the parent process is used instead.
|
||||||
|
In most cases this will prevent a time stamp record from being re-used
|
||||||
|
without the user entering a password when logging out and back in again.
|
||||||
.SH "DEBUGGING"
|
.SH "DEBUGGING"
|
||||||
Versions 1.8.4 and higher of the
|
Versions 1.8.4 and higher of the
|
||||||
\fBsudoers\fR
|
\fBsudoers\fR
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
|
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
.\"
|
.\"
|
||||||
.Dd December 11, 2017
|
.Dd December 15, 2017
|
||||||
.Dt SUDOERS @mansectform@
|
.Dt SUDOERS @mansectform@
|
||||||
.Os Sudo @PACKAGE_VERSION@
|
.Os Sudo @PACKAGE_VERSION@
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -5089,31 +5089,33 @@ will be ignored and
|
|||||||
.Nm sudoers
|
.Nm sudoers
|
||||||
will log and complain.
|
will log and complain.
|
||||||
.Pp
|
.Pp
|
||||||
Since time stamp files live in the file system, they can outlive a
|
If the
|
||||||
user's login session.
|
.Em timestamp_type
|
||||||
As a result, a user may be able to login, run a command with
|
option is set to
|
||||||
.Nm sudo
|
.Dq tty ,
|
||||||
after authenticating, logout, login again, and run
|
the time stamp record includes the device number of the terminal
|
||||||
.Nm sudo
|
the user authenticated with.
|
||||||
without authenticating so long as the record's time stamp is within
|
This provides per-terminal granularity but time stamp records may still
|
||||||
.Li @timeout@
|
outlive the user's session.
|
||||||
minutes (or whatever value the timeout is set to in the
|
.Pp
|
||||||
.Em sudoers
|
Unless the
|
||||||
file).
|
.Em timestamp_type
|
||||||
When the
|
option is set to
|
||||||
.Em tty_tickets
|
.Dq global ,
|
||||||
option is enabled, the time stamp record includes the device
|
the time stamp record also includes the session ID of the process
|
||||||
number of the terminal the user authenticated with.
|
|
||||||
This provides per-tty granularity but time stamp records still
|
|
||||||
may outlive the user's session.
|
|
||||||
The time stamp record also includes the session ID of the process
|
|
||||||
that last authenticated.
|
that last authenticated.
|
||||||
This prevents processes in different terminal sessions from using
|
This prevents processes in different terminal sessions from using
|
||||||
the same time stamp record.
|
the same time stamp record.
|
||||||
It also helps reduce the chance that a user will be able to run
|
On systems where a process's start time can be queried,
|
||||||
.Nm sudo
|
the start time of the session leader
|
||||||
without entering a password when logging out and back in again
|
is recorded in the time stamp record.
|
||||||
on the same terminal.
|
If no terminal is present or the
|
||||||
|
.Em timestamp_type
|
||||||
|
option is set to
|
||||||
|
.Dq ppid ,
|
||||||
|
the start time of the parent process is used instead.
|
||||||
|
In most cases this will prevent a time stamp record from being re-used
|
||||||
|
without the user entering a password when logging out and back in again.
|
||||||
.Sh DEBUGGING
|
.Sh DEBUGGING
|
||||||
Versions 1.8.4 and higher of the
|
Versions 1.8.4 and higher of the
|
||||||
.Nm
|
.Nm
|
||||||
|
@@ -161,7 +161,8 @@ SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
|
|||||||
env_pattern.lo find_path.lo gc.lo goodpath.lo group_plugin.lo \
|
env_pattern.lo find_path.lo gc.lo goodpath.lo group_plugin.lo \
|
||||||
interfaces.lo iolog.lo iolog_path.lo locale.lo logging.lo \
|
interfaces.lo iolog.lo iolog_path.lo locale.lo logging.lo \
|
||||||
logwrap.lo mkdir_parents.lo parse.lo policy.lo prompt.lo \
|
logwrap.lo mkdir_parents.lo parse.lo policy.lo prompt.lo \
|
||||||
set_perms.lo sudo_nss.lo sudoers.lo timestamp.lo @SUDOERS_OBJS@
|
set_perms.lo starttime.lo sudo_nss.lo sudoers.lo \
|
||||||
|
timestamp.lo @SUDOERS_OBJS@
|
||||||
|
|
||||||
VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o sudo_printf.o visudo.o \
|
VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o sudo_printf.o visudo.o \
|
||||||
visudo_json.o
|
visudo_json.o
|
||||||
@@ -607,12 +608,13 @@ check_addr.o: $(srcdir)/regress/parser/check_addr.c $(devdir)/def_data.h \
|
|||||||
$(top_builddir)/pathnames.h
|
$(top_builddir)/pathnames.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_addr.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_addr.c
|
||||||
check_base64.o: $(srcdir)/regress/parser/check_base64.c \
|
check_base64.o: $(srcdir)/regress/parser/check_base64.c \
|
||||||
$(incdir)/sudo_compat.h $(top_builddir)/config.h
|
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||||
|
$(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_base64.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_base64.c
|
||||||
check_digest.o: $(srcdir)/regress/parser/check_digest.c \
|
check_digest.o: $(srcdir)/regress/parser/check_digest.c \
|
||||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_queue.h \
|
$(incdir)/sudo_fatal.h $(incdir)/sudo_queue.h \
|
||||||
$(srcdir)/parse.h $(top_builddir)/config.h
|
$(incdir)/sudo_util.h $(srcdir)/parse.h $(top_builddir)/config.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_digest.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_digest.c
|
||||||
check_env_pattern.o: $(srcdir)/regress/env_match/check_env_pattern.c \
|
check_env_pattern.o: $(srcdir)/regress/env_match/check_env_pattern.c \
|
||||||
$(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
$(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||||
@@ -634,11 +636,12 @@ check_fill.o: $(srcdir)/regress/parser/check_fill.c $(devdir)/gram.h \
|
|||||||
check_gentime.o: $(srcdir)/regress/parser/check_gentime.c \
|
check_gentime.o: $(srcdir)/regress/parser/check_gentime.c \
|
||||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||||
$(incdir)/sudo_debug.h $(incdir)/sudo_queue.h \
|
$(incdir)/sudo_debug.h $(incdir)/sudo_queue.h \
|
||||||
$(srcdir)/parse.h $(srcdir)/sudoers_debug.h \
|
$(incdir)/sudo_util.h $(srcdir)/parse.h \
|
||||||
$(top_builddir)/config.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
|
$(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)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||||
|
$(incdir)/sudo_util.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
|
||||||
check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
||||||
$(devdir)/def_data.c $(devdir)/def_data.h \
|
$(devdir)/def_data.c $(devdir)/def_data.h \
|
||||||
@@ -1111,6 +1114,16 @@ sssd.lo: $(srcdir)/sssd.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)/sssd.c
|
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sssd.c
|
||||||
|
starttime.lo: $(srcdir)/starttime.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)/check.h $(srcdir)/defaults.h \
|
||||||
|
$(srcdir)/logging.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)/starttime.c
|
||||||
sudo_auth.lo: $(authdir)/sudo_auth.c $(devdir)/def_data.h \
|
sudo_auth.lo: $(authdir)/sudo_auth.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 \
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
* records. Each record starts with a 16-bit version number and a 16-bit
|
* records. Each record starts with a 16-bit version number and a 16-bit
|
||||||
* record size. Multiple record types can coexist in the same file.
|
* record size. Multiple record types can coexist in the same file.
|
||||||
*/
|
*/
|
||||||
#define TS_VERSION 1
|
#define TS_VERSION 2
|
||||||
|
|
||||||
/* Time stamp entry types */
|
/* Time stamp entry types */
|
||||||
#define TS_GLOBAL 0x01
|
#define TS_GLOBAL 0x01
|
||||||
@@ -46,7 +46,6 @@
|
|||||||
#define TS_DISABLED 0x01 /* entry disabled */
|
#define TS_DISABLED 0x01 /* entry disabled */
|
||||||
#define TS_ANYUID 0x02 /* ignore uid, only valid in the key */
|
#define TS_ANYUID 0x02 /* ignore uid, only valid in the key */
|
||||||
|
|
||||||
/* XXX - may also want to store uid/gid of tty device */
|
|
||||||
struct timestamp_entry {
|
struct timestamp_entry {
|
||||||
unsigned short version; /* version number */
|
unsigned short version; /* version number */
|
||||||
unsigned short size; /* entry size */
|
unsigned short size; /* entry size */
|
||||||
@@ -54,6 +53,7 @@ struct timestamp_entry {
|
|||||||
unsigned short flags; /* TS_DISABLED, TS_ANYUID */
|
unsigned short flags; /* TS_DISABLED, TS_ANYUID */
|
||||||
uid_t auth_uid; /* uid to authenticate as */
|
uid_t auth_uid; /* uid to authenticate as */
|
||||||
pid_t sid; /* session ID associated with tty/ppid */
|
pid_t sid; /* session ID associated with tty/ppid */
|
||||||
|
struct timespec start_time; /* session/ppid start time */
|
||||||
struct timespec ts; /* timestamp (CLOCK_MONOTONIC) */
|
struct timespec ts; /* timestamp (CLOCK_MONOTONIC) */
|
||||||
union {
|
union {
|
||||||
dev_t ttydev; /* tty device number */
|
dev_t ttydev; /* tty device number */
|
||||||
@@ -66,6 +66,7 @@ void timestamp_close(void *vcookie);
|
|||||||
bool timestamp_lock(void *vcookie, struct passwd *pw);
|
bool timestamp_lock(void *vcookie, struct passwd *pw);
|
||||||
bool timestamp_update(void *vcookie, struct passwd *pw);
|
bool timestamp_update(void *vcookie, struct passwd *pw);
|
||||||
int timestamp_status(void *vcookie, struct passwd *pw);
|
int timestamp_status(void *vcookie, struct passwd *pw);
|
||||||
|
int get_starttime(pid_t pid, struct timespec *starttime);
|
||||||
bool already_lectured(int status);
|
bool already_lectured(int status);
|
||||||
int set_lectured(void);
|
int set_lectured(void);
|
||||||
|
|
||||||
|
282
plugins/sudoers/starttime.c
Normal file
282
plugins/sudoers/starttime.c
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2017 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
/* Large files not supported by procfs.h on Solaris. */
|
||||||
|
#if defined(HAVE_STRUCT_PSINFO_PR_TTYDEV)
|
||||||
|
# undef _FILE_OFFSET_BITS
|
||||||
|
# undef _LARGE_FILES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV)
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
# include <sys/user.h>
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_PROCFS_H)
|
||||||
|
# include <procfs.h>
|
||||||
|
#elif defined(HAVE_SYS_PROCFS_H)
|
||||||
|
# include <sys/procfs.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_PSTAT_GETPROC
|
||||||
|
# include <sys/pstat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "sudoers.h"
|
||||||
|
#include "check.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arguments for sysctl(2) when reading the process start time.
|
||||||
|
*/
|
||||||
|
#if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV)
|
||||||
|
# define SUDO_KERN_PROC KERN_PROC2
|
||||||
|
# define sudo_kinfo_proc kinfo_proc2
|
||||||
|
# define sudo_kp_namelen 6
|
||||||
|
#elif defined(HAVE_STRUCT_KINFO_PROC_P_TDEV)
|
||||||
|
# define SUDO_KERN_PROC KERN_PROC
|
||||||
|
# define sudo_kinfo_proc kinfo_proc
|
||||||
|
# define sudo_kp_namelen 6
|
||||||
|
#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
|
||||||
|
# define SUDO_KERN_PROC KERN_PROC
|
||||||
|
# define sudo_kinfo_proc kinfo_proc
|
||||||
|
# define sudo_kp_namelen 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store start time of the specified process in starttime.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(sudo_kinfo_proc)
|
||||||
|
int
|
||||||
|
get_starttime(pid_t pid, struct timespec *starttime)
|
||||||
|
{
|
||||||
|
struct sudo_kinfo_proc *ki_proc = NULL;
|
||||||
|
size_t size = sizeof(*ki_proc);
|
||||||
|
int mib[6], rc;
|
||||||
|
debug_decl(get_starttime, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup start time for pid via sysctl.
|
||||||
|
*/
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = SUDO_KERN_PROC;
|
||||||
|
mib[2] = KERN_PROC_PID;
|
||||||
|
mib[3] = (int)pid;
|
||||||
|
mib[4] = sizeof(*ki_proc);
|
||||||
|
mib[5] = 1;
|
||||||
|
do {
|
||||||
|
struct sudo_kinfo_proc *kp;
|
||||||
|
|
||||||
|
size += size / 10;
|
||||||
|
if ((kp = realloc(ki_proc, size)) == NULL) {
|
||||||
|
rc = -1;
|
||||||
|
break; /* really out of memory. */
|
||||||
|
}
|
||||||
|
ki_proc = kp;
|
||||||
|
rc = sysctl(mib, sudo_kp_namelen, ki_proc, &size, NULL, 0);
|
||||||
|
} while (rc == -1 && errno == ENOMEM);
|
||||||
|
if (rc != -1) {
|
||||||
|
#if defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
|
||||||
|
/* FreeBSD and macOS */
|
||||||
|
starttime->tv_sec = ki_proc->ki_start->tv_sec;
|
||||||
|
starttime->tv_nsec = ki_proc->ki_start->tv_usec / 1000;
|
||||||
|
#else
|
||||||
|
/* NetBSD and OpenBSD */
|
||||||
|
starttime->tv_sec = ki_proc->p_ustart_sec;
|
||||||
|
starttime->tv_nsec = ki_proc->p_ustart_usec / 1000;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
"unable to get start time for %d via KERN_PROC", (int)pid);
|
||||||
|
}
|
||||||
|
free(ki_proc);
|
||||||
|
|
||||||
|
debug_return_int(rc == -1 ? -1 : 0);
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV)
|
||||||
|
int
|
||||||
|
get_starttime(pid_t pid, struct timespec *starttime)
|
||||||
|
{
|
||||||
|
struct psinfo psinfo;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
ssize_t nread;
|
||||||
|
int fd, ret = -1;
|
||||||
|
debug_decl(get_starttime, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
|
/* Determine the start time from pr_start in /proc/pid/psinfo. */
|
||||||
|
snprintf(path, sizeof(path), "/proc/%u/psinfo", (unsigned int)pid);
|
||||||
|
if ((fd = open(path, O_RDONLY, 0)) != -1) {
|
||||||
|
nread = read(fd, &psinfo, sizeof(psinfo));
|
||||||
|
close(fd);
|
||||||
|
if (nread == (ssize_t)sizeof(psinfo)) {
|
||||||
|
starttime->tv_sec = psinfo.pr_start.tv_sec;
|
||||||
|
starttime->tv_nsec = psinfo.pr_start.tv_nsec;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
"unable to get start time for %d via %s", (int)pid, path);
|
||||||
|
debug_return_int(ret);
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
int
|
||||||
|
get_starttime(pid_t pid, struct timespec *starttime)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
char *cp, buf[1024];
|
||||||
|
ssize_t nread;
|
||||||
|
int ret = -1;
|
||||||
|
int fd = -1;
|
||||||
|
long tps;
|
||||||
|
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start time is in ticks per second on Linux.
|
||||||
|
*/
|
||||||
|
tps = sysconf(_SC_CLK_TCK);
|
||||||
|
if (tps == -1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the start time from 22nd field in /proc/pid/stat.
|
||||||
|
* Ignore /proc/self/stat if it contains embedded NUL bytes.
|
||||||
|
* XXX - refactor common code with ttyname.c?
|
||||||
|
*/
|
||||||
|
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned int)pid);
|
||||||
|
if ((fd = open(path, O_RDONLY | O_NOFOLLOW)) != -1) {
|
||||||
|
cp = buf;
|
||||||
|
while ((nread = read(fd, cp, buf + sizeof(buf) - cp)) != 0) {
|
||||||
|
if (nread == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cp += nread;
|
||||||
|
if (cp >= buf + sizeof(buf))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nread == 0 && memchr(buf, '\0', cp - buf) == NULL) {
|
||||||
|
/*
|
||||||
|
* Field 22 is the start time (%ull).
|
||||||
|
* Since the process name at field 2 "(comm)" may include
|
||||||
|
* whitespace (including newlines), start at the last ')' found.
|
||||||
|
*/
|
||||||
|
*cp = '\0';
|
||||||
|
cp = strrchr(buf, ')');
|
||||||
|
if (cp != NULL) {
|
||||||
|
char *ep = cp;
|
||||||
|
int field = 1;
|
||||||
|
|
||||||
|
while (*++ep != '\0') {
|
||||||
|
if (*ep == ' ') {
|
||||||
|
*ep = '\0';
|
||||||
|
if (++field == 22) {
|
||||||
|
unsigned long long ullval;
|
||||||
|
|
||||||
|
/* Must start with a digit (not negative). */
|
||||||
|
if (!isdigit((unsigned char)*cp)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* starttime is %ul in 2.4 and %ull in >= 2.6 */
|
||||||
|
errno = 0;
|
||||||
|
ullval = strtoull(cp, &ep, 10);
|
||||||
|
if (ep == cp || *ep != ' ') {
|
||||||
|
errno = EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (errno == ERANGE && ullval == ULLONG_MAX)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Convert from ticks to timespec */
|
||||||
|
starttime->tv_sec = ullval / tps;
|
||||||
|
starttime->tv_nsec =
|
||||||
|
(ullval % tps) * (1000000000 / tps);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cp = ep + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errno = ENOENT;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
if (ret == -1)
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
"unable to get start time for %d via %s", (int)pid, path);
|
||||||
|
debug_return_int(ret);
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_PSTAT_GETPROC)
|
||||||
|
int
|
||||||
|
get_starttime(pid_t pid, struct timespec *starttime)
|
||||||
|
{
|
||||||
|
struct pst_status pstat;
|
||||||
|
int rc;
|
||||||
|
debug_decl(get_starttime, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the start time from pst_start in struct pst_status.
|
||||||
|
* We may get EOVERFLOW if the whole thing doesn't fit but that is OK.
|
||||||
|
*/
|
||||||
|
rc = pstat_getproc(&pstat, sizeof(pstat), (size_t)0, (int)getpid());
|
||||||
|
if (rc != -1 || errno == EOVERFLOW) {
|
||||||
|
starttime->tv_sec = pstat.pst_start;
|
||||||
|
starttime->tv_nsec = 0;
|
||||||
|
debug_return_int(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
"unable to get start time for %d via pstat_getproc", (int)pid);
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int
|
||||||
|
get_starttime(pid_t pid, struct timespec *starttime)
|
||||||
|
{
|
||||||
|
debug_decl(get_starttime, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
|
||||||
|
"process start time not supported by sudo on this system");
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
#endif
|
@@ -90,10 +90,15 @@ ts_match_record(struct timestamp_entry *key, struct timestamp_entry *entry)
|
|||||||
/* verify parent pid */
|
/* verify parent pid */
|
||||||
if (entry->u.ppid != key->u.ppid)
|
if (entry->u.ppid != key->u.ppid)
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
|
if (sudo_timespeccmp(&entry->start_time, &key->start_time, !=))
|
||||||
|
debug_return_bool(false);
|
||||||
|
break;
|
||||||
break;
|
break;
|
||||||
case TS_TTY:
|
case TS_TTY:
|
||||||
if (entry->u.ttydev != key->u.ttydev)
|
if (entry->u.ttydev != key->u.ttydev)
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
|
if (sudo_timespeccmp(&entry->start_time, &key->start_time, !=))
|
||||||
|
debug_return_bool(false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* unknown record type, ignore it */
|
/* unknown record type, ignore it */
|
||||||
@@ -334,6 +339,8 @@ ts_init_key(struct timestamp_entry *entry, struct passwd *pw, int flags,
|
|||||||
/* tty-based time stamp */
|
/* tty-based time stamp */
|
||||||
entry->type = TS_TTY;
|
entry->type = TS_TTY;
|
||||||
entry->u.ttydev = sb.st_rdev;
|
entry->u.ttydev = sb.st_rdev;
|
||||||
|
if (entry->sid != -1)
|
||||||
|
get_starttime(entry->sid, &entry->start_time);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
@@ -341,6 +348,7 @@ ts_init_key(struct timestamp_entry *entry, struct passwd *pw, int flags,
|
|||||||
/* ppid-based time stamp */
|
/* ppid-based time stamp */
|
||||||
entry->type = TS_PPID;
|
entry->type = TS_PPID;
|
||||||
entry->u.ppid = getppid();
|
entry->u.ppid = getppid();
|
||||||
|
get_starttime(entry->u.ppid, &entry->start_time);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* global time stamp */
|
/* global time stamp */
|
||||||
|
Reference in New Issue
Block a user