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 "sudo_auth.h"
#include "check.h"
int
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))
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 */
ka_StringToKey(pass, NULL, &afs_key);
if (ka_GetAdminToken(pw->pw_name, /* name */

View File

@@ -54,6 +54,7 @@
#include "sudoers.h"
#include "sudo_auth.h"
#include "check.h"
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))
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
* to perform authenticated network operations. The network

View File

@@ -44,6 +44,7 @@
#include "sudoers.h"
#include "sudo_auth.h"
#include "insults.h"
#include "check.h"
static sudo_auth auth_switch[] = {
/* Standalone entries first */
@@ -443,6 +444,9 @@ auth_getpass(const char *prompt, int type, struct sudo_conv_callback *callback)
sigset_t mask, omask;
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. */
if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback)
type = SUDO_CONV_PROMPT_MASK;

View File

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

View File

@@ -1,7 +1,7 @@
/*
* 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
* 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.
*/
bool
already_lectured(int unused)
already_lectured(void)
{
char status_file[PATH_MAX];
struct stat sb;