diff --git a/MANIFEST b/MANIFEST index c4faf74e2..8f1ca8d5a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -156,6 +156,7 @@ plugins/sudoers/boottime.c plugins/sudoers/bsm_audit.c plugins/sudoers/bsm_audit.h plugins/sudoers/check.c +plugins/sudoers/check.h plugins/sudoers/def_data.c plugins/sudoers/def_data.h plugins/sudoers/def_data.in diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 42caa4f3a..2b5f8d98b 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -448,7 +448,7 @@ check.lo: $(srcdir)/check.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ - $(srcdir)/timestamp.h + $(srcdir)/timestamp.h $(srcdir)/check.h $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(DEFS) $(srcdir)/check.c check_addr.o: $(srcdir)/regress/parser/check_addr.c $(top_builddir)/config.h \ $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c index 15893984a..34146a156 100644 --- a/plugins/sudoers/check.c +++ b/plugins/sudoers/check.c @@ -48,6 +48,7 @@ #include "sudoers.h" #include "timestamp.h" +#include "check.h" static char *expand_prompt(char *, char *, char *); static bool display_lecture(int); @@ -101,9 +102,11 @@ check_user(int validated, int mode) goto done; } - status = timestamp_status(TS_MAKE_DIRS); + status = timestamp_status(); if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) { + bool lectured; + /* Bail out if we are non-interactive and a password is required */ if (ISSET(mode, MODE_NONINTERACTIVE)) { validated |= FLAG_NON_INTERACTIVE; @@ -113,13 +116,15 @@ check_user(int validated, int mode) } /* XXX - should not lecture if askpass helper is being used. */ - display_lecture(status); + lectured = display_lecture(status); /* Expand any escapes in the prompt. */ prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, user_name, user_shost); rval = verify_user(auth_pw, prompt, validated); + if (rval == true && lectured) + set_lectured(); } /* Only update timestamp if user was validated. */ if (rval == true && ISSET(validated, VALIDATE_OK) && @@ -155,7 +160,7 @@ display_lecture(int status) debug_decl(lecture, SUDO_DEBUG_AUTH) if (def_lecture == never || - (def_lecture == once && status != TS_MISSING && status != TS_ERROR)) + (def_lecture == once && already_lectured(status))) debug_return_int(false); memset(&msg, 0, sizeof(msg)); diff --git a/plugins/sudoers/check.h b/plugins/sudoers/check.h new file mode 100644 index 000000000..af5eabb8e --- /dev/null +++ b/plugins/sudoers/check.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012 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 + * 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. + */ + +#ifndef _SUDOERS_CHECK_H +#define _SUDOERS_CHECK_H + +#define already_lectured(s) (s != TS_MISSING && s != TS_ERROR) + +#endif /* _SUDOERS_CHECK_H */ diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index d6b4463f3..b592da09f 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -231,9 +231,11 @@ int find_path(char *, char **, struct stat *, char *, int); /* check.c */ int check_user(int, int); -void remove_timestamp(bool); bool user_is_exempt(void); +/* timestamp.c */ +void remove_timestamp(bool); + /* sudo_auth.c */ int verify_user(struct passwd *pw, char *prompt, int validated); int sudo_auth_begin_session(struct passwd *pw, char **user_env[]); diff --git a/plugins/sudoers/timestamp.c b/plugins/sudoers/timestamp.c index f26cee32f..b4fc4bc21 100644 --- a/plugins/sudoers/timestamp.c +++ b/plugins/sudoers/timestamp.c @@ -174,15 +174,15 @@ update_timestamp(void) /* * Check the timestamp file and directory and return their status. */ -int -timestamp_status(int flags) +static int +timestamp_status_internal(bool removing) { struct stat sb; struct timeval boottime, mtime; time_t now; char *dirparent = def_timestampdir; int status = TS_ERROR; /* assume the worst */ - debug_decl(timestamp_status, SUDO_DEBUG_AUTH) + debug_decl(timestamp_status_internal, SUDO_DEBUG_AUTH) if (timestamp_uid != 0) set_perms(PERM_TIMESTAMP); @@ -215,7 +215,7 @@ timestamp_status(int flags) log_error(USE_ERRNO, _("unable to stat %s"), dirparent); } else { /* No dirparent, try to make one. */ - if (ISSET(flags, TS_MAKE_DIRS)) { + if (!removing) { if (mkdir(dirparent, S_IRWXU)) log_error(USE_ERRNO, _("unable to mkdir %s"), dirparent); @@ -262,9 +262,9 @@ timestamp_status(int flags) /* * If there is no user ticket dir, AND we are in tty ticket mode, - * AND the TS_MAKE_DIRS flag is set, create the user ticket dir. + * AND we are not just going to remove it, create the user ticket dir. */ - if (status == TS_MISSING && *timestampfile && ISSET(flags, TS_MAKE_DIRS)) { + if (status == TS_MISSING && *timestampfile && !removing) { if (mkdir(timestampdir, S_IRWXU) == -1) { status = TS_ERROR; log_error(USE_ERRNO, _("unable to mkdir %s"), timestampdir); @@ -308,7 +308,7 @@ timestamp_status(int flags) * If removing, we don't care about the contents. * The actual mtime check is done later. */ - if (ISSET(flags, TS_REMOVE)) { + if (removing) { status = TS_OLD; } else if (sb.st_size != 0) { struct sudo_tty_info info; @@ -332,7 +332,7 @@ timestamp_status(int flags) /* * If the file/dir exists and we are not removing it, check its mtime. */ - if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) { + if (status == TS_OLD && !removing) { mtim_get(&sb, &mtime); /* Negative timeouts only expire manually (sudo -k). */ if (def_timestamp_timeout < 0 && mtime.tv_sec != 0) @@ -370,6 +370,12 @@ done: debug_return_int(status); } +int +timestamp_status(void) +{ + return timestamp_status_internal(false); +} + /* * Remove the timestamp ticket file/dir. */ @@ -384,7 +390,7 @@ remove_timestamp(bool remove) if (build_timestamp() == -1) debug_return; - status = timestamp_status(TS_REMOVE); + status = timestamp_status_internal(true); if (status != TS_MISSING && status != TS_ERROR) { path = *timestampfile ? timestampfile : timestampdir; if (remove) { @@ -446,3 +452,13 @@ tty_is_devpts(const char *tty) #endif /* __linux__ */ debug_return_bool(retval); } + +/* + * Lecture status is currently implied by the timestamp status but + * may be stored separately in a future release. + */ +bool +set_lectured(void) +{ + return true; +} diff --git a/plugins/sudoers/timestamp.h b/plugins/sudoers/timestamp.h index a0e9ead2e..00679ec8a 100644 --- a/plugins/sudoers/timestamp.h +++ b/plugins/sudoers/timestamp.h @@ -29,10 +29,6 @@ #define TS_NOFILE 3 #define TS_ERROR 4 -/* Flags for timestamp_status() */ -#define TS_MAKE_DIRS 1 -#define TS_REMOVE 2 - /* * Info stored in tty ticket from stat(2) to help with tty matching. */ @@ -45,6 +41,6 @@ struct sudo_tty_info { bool update_timestamp(void); int build_timestamp(void); -int timestamp_status(int); +int timestamp_status(void); #endif /* _SUDO_TIMESTAMP_H */