2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 01:49:11 +00:00

Use the user-ID instead of user-name for the timestamp and lecture file.

This avoids problems if the user name itself contains a path separator.
This commit is contained in:
Todd C. Miller 2023-09-11 10:27:35 -06:00
parent 94b80e3ad4
commit 7363ad7b32
7 changed files with 73 additions and 33 deletions

View File

@ -25,7 +25,7 @@
.nr BA @BAMAN@
.nr LC @LCMAN@
.nr PS @PSMAN@
.TH "SUDOERS" "@mansectform@" "August 28, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.TH "SUDOERS" "@mansectform@" "September 20, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@ -6199,7 +6199,7 @@ line in the
sudo.conf(@mansectform@)
file.
.TP 3n
unable to open @rundir@/ts/username
unable to open @rundir@/ts/user-ID
\fBsudoers\fR
was unable to read or create the user's time stamp file.
This can happen when
@ -6213,7 +6213,7 @@ The default mode for
\fI@rundir@\fR
is 0711.
.TP 3n
unable to write to @rundir@/ts/username
unable to write to @rundir@/ts/user-ID
\fBsudoers\fR
was unable to write to the user's time stamp file.
.TP 3n

View File

@ -25,7 +25,7 @@
.nr BA @BAMAN@
.nr LC @LCMAN@
.nr PS @PSMAN@
.Dd August 28, 2023
.Dd September 20, 2023
.Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@ -5797,7 +5797,7 @@ file) to the
line in the
.Xr sudo.conf @mansectform@
file.
.It unable to open @rundir@/ts/username
.It unable to open @rundir@/ts/user-ID
.Nm
was unable to read or create the user's time stamp file.
This can happen when
@ -5810,7 +5810,7 @@ is not searchable by group or other.
The default mode for
.Pa @rundir@
is 0711.
.It unable to write to @rundir@/ts/username
.It unable to write to @rundir@/ts/user-ID
.Nm
was unable to write to the user's time stamp file.
.It @rundir@/ts is owned by uid X, should be Y

View File

@ -2,7 +2,7 @@
.\"
.\" SPDX-License-Identifier: ISC
.\"
.\" Copyright (c) 2017-2020, 2022 Todd C. Miller <Todd.Miller@sudo.ws>
.\" Copyright (c) 2017-2020, 2022-2023 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
@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.TH "SUDOERS_TIMESTAMP" "@mansectform@" "September 13, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.TH "SUDOERS_TIMESTAMP" "@mansectform@" "September 20, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@ -25,7 +25,7 @@
.SH "DESCRIPTION"
The
\fBsudoers\fR
plugin uses per-user time stamp files for credential caching.
plugin uses per-user-ID time stamp files for credential caching.
Once a user has been authenticated, they may use
\fBsudo\fR
without a password for a short period of time
@ -278,6 +278,12 @@ This prevents re-use of the time stamp file after logout in most cases.
Support was added for the kernel-based tty time stamps available in
OpenBSD
which do not use an on-disk time stamp file.
.TP 6n
1.9.15
Time stamp file path names are now based on the invoking user-ID
instead of the user name.
This avoids problems with user names that include a path separator
character.
.SH "AUTHORS"
Many people have worked on
\fBsudo\fR

View File

@ -1,7 +1,7 @@
.\"
.\" SPDX-License-Identifier: ISC
.\"
.\" Copyright (c) 2017-2020, 2022 Todd C. Miller <Todd.Miller@sudo.ws>
.\" Copyright (c) 2017-2020, 2022-2023 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
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd September 13, 2022
.Dd September 20, 2023
.Dt SUDOERS_TIMESTAMP @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@ -24,7 +24,7 @@
.Sh DESCRIPTION
The
.Nm sudoers
plugin uses per-user time stamp files for credential caching.
plugin uses per-user-ID time stamp files for credential caching.
Once a user has been authenticated, they may use
.Nm sudo
without a password for a short period of time
@ -256,6 +256,11 @@ This prevents re-use of the time stamp file after logout in most cases.
Support was added for the kernel-based tty time stamps available in
.Ox
which do not use an on-disk time stamp file.
.It 1.9.15
Time stamp file path names are now based on the invoking user-ID
instead of the user name.
This avoids problems with user names that include a path separator
character.
.El
.Sh AUTHORS
Many people have worked on

