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.h
|
||||
plugins/sudoers/sssd.c
|
||||
plugins/sudoers/starttime.c
|
||||
plugins/sudoers/sudo_nss.c
|
||||
plugins/sudoers/sudo_nss.h
|
||||
plugins/sudoers/sudo_printf.c
|
||||
|
@@ -2772,19 +2772,21 @@ SSEECCUURRIITTYY NNOOTTEESS
|
||||
with a date greater than current_time + 2 * TIMEOUT will be ignored and
|
||||
ssuuddooeerrss will log and complain.
|
||||
|
||||
Since time stamp files live in the file system, they can outlive a user's
|
||||
login session. As a result, a user may be able to login, run a command
|
||||
with ssuuddoo after authenticating, logout, login again, and run ssuuddoo without
|
||||
authenticating so long as the record's time stamp is within 5 minutes (or
|
||||
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
|
||||
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. This prevents processes in different
|
||||
terminal sessions from using the same time stamp record. It also helps
|
||||
reduce the chance that a user will be able to run ssuuddoo without entering a
|
||||
password when logging out and back in again on the same terminal.
|
||||
If the _t_i_m_e_s_t_a_m_p___t_y_p_e option is set to "tty", the time stamp record
|
||||
includes the device number of the terminal the user authenticated with.
|
||||
This provides per-terminal granularity but time stamp records may still
|
||||
outlive the user's session.
|
||||
|
||||
Unless the _t_i_m_e_s_t_a_m_p___t_y_p_e option is set to "global", the time stamp
|
||||
record also includes the session ID of the process that last
|
||||
authenticated. This prevents processes in different terminal sessions
|
||||
from using the same time stamp record. On systems where a process's
|
||||
start time can be queried, the start time of the session leader is
|
||||
recorded in the time stamp record. If no terminal is present or the
|
||||
_t_i_m_e_s_t_a_m_p___t_y_p_e option is set to "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.
|
||||
|
||||
DDEEBBUUGGGGIINNGG
|
||||
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
|
||||
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
|
||||
.\" 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
|
||||
.if n .ad l
|
||||
.SH "NAME"
|
||||
@@ -5497,31 +5497,33 @@ will be ignored and
|
||||
\fBsudoers\fR
|
||||
will log and complain.
|
||||
.PP
|
||||
Since time stamp files live in the file system, they can outlive a
|
||||
user's login session.
|
||||
As a result, a user may be able to login, run a command with
|
||||
\fBsudo\fR
|
||||
after authenticating, logout, login again, and run
|
||||
\fBsudo\fR
|
||||
without authenticating so long as the record's time stamp is within
|
||||
\fR@timeout@\fR
|
||||
minutes (or whatever value the timeout is set to in the
|
||||
\fIsudoers\fR
|
||||
file).
|
||||
When the
|
||||
\fItty_tickets\fR
|
||||
option is enabled, the time stamp record includes the device
|
||||
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
|
||||
If the
|
||||
\fItimestamp_type\fR
|
||||
option is set to
|
||||
\(Lqtty\(Rq,
|
||||
the time stamp record includes the device number of the terminal
|
||||
the user authenticated with.
|
||||
This provides per-terminal granularity but time stamp records may still
|
||||
outlive the user's session.
|
||||
.PP
|
||||
Unless the
|
||||
\fItimestamp_type\fR
|
||||
option is set to
|
||||
\(Lqglobal\(Rq,
|
||||
the time stamp record also includes the session ID of the process
|
||||
that last authenticated.
|
||||
This prevents processes in different terminal sessions from using
|
||||
the same time stamp record.
|
||||
It also helps reduce the chance that a user will be able to run
|
||||
\fBsudo\fR
|
||||
without entering a password when logging out and back in again
|
||||
on the same terminal.
|
||||
On systems where a process's start time can be queried,
|
||||
the start time of the session leader
|
||||
is recorded in the time stamp record.
|
||||
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"
|
||||
Versions 1.8.4 and higher of the
|
||||
\fBsudoers\fR
|
||||
|
@@ -19,7 +19,7 @@
|
||||
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
.\"
|
||||
.Dd December 11, 2017
|
||||
.Dd December 15, 2017
|
||||
.Dt SUDOERS @mansectform@
|
||||
.Os Sudo @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
@@ -5089,31 +5089,33 @@ will be ignored and
|
||||
.Nm sudoers
|
||||
will log and complain.
|
||||
.Pp
|
||||
Since time stamp files live in the file system, they can outlive a
|
||||
user's login session.
|
||||
As a result, a user may be able to login, run a command with
|
||||
.Nm sudo
|
||||
after authenticating, logout, login again, and run
|
||||
.Nm sudo
|
||||
without authenticating so long as the record's time stamp is within
|
||||
.Li @timeout@
|
||||
minutes (or whatever value the timeout is set to in the
|
||||
.Em sudoers
|
||||
file).
|
||||
When the
|
||||
.Em tty_tickets
|
||||
option is enabled, the time stamp record includes the device
|
||||
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
|
||||
If the
|
||||
.Em timestamp_type
|
||||
option is set to
|
||||
.Dq tty ,
|
||||
the time stamp record includes the device number of the terminal
|
||||
the user authenticated with.
|
||||
This provides per-terminal granularity but time stamp records may still
|
||||
outlive the user's session.
|
||||
.Pp
|
||||
Unless the
|
||||
.Em timestamp_type
|
||||
option is set to
|
||||
.Dq global ,
|
||||
the time stamp record also includes the session ID of the process
|
||||
that last authenticated.
|
||||
This prevents processes in different terminal sessions from using
|
||||
the same time stamp record.
|
||||
It also helps reduce the chance that a user will be able to run
|
||||
.Nm sudo
|
||||
without entering a password when logging out and back in again
|
||||
on the same terminal.
|
||||
On systems where a process's start time can be queried,
|
||||
the start time of the session leader
|
||||
is recorded in the time stamp record.
|
||||
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
|
||||
Versions 1.8.4 and higher of the
|
||||
.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 \
|
||||
interfaces.lo iolog.lo iolog_path.lo locale.lo logging.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_json.o
|
||||
@@ -607,12 +608,13 @@ check_addr.o: $(srcdir)/regress/parser/check_addr.c $(devdir)/def_data.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(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 \
|
||||
$(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
|
||||
check_digest.o: $(srcdir)/regress/parser/check_digest.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.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
|
||||
check_env_pattern.o: $(srcdir)/regress/env_match/check_env_pattern.c \
|
||||
$(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 \
|
||||
$(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
|
||||
$(incdir)/sudo_util.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 \
|
||||
$(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
|
||||
check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
||||
$(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 \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(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 \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.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
|
||||
* record size. Multiple record types can coexist in the same file.
|
||||
*/
|
||||
#define TS_VERSION 1
|
||||
#define TS_VERSION 2
|
||||
|
||||
/* Time stamp entry types */
|
||||
#define TS_GLOBAL 0x01
|
||||
@@ -46,7 +46,6 @@
|
||||
#define TS_DISABLED 0x01 /* entry disabled */
|
||||
#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 {
|
||||
unsigned short version; /* version number */
|
||||
unsigned short size; /* entry size */
|
||||
@@ -54,6 +53,7 @@ struct timestamp_entry {
|
||||
unsigned short flags; /* TS_DISABLED, TS_ANYUID */
|
||||
uid_t auth_uid; /* uid to authenticate as */
|
||||
pid_t sid; /* session ID associated with tty/ppid */
|
||||
struct timespec start_time; /* session/ppid start time */
|
||||
struct timespec ts; /* timestamp (CLOCK_MONOTONIC) */
|
||||
union {
|
||||
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_update(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);
|
||||
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 */
|
||||
if (entry->u.ppid != key->u.ppid)
|
||||
debug_return_bool(false);
|
||||
if (sudo_timespeccmp(&entry->start_time, &key->start_time, !=))
|
||||
debug_return_bool(false);
|
||||
break;
|
||||
break;
|
||||
case TS_TTY:
|
||||
if (entry->u.ttydev != key->u.ttydev)
|
||||
debug_return_bool(false);
|
||||
if (sudo_timespeccmp(&entry->start_time, &key->start_time, !=))
|
||||
debug_return_bool(false);
|
||||
break;
|
||||
default:
|
||||
/* 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 */
|
||||
entry->type = TS_TTY;
|
||||
entry->u.ttydev = sb.st_rdev;
|
||||
if (entry->sid != -1)
|
||||
get_starttime(entry->sid, &entry->start_time);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
@@ -341,6 +348,7 @@ ts_init_key(struct timestamp_entry *entry, struct passwd *pw, int flags,
|
||||
/* ppid-based time stamp */
|
||||
entry->type = TS_PPID;
|
||||
entry->u.ppid = getppid();
|
||||
get_starttime(entry->u.ppid, &entry->start_time);
|
||||
break;
|
||||
default:
|
||||
/* global time stamp */
|
||||
|
Reference in New Issue
Block a user