summaryrefslogtreecommitdiffstats
path: root/plugins/sudoers/boottime.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/sudoers/boottime.c')
-rw-r--r--plugins/sudoers/boottime.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/plugins/sudoers/boottime.c b/plugins/sudoers/boottime.c
new file mode 100644
index 0000000..ff409ae
--- /dev/null
+++ b/plugins/sudoers/boottime.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2009-2015, 2018 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.
+ */
+
+/*
+ * This is an open source non-commercial project. Dear PVS-Studio, please check it.
+ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/time.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 <errno.h>
+#include <limits.h>
+#include <time.h>
+#ifndef __linux__
+# if defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME)
+# include <sys/sysctl.h>
+# elif defined(HAVE_GETUTXID)
+# include <utmpx.h>
+# elif defined(HAVE_GETUTID)
+# include <utmp.h>
+# endif
+#endif /* !__linux__ */
+
+#include "sudoers.h"
+
+/*
+ * Fill in a struct timespec with the time the system booted.
+ * Returns 1 on success and 0 on failure.
+ */
+
+#if defined(__linux__)
+bool
+get_boottime(struct timespec *ts)
+{
+ char *line = NULL;
+ size_t linesize = 0;
+ bool found = false;
+ long long llval;
+ ssize_t len;
+ FILE *fp;
+ debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)
+
+ /* read btime from /proc/stat */
+ fp = fopen("/proc/stat", "r");
+ if (fp != NULL) {
+ while ((len = getline(&line, &linesize, fp)) != -1) {
+ if (strncmp(line, "btime ", 6) == 0) {
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ llval = strtonum(line + 6, 1, LLONG_MAX, NULL);
+ if (llval > 0) {
+ ts->tv_sec = (time_t)llval;
+ ts->tv_nsec = 0;
+ found = true;
+ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
+ "found btime in /proc/stat: %lld", llval);
+ break;
+ } else {
+ sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
+ "invalid btime in /proc/stat: %s", line);
+ }
+ }
+ }
+ fclose(fp);
+ free(line);
+ }
+
+ debug_return_bool(found);
+}
+
+#elif defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME)
+
+bool
+get_boottime(struct timespec *ts)
+{
+ size_t size;
+ int mib[2];
+ struct timeval tv;
+ debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ size = sizeof(tv);
+ if (sysctl(mib, 2, &tv, &size, NULL, 0) != -1) {
+ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
+ "KERN_BOOTTIME: %lld, %ld", (long long)tv.tv_sec, (long)tv.tv_usec);
+ TIMEVAL_TO_TIMESPEC(&tv, ts);
+ debug_return_bool(true);
+ }
+
+ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
+ "KERN_BOOTTIME: %s", strerror(errno));
+ debug_return_bool(false);
+}
+
+#elif defined(HAVE_GETUTXID)
+
+bool
+get_boottime(struct timespec *ts)
+{
+ struct utmpx *ut, key;
+ debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)
+
+ memset(&key, 0, sizeof(key));
+ key.ut_type = BOOT_TIME;
+ setutxent();
+ if ((ut = getutxid(&key)) != NULL) {
+ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
+ "BOOT_TIME: %lld, %ld", (long long)ut->ut_tv.tv_sec,
+ (long)ut->ut_tv.tv_usec);
+ TIMEVAL_TO_TIMESPEC(&ut->ut_tv, ts);
+ }
+ endutxent();
+ debug_return_bool(ut != NULL);
+}
+
+#elif defined(HAVE_GETUTID)
+
+bool
+get_boottime(struct timespec *ts)
+{
+ struct utmp *ut, key;
+ debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)
+
+ memset(&key, 0, sizeof(key));
+ key.ut_type = BOOT_TIME;
+ setutent();
+ if ((ut = getutid(&key)) != NULL) {
+ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
+ "BOOT_TIME: %lld", (long long)ut->ut_time);
+ ts->tv_sec = ut->ut_time;
+ ts->tv_nsec = 0;
+ }
+ endutent();
+ debug_return_bool(ut != NULL);
+}
+
+#else
+
+bool
+get_boottime(struct timespec *ts)
+{
+ debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)
+ debug_return_bool(false);
+}
+#endif