listed in the entry.
or not I/O logging is in use. By default, B<sudo> will only run
the command in a pty when an I/O log plugin is loaded.
+=item set_utmp=bool
+
+Create a utmp (or utmpx) entry when a pseudo-tty is allocated. By
+default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type and pid fields updated.
+
+=item utmp_user=string
+
+User name to use when constructing a new utmp (or utmpx) entry when
+I<set_utmp> is enabled. This option can be used to set the user
+field in the utmp entry to the user the command runs as rather than
+the invoking user. If not set, B<sudo> will base the new entry on
+the invoking user's existing entry.
+
=back
Unsupported values will be ignored.
"iolog_file", T_STR,
"File in which to store the input/output log",
NULL,
+ }, {
+ "set_utmp", T_FLAG,
+ "Add an entry to the utmp/utmpx file when allocating a pty",
+ NULL,
+ }, {
+ "utmp_runas", T_FLAG,
+ "Set the user in utmp to the runas user, not the invoking user",
+ NULL,
}, {
NULL, 0, NULL
}
#define I_IOLOG_DIR 77
#define def_iolog_file (sudo_defs_table[78].sd_un.str)
#define I_IOLOG_FILE 78
+#define def_set_utmp (sudo_defs_table[79].sd_un.flag)
+#define I_SET_UTMP 79
+#define def_utmp_runas (sudo_defs_table[80].sd_un.flag)
+#define I_UTMP_RUNAS 80
enum def_tuple {
never,
iolog_file
T_STR
"File in which to store the input/output log"
+set_utmp
+ T_FLAG
+ "Add an entry to the utmp/utmpx file when allocating a pty"
+utmp_runas
+ T_FLAG
+ "Set the user in utmp to the runas user, not the invoking user"
def_secure_path = estrdup(SECURE_PATH);
#endif
def_editor = estrdup(EDITOR);
+ def_set_utmp = TRUE;
/* Finally do the lists (currently just environment tables). */
init_envtables();
command_info[info_len++] = estrdup("noexec=true");
if (def_noexec_file)
command_info[info_len++] = fmt_string("noexec_file", def_noexec_file);
+ if (def_set_utmp)
+ command_info[info_len++] = estrdup("set_utmp=true");
+ if (def_utmp_runas)
+ command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);
#ifdef HAVE_LOGIN_CAP_H
if (lc != NULL)
command_info[info_len++] = fmt_string("login_class", lc->lc_class);
sudo_execve(struct command_details *details, struct command_status *cstat)
{
int maxfd, n, nready, sv[2], log_io = FALSE;
+ const char *utmp_user = NULL;
fd_set *fdsr, *fdsw;
sigaction_t sa;
pid_t child;
if (!tq_empty(&io_plugins) || ISSET(details->flags, CD_USE_PTY)) {
log_io = TRUE;
if (!ISSET(details->flags, CD_BACKGROUND)) {
+ if (ISSET(details->flags, CD_SET_UTMP))
+ utmp_user = details->utmp_user ? details->utmp_user : user_details.username;
sudo_debug(8, "allocate pty for I/O logging");
- pty_setup(details->euid, user_details.tty);
+ pty_setup(details->euid, user_details.tty, utmp_user);
}
}
#ifdef HAVE_SELINUX
selinux_restore_tty();
#endif
- utmp_logout(slavename);
+ utmp_logout(slavename); /* XXX - only if CD_SET_UTMP */
}
/*
* and slavename globals.
*/
void
-pty_setup(uid_t uid, const char *tty)
+pty_setup(uid_t uid, const char *tty, const char *utmp_user)
{
io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
if (io_fds[SFD_USERTTY] != -1) {
if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE],
slavename, sizeof(slavename), uid))
error(1, "Can't get pty");
- /*
- * Add entry to utmp/utmpx.
- */
- utmp_login(tty, slavename, io_fds[SFD_SLAVE]);
+ /* Add entry to utmp/utmpx? */
+ if (utmp_user != NULL)
+ utmp_login(tty, slavename, io_fds[SFD_SLAVE], utmp_user);
}
}
}
}
}
- utmp_logout(slavename);
+ utmp_logout(slavename); /* XXX - only if CD_SET_UTMP */
}
/*
case 's':
SET_STRING("selinux_role=", selinux_role)
SET_STRING("selinux_type=", selinux_type)
+ if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
+ if (atobool(info[i] + sizeof("set_utmp=") - 1) == TRUE)
+ SET(details->flags, CD_SET_UTMP);
+ break;
+ }
if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
if (atobool(info[i] + sizeof("sudoedit=") - 1) == TRUE)
SET(details->flags, CD_SUDOEDIT);
SET(details->flags, CD_USE_PTY);
break;
}
+ SET_STRING("utmp_user=", utmp_user)
break;
}
}
#define CD_BACKGROUND 0x0400
#define CD_RBAC_ENABLED 0x0800
#define CD_USE_PTY 0x1000
+#define CD_SET_UTMP 0x2000
struct command_details {
uid_t uid;
const char *chroot;
const char *selinux_role;
const char *selinux_type;
+ const char *utmp_user;
char **argv;
char **envp;
};
void fd_set_iobs(fd_set *fdsr, fd_set *fdsw);
void handler(int s);
void pty_close(struct command_status *cstat);
-void pty_setup(uid_t uid, const char *tty);
+void pty_setup(uid_t uid, const char *tty, const char *utmp_user);
void terminate_child(pid_t pid, int use_pgrp);
extern int signal_pipe[2];
/* utmp.c */
-int utmp_login(const char *from_line, const char *to_line, int ttyfd);
+int utmp_login(const char *from_line, const char *to_line, int ttyfd,
+ const char *user);
int utmp_logout(const char *line);
#endif /* _SUDO_EXEC_H */
* Fill in a utmp entry, using an old entry as a template if there is one.
*/
static void
-utmp_fill(const char *line, sudo_utmp_t *ut_old, sudo_utmp_t *ut_new)
+utmp_fill(const char *line, const char *user, sudo_utmp_t *ut_old,
+ sudo_utmp_t *ut_new)
{
if (ut_old == NULL) {
memset(ut_new, 0, sizeof(*ut_new));
- strncpy(ut_new->ut_user, user_details.username, sizeof(ut_new->ut_user));
+ if (user == NULL) {
+ strncpy(ut_new->ut_user, user_details.username,
+ sizeof(ut_new->ut_user));
+ }
} else if (ut_old != ut_new) {
memcpy(ut_new, ut_old, sizeof(*ut_new));
}
+ if (user != NULL)
+ strncpy(ut_new->ut_user, user, sizeof(ut_new->ut_user));
strncpy(ut_new->ut_line, line, sizeof(ut_new->ut_line));
#if defined(HAVE_STRUCT_UTMPX_UT_ID) || defined(HAVE_STRUCT_UTMP_UT_ID)
utmp_setid(ut_old, ut_new);
*/
#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
int
-utmp_login(const char *from_line, const char *to_line, int ttyfd)
+utmp_login(const char *from_line, const char *to_line, int ttyfd,
+ const char *user)
{
sudo_utmp_t utbuf, *ut_old = NULL;
int rval = FALSE;
strncpy(utbuf.ut_line, from_line, sizeof(utbuf.ut_line));
ut_old = getutxline(&utbuf);
}
- utmp_fill(to_line, ut_old, &utbuf);
+ utmp_fill(to_line, user, ut_old, &utbuf);
if (pututxline(&utbuf) != NULL)
rval = TRUE;
endutxent();
# endif /* HAVE_GETTTYENT */
int
-utmp_login(const char *from_line, const char *to_line, int ttyfd)
+utmp_login(const char *from_line, const char *to_line, int ttyfd,
+ const char *user)
{
sudo_utmp_t utbuf, *ut_old = NULL;
int slot, rval = FALSE;
}
}
}
- utmp_fill(to_line, ut_old, &utbuf);
+ utmp_fill(to_line, user, ut_old, &utbuf);
if (fseek(fp, slot * (long)sizeof(utbuf), SEEK_SET) == 0) {
if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
rval = TRUE;