View File

@ -201,7 +201,7 @@ check_user(struct sudoers_context *ctx, unsigned int validated,
ret = verify_user(ctx, closure.auth_pw, prompt, validated, &callback);
if (ret == AUTH_SUCCESS && closure.lectured)
(void)set_lectured(ctx->user.name); /* lecture error not fatal */
(void)set_lectured(ctx); /* lecture error not fatal */
free(prompt);
break;
}
@ -251,7 +251,7 @@ display_lecture(struct sudo_conv_callback *callback)
debug_return;
if (def_lecture == never ||
(def_lecture == once && already_lectured(closure->ctx->user.name)))
(def_lecture == once && already_lectured(closure->ctx)))
debug_return;
memset(&msg, 0, sizeof(msg));

View File

@ -442,9 +442,10 @@ ts_init_key_nonglobal(const struct sudoers_context *ctx,
void *
timestamp_open(const struct sudoers_context *ctx)
{
int tries, len, dfd = -1, fd = -1;
char uidstr[STRLEN_MAX_UNSIGNED(uid_t) + 1];
struct ts_cookie *cookie;
char *fname = NULL;
int tries, dfd = -1, fd = -1;
debug_decl(timestamp_open, SUDOERS_DEBUG_AUTH);
/* Zero timeout means don't use the time stamp file. */
@ -459,14 +460,19 @@ timestamp_open(const struct sudoers_context *ctx)
goto bad;
/* Open time stamp file. */
if (asprintf(&fname, "%s/%s", def_timestampdir, ctx->user.name) == -1) {
len = snprintf(uidstr, sizeof(uidstr), "%u", (unsigned int)ctx->user.uid);
if (len < 0 || len >= ssizeof(uidstr)) {
errno = EINVAL;
goto bad;
}
if (asprintf(&fname, "%s/%s", def_timestampdir, uidstr) == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto bad;
}
for (tries = 1; ; tries++) {
struct stat sb;
fd = ts_openat(dfd, ctx->user.name, O_RDWR|O_CREAT);
fd = ts_openat(dfd, uidstr, O_RDWR|O_CREAT);
switch (fd) {
case TIMESTAMP_OPEN_ERROR:
log_warning(ctx, SLOG_SEND_MAIL, N_("unable to open %s"), fname);
@ -492,7 +498,7 @@ timestamp_open(const struct sudoers_context *ctx)
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
"removing time stamp file that predates boot time");
close(fd);
unlinkat(dfd, ctx->user.name, 0);
unlinkat(dfd, uidstr, 0);
continue;
}
}
@ -1004,7 +1010,8 @@ int
timestamp_remove(const struct sudoers_context *ctx, bool unlink_it)
{
struct timestamp_entry key, entry;
int dfd = -1, fd = -1, ret = true;
int len, dfd = -1, fd = -1, ret = true;
char uidstr[STRLEN_MAX_UNSIGNED(uid_t) + 1];
char *fname = NULL;
debug_decl(timestamp_remove, SUDOERS_DEBUG_AUTH);
@ -1025,7 +1032,13 @@ timestamp_remove(const struct sudoers_context *ctx, bool unlink_it)
goto done;
}
if (asprintf(&fname, "%s/%s", def_timestampdir, ctx->user.name) == -1) {
len = snprintf(uidstr, sizeof(uidstr), "%u", (unsigned int)ctx->user.uid);
if (len < 0 || len >= ssizeof(uidstr)) {
errno = EINVAL;
ret = -1;
goto done;
}
if (asprintf(&fname, "%s/%s", def_timestampdir, uidstr) == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
ret = -1;
goto done;
@ -1033,12 +1046,12 @@ timestamp_remove(const struct sudoers_context *ctx, bool unlink_it)
/* For "sudo -K" simply unlink the time stamp file. */
if (unlink_it) {
ret = unlinkat(dfd, ctx->user.name, 0) ? -1 : true;
ret = unlinkat(dfd, uidstr, 0) ? -1 : true;
goto done;
}
/* Open time stamp file and lock it for exclusive access. */
fd = ts_openat(dfd, ctx->user.name, O_RDWR);
fd = ts_openat(dfd, uidstr, O_RDWR);
switch (fd) {
case TIMESTAMP_OPEN_ERROR:
if (errno != ENOENT)
@ -1113,18 +1126,28 @@ cb_timestampowner(struct sudoers_context *ctx, const char *file,
* Returns true if the user has already been lectured.
*/
bool
already_lectured(const char *user)
already_lectured(const struct sudoers_context *ctx)
{
char uidstr[STRLEN_MAX_UNSIGNED(uid_t) + 1];
bool ret = false;
struct stat sb;
int dfd;
int dfd, len;
debug_decl(already_lectured, SUDOERS_DEBUG_AUTH);
/* Check the existence and validity of timestamp dir. */
dfd = ts_secure_opendir(def_lecture_status_dir, false, true);
if (dfd != -1) {
ret = fstatat(dfd, user, &sb, AT_SYMLINK_NOFOLLOW) == 0;
if (dfd == -1)
goto done;
len = snprintf(uidstr, sizeof(uidstr), "%u", (unsigned int)ctx->user.uid);
if (len < 0 || len >= ssizeof(uidstr))
goto done;
ret = fstatat(dfd, uidstr, &sb, AT_SYMLINK_NOFOLLOW) == 0;
done:
if (dfd != -1)
close(dfd);
}
debug_return_bool(ret);
}
@ -1133,9 +1156,10 @@ already_lectured(const char *user)
* Returns true on success, false on failure or -1 on setuid failure.
*/
int
set_lectured(const char *user)
set_lectured(const struct sudoers_context *ctx)
{
int dfd, fd, ret = false;
char uidstr[STRLEN_MAX_UNSIGNED(uid_t) + 1];
int dfd, fd, len, ret = false;
debug_decl(set_lectured, SUDOERS_DEBUG_AUTH);
/* Check the validity of timestamp dir and create if missing. */
@ -1143,8 +1167,12 @@ set_lectured(const char *user)
if (dfd == -1)
goto done;
len = snprintf(uidstr, sizeof(uidstr), "%u", (unsigned int)ctx->user.uid);
if (len < 0 || len >= ssizeof(uidstr))
goto done;
/* Create lecture file. */
fd = ts_openat(dfd, user, O_WRONLY|O_CREAT|O_EXCL);
fd = ts_openat(dfd, uidstr, O_WRONLY|O_CREAT|O_EXCL);
switch (fd) {
case TIMESTAMP_OPEN_ERROR:
/* Failed to open, not a fatal error. */
@ -1159,9 +1187,10 @@ set_lectured(const char *user)
ret = true;
break;
}
close(dfd);
done:
if (dfd != -1)
close(dfd);
debug_return_int(ret);
}

View File

@ -96,8 +96,8 @@ int timestamp_status(void *vcookie, struct passwd *pw);
uid_t timestamp_get_uid(void);
bool cb_timestampowner(struct sudoers_context *ctx, const char *file, int line, int column, const union sudo_defs_val *sd_un, int op);
int get_starttime(pid_t pid, struct timespec *starttime);
bool already_lectured(const char *user);
int set_lectured(const char *user);
bool already_lectured(const struct sudoers_context *ctx);
int set_lectured(const struct sudoers_context *ctx);
void display_lecture(struct sudo_conv_callback *callback);
int create_admin_success_flag(const struct sudoers_context *ctx);