From: Todd C. Miller Date: Mon, 22 Jan 2018 19:18:48 +0000 (-0700) Subject: Store passwd_timeout and timestamp_timeout as a struct timespec X-Git-Tag: SUDO_1_8_23^2~191 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4c0c22506242f8d1999d2c8979ad933b1c0d84d6;p=sudo Store passwd_timeout and timestamp_timeout as a struct timespec instead of as a float. Remove timeout argument to auth_getpass() as it was never used. --- diff --git a/plugins/sudoers/auth/aix_auth.c b/plugins/sudoers/auth/aix_auth.c index 88e96dde5..d92483c6a 100644 --- a/plugins/sudoers/auth/aix_auth.c +++ b/plugins/sudoers/auth/aix_auth.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005, 2007-2016 Todd C. Miller + * Copyright (c) 1999-2005, 2007-2018 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -144,8 +144,7 @@ sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_co debug_decl(sudo_aix_verify, SUDOERS_DEBUG_AUTH) do { - pass = auth_getpass(prompt, def_passwd_timeout * 60, - SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(prompt, SUDO_CONV_PROMPT_ECHO_OFF, callback); if (pass == NULL) break; free(message); diff --git a/plugins/sudoers/auth/bsdauth.c b/plugins/sudoers/auth/bsdauth.c index e34b68676..444cd337a 100644 --- a/plugins/sudoers/auth/bsdauth.c +++ b/plugins/sudoers/auth/bsdauth.c @@ -121,9 +121,9 @@ bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_con * S/Key. */ if ((s = auth_challenge(as)) == NULL) { - pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(prompt, SUDO_CONV_PROMPT_ECHO_OFF, callback); } else { - pass = auth_getpass(s, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(s, SUDO_CONV_PROMPT_ECHO_OFF, callback); if (pass && *pass == '\0') { if ((prompt = strrchr(s, '\n'))) prompt++; @@ -142,8 +142,7 @@ bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_con debug_return_int(AUTH_FATAL); } free(pass); - pass = auth_getpass(s, def_passwd_timeout * 60, - SUDO_CONV_PROMPT_ECHO_ON, callback); + pass = auth_getpass(s, SUDO_CONV_PROMPT_ECHO_ON, callback); free(s); } } diff --git a/plugins/sudoers/auth/fwtk.c b/plugins/sudoers/auth/fwtk.c index 77d96d243..03d448b0f 100644 --- a/plugins/sudoers/auth/fwtk.c +++ b/plugins/sudoers/auth/fwtk.c @@ -91,18 +91,16 @@ restart: /* Get the password/response from the user. */ if (strncmp(resp, "challenge ", 10) == 0) { (void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]); - pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(buf, SUDO_CONV_PROMPT_ECHO_OFF, callback); if (pass && *pass == '\0') { free(pass); pass = auth_getpass("Response [echo on]: ", - def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON, callback); + SUDO_CONV_PROMPT_ECHO_ON, callback); } } else if (strncmp(resp, "chalnecho ", 10) == 0) { - pass = auth_getpass(&resp[10], def_passwd_timeout * 60, - SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(&resp[10], SUDO_CONV_PROMPT_ECHO_OFF, callback); } else if (strncmp(resp, "password", 8) == 0) { - pass = auth_getpass(prompt, def_passwd_timeout * 60, - SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(prompt, SUDO_CONV_PROMPT_ECHO_OFF, callback); } else if (strncmp(resp, "display ", 8) == 0) { sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", &resp[8]); strlcpy(buf, "response dummy", sizeof(buf)); diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c index dcd7f2a22..347289da3 100644 --- a/plugins/sudoers/auth/pam.c +++ b/plugins/sudoers/auth/pam.c @@ -533,7 +533,7 @@ converse(int num_msg, PAM_CONST struct pam_message **msg, prompt = use_pam_prompt(pm->msg) ? pm->msg : def_prompt; /* Read the password unless interrupted. */ - pass = auth_getpass(prompt, def_passwd_timeout * 60, type, callback); + pass = auth_getpass(prompt, type, callback); if (pass == NULL) { /* Error (or ^C) reading password, don't try again. */ getpass_error = true; diff --git a/plugins/sudoers/auth/securid5.c b/plugins/sudoers/auth/securid5.c index b3bfd24d8..fd6fe6c4f 100644 --- a/plugins/sudoers/auth/securid5.c +++ b/plugins/sudoers/auth/securid5.c @@ -145,8 +145,8 @@ sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_ int ret; debug_decl(sudo_securid_verify, SUDOERS_DEBUG_AUTH) - pass = auth_getpass("Enter your PASSCODE: ", - def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass("Enter your PASSCODE: ", SUDO_CONV_PROMPT_ECHO_OFF, + callback); /* Have ACE verify password */ switch (SD_Check(*sd, pass, pw->pw_name)) { @@ -185,7 +185,7 @@ sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_ !!! ATTENTION !!!\n\ Wait for the token code to change, \n\ then enter the new token code.\n", \ - def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback); + SUDO_CONV_PROMPT_ECHO_OFF, callback); if (SD_Next(*sd, pass) == ACM_OK) { ret = AUTH_SUCCESS; diff --git a/plugins/sudoers/auth/sia.c b/plugins/sudoers/auth/sia.c index a59459ca7..ab18139b5 100644 --- a/plugins/sudoers/auth/sia.c +++ b/plugins/sudoers/auth/sia.c @@ -84,8 +84,7 @@ sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth, debug_decl(sudo_sia_verify, SUDOERS_DEBUG_AUTH) /* Get password, return AUTH_INTR if we got ^C */ - pass = auth_getpass(prompt, def_passwd_timeout * 60, - SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(prompt, SUDO_CONV_PROMPT_ECHO_OFF, callback); if (pass == NULL) debug_return_int(AUTH_INTR); diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c index 76569ee91..6ef9bd726 100644 --- a/plugins/sudoers/auth/sudo_auth.c +++ b/plugins/sudoers/auth/sudo_auth.c @@ -304,8 +304,7 @@ verify_user(struct passwd *pw, char *prompt, int validated, /* Get the password unless the auth function will do it for us */ if (!standalone) { - pass = auth_getpass(prompt, def_passwd_timeout * 60, - SUDO_CONV_PROMPT_ECHO_OFF, callback); + pass = auth_getpass(prompt, SUDO_CONV_PROMPT_ECHO_OFF, callback); if (pass == NULL) break; } @@ -422,8 +421,7 @@ sudo_auth_end_session(struct passwd *pw) * The user is responsible for freeing the returned value. */ char * -auth_getpass(const char *prompt, int timeout, int type, - struct sudo_conv_callback *callback) +auth_getpass(const char *prompt, int type, struct sudo_conv_callback *callback) { struct sudo_conv_message msg; struct sudo_conv_reply repl; @@ -448,7 +446,7 @@ auth_getpass(const char *prompt, int timeout, int type, /* Call conversation function. */ memset(&msg, 0, sizeof(msg)); msg.msg_type = type; - msg.timeout = def_passwd_timeout * 60; + msg.timeout = def_passwd_timeout.tv_sec; msg.msg = prompt; memset(&repl, 0, sizeof(repl)); sudo_conv(1, &msg, &repl, callback); diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h index 6e3128071..ea5ed9cd7 100644 --- a/plugins/sudoers/auth/sudo_auth.h +++ b/plugins/sudoers/auth/sudo_auth.h @@ -48,8 +48,7 @@ typedef struct sudo_auth { #define IS_ONEANDONLY(x) ((x)->flags & FLAG_ONEANDONLY) /* Like tgetpass() but uses conversation function */ -char *auth_getpass(const char *prompt, int timeout, int type, - struct sudo_conv_callback *callback); +char *auth_getpass(const char *prompt, int type, struct sudo_conv_callback *callback); /* Pointer to conversation function to use with auth_getpass(). */ extern sudo_conv_t sudo_conv; diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index cc334b460..73f18d8b2 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -174,11 +174,11 @@ struct sudo_defs_types sudo_defs_table[] = { N_("Length at which to wrap log file lines (0 for no wrap): %u"), NULL, }, { - "timestamp_timeout", T_FLOAT|T_BOOL, + "timestamp_timeout", T_TIMESPEC|T_BOOL, N_("Authentication timestamp timeout: %.1f minutes"), NULL, }, { - "passwd_timeout", T_FLOAT|T_BOOL, + "passwd_timeout", T_TIMESPEC|T_BOOL, N_("Password prompt timeout: %.1f minutes"), NULL, }, { diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index 7239690d2..67dc145da 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -67,9 +67,9 @@ #define I_LOGLINELEN 33 #define def_loglinelen (sudo_defs_table[I_LOGLINELEN].sd_un.uival) #define I_TIMESTAMP_TIMEOUT 34 -#define def_timestamp_timeout (sudo_defs_table[I_TIMESTAMP_TIMEOUT].sd_un.fval) +#define def_timestamp_timeout (sudo_defs_table[I_TIMESTAMP_TIMEOUT].sd_un.tspec) #define I_PASSWD_TIMEOUT 35 -#define def_passwd_timeout (sudo_defs_table[I_PASSWD_TIMEOUT].sd_un.fval) +#define def_passwd_timeout (sudo_defs_table[I_PASSWD_TIMEOUT].sd_un.tspec) #define I_PASSWD_TRIES 36 #define def_passwd_tries (sudo_defs_table[I_PASSWD_TRIES].sd_un.uival) #define I_UMASK 37 diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index 944454533..5bb8d31ee 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -114,10 +114,10 @@ loglinelen T_UINT|T_BOOL "Length at which to wrap log file lines (0 for no wrap): %u" timestamp_timeout - T_FLOAT|T_BOOL + T_TIMESPEC|T_BOOL "Authentication timestamp timeout: %.1f minutes" passwd_timeout - T_FLOAT|T_BOOL + T_TIMESPEC|T_BOOL "Password prompt timeout: %.1f minutes" passwd_tries T_UINT diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index 77687a523..ce7d6a83d 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -105,7 +105,7 @@ static bool store_syslogpri(const char *str, union sudo_defs_val *sd_un); static bool store_timeout(const char *str, union sudo_defs_val *sd_un); static bool store_tuple(const char *str, union sudo_defs_val *sd_un, struct def_values *tuple_vals); static bool store_uint(const char *str, union sudo_defs_val *sd_un); -static bool store_float(const char *str, union sudo_defs_val *sd_un); +static bool store_timespec(const char *str, union sudo_defs_val *sd_un); static bool list_op(const char *str, size_t, union sudo_defs_val *sd_un, enum list_ops op); static const char *logfac2str(int); static const char *logpri2str(int); @@ -163,10 +163,14 @@ dump_defaults(void) sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.uival); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); break; - case T_FLOAT: - sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.fval); + case T_TIMESPEC: { + /* display time spec in minutes as a double */ + double d = cur->sd_un.tspec.tv_sec / 60.0; + d += cur->sd_un.tspec.tv_nsec / 1000000000.0; + sudo_printf(SUDO_CONV_INFO_MSG, desc, d); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); break; + } case T_MODE: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); @@ -305,9 +309,6 @@ parse_default_entry(struct sudo_defs_types *def, const char *val, int op, case T_UINT: rc = store_uint(val, sd_un); break; - case T_FLOAT: - rc = store_float(val, sd_un); - break; case T_MODE: rc = store_mode(val, sd_un); break; @@ -337,6 +338,9 @@ parse_default_entry(struct sudo_defs_types *def, const char *val, int op, case T_TUPLE: rc = store_tuple(val, sd_un, def->values); break; + case T_TIMESPEC: + rc = store_timespec(val, sd_un); + break; default: if (!quiet) { if (lineno > 0) { @@ -585,8 +589,8 @@ init_defaults(void) def_umask = ACCESSPERMS; #endif def_loglinelen = MAXLOGFILELEN; - def_timestamp_timeout = TIMEOUT; - def_passwd_timeout = PASSWORD_TIMEOUT; + def_timestamp_timeout.tv_sec = TIMEOUT * 60; + def_passwd_timeout.tv_sec = PASSWORD_TIMEOUT * 60; def_passwd_tries = TRIES_FOR_PASSWORD; #ifdef HAVE_ZLIB_H def_compress_io = true; @@ -848,20 +852,25 @@ store_uint(const char *str, union sudo_defs_val *sd_un) } static bool -store_float(const char *str, union sudo_defs_val *sd_un) +store_timespec(const char *str, union sudo_defs_val *sd_un) { char *endp; double d; - debug_decl(store_float, SUDOERS_DEBUG_DEFAULTS) + debug_decl(store_timespec, SUDOERS_DEBUG_DEFAULTS) if (str == NULL) { - sd_un->fval = 0.0; + sd_un->tspec.tv_sec = 0; + sd_un->tspec.tv_nsec = 0; } else { d = strtod(str, &endp); if (*endp != '\0') debug_return_bool(false); /* XXX - should check against HUGE_VAL */ - sd_un->fval = d; + + /* Convert from minutes to seconds and nanoseconds. */ + d *= 60.0; + sd_un->tspec.tv_sec = (time_t)d; + sd_un->tspec.tv_nsec = (long)(d - sd_un->tspec.tv_sec) * 1000000000L; } debug_return_bool(true); } diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h index ea4da1c5e..c0016e294 100644 --- a/plugins/sudoers/defaults.h +++ b/plugins/sudoers/defaults.h @@ -22,6 +22,7 @@ #ifndef SUDOERS_DEFAULTS_H #define SUDOERS_DEFAULTS_H +#include #include struct list_member { @@ -47,10 +48,10 @@ union sudo_defs_val { int flag; int ival; unsigned int uival; - double fval; enum def_tuple tuple; char *str; mode_t mode; + struct timespec tspec; struct list_members list; }; @@ -76,7 +77,7 @@ struct early_default { /* * Four types of defaults: strings, integers, and flags. - * Also, T_INT, T_FLOAT or T_STR may be ANDed with T_BOOL to indicate that + * Also, T_INT, T_TIMESPEC or T_STR may be ANDed with T_BOOL to indicate that * a value is not required. Flags are boolean by nature... */ #undef T_INT @@ -97,8 +98,8 @@ struct early_default { #define T_LOGPRI 0x008 #undef T_TUPLE #define T_TUPLE 0x009 -#undef T_FLOAT -#define T_FLOAT 0x010 +#undef T_TIMESPEC +#define T_TIMESPEC 0x010 #undef T_TIMEOUT #define T_TIMEOUT 0x020 #undef T_MASK diff --git a/plugins/sudoers/mkdefaults b/plugins/sudoers/mkdefaults index 6943ec4b4..885c1b581 100755 --- a/plugins/sudoers/mkdefaults +++ b/plugins/sudoers/mkdefaults @@ -137,16 +137,16 @@ sub print_record { $defname = "I_" . uc($rec->[0]); printf HEADER "#define %-23s %d\n", $defname, $recnum; for ($rec->[1]) { - if (/^T_INT/) { $v = "ival"; } - elsif (/^T_UINT/) { $v = "uival"; } - elsif (/^T_STR/) { $v = "str"; } - elsif (/^T_FLAG/) { $v = "flag"; } - elsif (/^T_MODE/) { $v = "mode"; } - elsif (/^T_LIST/) { $v = "list"; } - elsif (/^T_LOGFAC/) { $v = "ival"; } - elsif (/^T_LOGPRI/) { $v = "ival"; } - elsif (/^T_TUPLE/) { $v = "tuple"; } - elsif (/^T_FLOAT/) { $v = "fval"; } + if (/^T_INT/) { $v = "ival"; } + elsif (/^T_UINT/) { $v = "uival"; } + elsif (/^T_STR/) { $v = "str"; } + elsif (/^T_FLAG/) { $v = "flag"; } + elsif (/^T_MODE/) { $v = "mode"; } + elsif (/^T_LIST/) { $v = "list"; } + elsif (/^T_LOGFAC/) { $v = "ival"; } + elsif (/^T_LOGPRI/) { $v = "ival"; } + elsif (/^T_TUPLE/) { $v = "tuple"; } + elsif (/^T_TIMESPEC/) { $v = "tspec"; } elsif (/^T_TIMEOUT/) { $v = "ival"; } else { die "$0: unknown defaults type: $_\n"; } } diff --git a/plugins/sudoers/timestamp.c b/plugins/sudoers/timestamp.c index d4e65c96e..9e2c4179a 100644 --- a/plugins/sudoers/timestamp.c +++ b/plugins/sudoers/timestamp.c @@ -381,7 +381,7 @@ timestamp_open(const char *user, pid_t sid) debug_decl(timestamp_open, SUDOERS_DEBUG_AUTH) /* Zero timeout means don't use the time stamp file. */ - if (def_timestamp_timeout == 0.0) { + if (!sudo_timespecisset(&def_timestamp_timeout)) { errno = ENOENT; goto bad; } @@ -720,13 +720,13 @@ timestamp_status(void *vcookie, struct passwd *pw) { struct ts_cookie *cookie = vcookie; struct timestamp_entry entry; - struct timespec diff, now, timeout; + struct timespec diff, now; int status = TS_ERROR; /* assume the worst */ ssize_t nread; debug_decl(timestamp_status, SUDOERS_DEBUG_AUTH) /* Zero timeout means don't use time stamp files. */ - if (def_timestamp_timeout == 0.0) { + if (!sudo_timespecisset(&def_timestamp_timeout)) { sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "timestamps disabled"); status = TS_OLD; @@ -781,7 +781,8 @@ timestamp_status(void *vcookie, struct passwd *pw) } /* Negative timeouts only expire manually (sudo -k). */ - if (def_timestamp_timeout < 0) { + sudo_timespecclear(&diff); + if (sudo_timespeccmp(&def_timestamp_timeout, &diff, <)) { sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "time stamp record does not expire"); status = TS_CURRENT; @@ -795,12 +796,9 @@ timestamp_status(void *vcookie, struct passwd *pw) goto done; } sudo_timespecsub(&now, &entry.ts, &diff); - timeout.tv_sec = 60 * def_timestamp_timeout; - timeout.tv_nsec = ((60.0 * def_timestamp_timeout) - (double)timeout.tv_sec) - * 1000000000.0; - if (sudo_timespeccmp(&diff, &timeout, <)) { + if (sudo_timespeccmp(&diff, &def_timestamp_timeout, <)) { status = TS_CURRENT; -#ifdef CLOCK_MONOTONIC +#if defined(CLOCK_MONOTONIC) || defined(__MACH__) /* A monotonic clock should never run backwards. */ if (diff.tv_sec < 0) { log_warningx(SLOG_SEND_MAIL, @@ -810,10 +808,21 @@ timestamp_status(void *vcookie, struct passwd *pw) (void)ts_write(cookie->fd, cookie->fname, &entry, cookie->pos); } #else - /* Check for bogus (future) time in the stampfile. */ + /* + * Check for bogus (future) time in the stampfile. + * If diff / 2 > timeout, someone has been fooling with the clock. + */ sudo_timespecsub(&entry.ts, &now, &diff); - timeout.tv_sec *= 2; - if (sudo_timespeccmp(&diff, &timeout, >)) { + diff.tv_nsec /= 2; + if (diff.tv_sec & 1) + diff.tv_nsec += 500000000; + diff.tv_sec /= 2; + while (diff.tv_nsec >= 1000000000) { + diff.tv_sec++; + diff.tv_nsec -= 1000000000; + } + + if (sudo_timespeccmp(&diff, &def_timestamp_timeout, >)) { time_t tv_sec = (time_t)entry.ts.tv_sec; log_warningx(SLOG_SEND_MAIL, N_("time stamp too far in the future: %20.20s"), @@ -843,7 +852,7 @@ timestamp_update(void *vcookie, struct passwd *pw) debug_decl(timestamp_update, SUDOERS_DEBUG_AUTH) /* Zero timeout means don't use time stamp files. */ - if (def_timestamp_timeout == 0.0) { + if (!sudo_timespecisset(&def_timestamp_timeout)) { sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "timestamps disabled"); goto done; @@ -858,7 +867,7 @@ timestamp_update(void *vcookie, struct passwd *pw) #ifdef TIOCSETVERAUTH int fd = open(_PATH_TTY, O_RDWR); if (fd != -1) { - int secs = 60 * def_timestamp_timeout; + int secs = def_timestamp_timeout.tv_sec; ioctl(fd, TIOCSETVERAUTH, &secs); close(fd); }