Display the lecture immediately before prompting for a password.

This means we no longer display the lecture unless the user is going
to enter a password.  Authentication methods that don't interact
with the user via the terminal don't trigger the lecture.
This commit is contained in:
Todd C. Miller
2022-02-21 19:34:06 -07:00
parent 9757d29a24
commit 2911c31dd7
6 changed files with 55 additions and 36 deletions

View File

@@ -42,6 +42,7 @@
#include "sudoers.h" #include "sudoers.h"
#include "sudo_auth.h" #include "sudo_auth.h"
#include "check.h"
int int
sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
@@ -53,6 +54,9 @@ sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv
if (IS_NONINTERACTIVE(auth)) if (IS_NONINTERACTIVE(auth))
debug_return_int(AUTH_NONINTERACTIVE); debug_return_int(AUTH_NONINTERACTIVE);
/* Display lecture if needed and we haven't already done so. */
display_lecture(callback);
/* Try to just check the password */ /* Try to just check the password */
ka_StringToKey(pass, NULL, &afs_key); ka_StringToKey(pass, NULL, &afs_key);
if (ka_GetAdminToken(pw->pw_name, /* name */ if (ka_GetAdminToken(pw->pw_name, /* name */

View File

@@ -54,6 +54,7 @@
#include "sudoers.h" #include "sudoers.h"
#include "sudo_auth.h" #include "sudo_auth.h"
#include "check.h"
static int check_dce_status(error_status_t, char *); static int check_dce_status(error_status_t, char *);
@@ -71,6 +72,9 @@ sudo_dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth, struct sudo_
if (IS_NONINTERACTIVE(auth)) if (IS_NONINTERACTIVE(auth))
debug_return_int(AUTH_NONINTERACTIVE); debug_return_int(AUTH_NONINTERACTIVE);
/* Display lecture if needed and we haven't already done so. */
display_lecture(callback);
/* /*
* Create the local context of the DCE principal necessary * Create the local context of the DCE principal necessary
* to perform authenticated network operations. The network * to perform authenticated network operations. The network

View File

@@ -44,6 +44,7 @@
#include "sudoers.h" #include "sudoers.h"
#include "sudo_auth.h" #include "sudo_auth.h"
#include "insults.h" #include "insults.h"
#include "check.h"
static sudo_auth auth_switch[] = { static sudo_auth auth_switch[] = {
/* Standalone entries first */ /* Standalone entries first */
@@ -443,6 +444,9 @@ auth_getpass(const char *prompt, int type, struct sudo_conv_callback *callback)
sigset_t mask, omask; sigset_t mask, omask;
debug_decl(auth_getpass, SUDOERS_DEBUG_AUTH); debug_decl(auth_getpass, SUDOERS_DEBUG_AUTH);
/* Display lecture if needed and we haven't already done so. */
display_lecture(callback);
/* Mask user input if pwfeedback set and echo is off. */ /* Mask user input if pwfeedback set and echo is off. */
if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback) if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback)
type = SUDO_CONV_PROMPT_MASK; type = SUDO_CONV_PROMPT_MASK;

View File

@@ -42,15 +42,15 @@
#include "sudoers.h" #include "sudoers.h"
#include "check.h" #include "check.h"
static bool display_lecture(int);
static struct passwd *get_authpw(int);
struct getpass_closure { struct getpass_closure {
int tstat; int tstat;
int lectured;
void *cookie; void *cookie;
struct passwd *auth_pw; struct passwd *auth_pw;
}; };
static struct passwd *get_authpw(int);
/* /*
* Called when getpass is suspended so we can drop the lock. * Called when getpass is suspended so we can drop the lock.
*/ */
@@ -87,26 +87,30 @@ getpass_resume(int signo, void *vclosure)
static int static int
check_user_interactive(int validated, int mode, struct getpass_closure *closure) check_user_interactive(int validated, int mode, struct getpass_closure *closure)
{ {
struct sudo_conv_callback cb, *callback = NULL; struct sudo_conv_callback callback;
int ret = -1; int ret = -1;
char *prompt; char *prompt;
bool lectured;
debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH); debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH);
/* Construct callback for getpass function. */
memset(&callback, 0, sizeof(callback));
callback.version = SUDO_CONV_CALLBACK_VERSION;
callback.closure = closure;
callback.on_suspend = getpass_suspend;
callback.on_resume = getpass_resume;
/* Open, lock and read time stamp file if we are using it. */ /* Open, lock and read time stamp file if we are using it. */
if (!ISSET(mode, MODE_IGNORE_TICKET)) { if (!ISSET(mode, MODE_IGNORE_TICKET)) {
/* Open time stamp file and check its status. */ /* Open time stamp file and check its status. */
closure->cookie = timestamp_open(user_name, user_sid); closure->cookie = timestamp_open(user_name, user_sid);
if (timestamp_lock(closure->cookie, closure->auth_pw)) if (closure->cookie != NULL) {
closure->tstat = timestamp_status(closure->cookie, closure->auth_pw); if (timestamp_lock(closure->cookie, closure->auth_pw)) {
closure->tstat = timestamp_status(closure->cookie,
/* Construct callback for getpass function. */ closure->auth_pw);
memset(&cb, 0, sizeof(cb)); }
cb.version = SUDO_CONV_CALLBACK_VERSION; callback.on_suspend = getpass_suspend;
cb.closure = closure; callback.on_resume = getpass_resume;
cb.on_suspend = getpass_suspend; }
cb.on_resume = getpass_resume;
callback = &cb;
} }
switch (closure->tstat) { switch (closure->tstat) {
@@ -131,17 +135,14 @@ check_user_interactive(int validated, int mode, struct getpass_closure *closure)
goto done; goto done;
} }
/* XXX - should not lecture if askpass helper is being used. */
lectured = display_lecture(closure->tstat);
/* Expand any escapes in the prompt. */ /* Expand any escapes in the prompt. */
prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
closure->auth_pw->pw_name); closure->auth_pw->pw_name);
if (prompt == NULL) if (prompt == NULL)
goto done; goto done;
ret = verify_user(closure->auth_pw, prompt, validated, callback); ret = verify_user(closure->auth_pw, prompt, validated, &callback);
if (ret == true && lectured) if (ret == true && closure->lectured)
(void)set_lectured(); /* lecture error not fatal */ (void)set_lectured(); /* lecture error not fatal */
free(prompt); free(prompt);
break; break;
@@ -228,9 +229,10 @@ done:
* Display sudo lecture (standard or custom). * Display sudo lecture (standard or custom).
* Returns true if the user was lectured, else false. * Returns true if the user was lectured, else false.
*/ */
static bool void
display_lecture(int status) display_lecture(struct sudo_conv_callback *callback)
{ {
struct getpass_closure *closure = callback->closure;
struct sudo_conv_message msg; struct sudo_conv_message msg;
struct sudo_conv_reply repl; struct sudo_conv_reply repl;
char buf[BUFSIZ]; char buf[BUFSIZ];
@@ -239,9 +241,11 @@ display_lecture(int status)
int fd; int fd;
debug_decl(lecture, SUDOERS_DEBUG_AUTH); debug_decl(lecture, SUDOERS_DEBUG_AUTH);
if (def_lecture == never || if (closure->lectured)
(def_lecture == once && already_lectured(status))) debug_return;
debug_return_bool(false);
if (def_lecture == never || (def_lecture == once && already_lectured()))
debug_return;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
memset(&repl, 0, sizeof(repl)); memset(&repl, 0, sizeof(repl));
@@ -257,13 +261,12 @@ display_lecture(int status)
msg.msg = buf; msg.msg = buf;
sudo_conv(1, &msg, &repl, NULL); sudo_conv(1, &msg, &repl, NULL);
} }
close(fd); if (nread == 0) {
if (nread == -1) { close(fd);
log_warning(SLOG_RAW_MSG, goto done;
N_("error reading lecture file %s"), def_lecture_file);
debug_return_bool(false);
} }
debug_return_bool(true); log_warning(SLOG_RAW_MSG,
N_("error reading lecture file %s"), def_lecture_file);
} else { } else {
log_warningx(SLOG_RAW_MSG, log_warningx(SLOG_RAW_MSG,
N_("ignoring lecture file %s: not a regular file"), N_("ignoring lecture file %s: not a regular file"),
@@ -286,7 +289,10 @@ display_lecture(int status)
" #2) Think before you type.\n" " #2) Think before you type.\n"
" #3) With great power comes great responsibility.\n\n"); " #3) With great power comes great responsibility.\n\n");
sudo_conv(1, &msg, &repl, NULL); sudo_conv(1, &msg, &repl, NULL);
debug_return_bool(true);
done:
closure->lectured = true;
debug_return;
} }
/* /*

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 1993-1996,1998-2005, 2007-2014 * Copyright (c) 1993-1996, 1998-2005, 2007-2015, 2017-2018, 2021-2022
* Todd C. Miller <Todd.Miller@sudo.ws> * Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@@ -83,8 +83,9 @@ 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); int get_starttime(pid_t pid, struct timespec *starttime);
bool already_lectured(int status); bool already_lectured(void);
int set_lectured(void); int set_lectured(void);
void display_lecture(struct sudo_conv_callback *callback);
int create_admin_success_flag(void); int create_admin_success_flag(void);
#endif /* SUDOERS_CHECK_H */ #endif /* SUDOERS_CHECK_H */

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2014-2021 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2014-2022 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -1033,7 +1033,7 @@ done:
* Returns true if the user has already been lectured. * Returns true if the user has already been lectured.
*/ */
bool bool
already_lectured(int unused) already_lectured(void)
{ {
char status_file[PATH_MAX]; char status_file[PATH_MAX];
struct stat sb; struct stat sb;