Add support for adding a utmp entry when allocating a new pty.
Requires the BSD login(3) or SYSV/POSIX getutent()/getutxent(). Currently only creates a new entry if the existing tty has a utmp entry.
This commit is contained in:
180
src/exec_pty.c
180
src/exec_pty.c
@@ -52,6 +52,14 @@
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
#if defined(HAVE_GETUTXID)
|
||||
# include <utmpx.h>
|
||||
#elif defined(HAVE_GETUTID)
|
||||
# include <utmp.h>
|
||||
#elif defined(HAVE_UTIL_H)
|
||||
# include <util.h>
|
||||
# include <utmp.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -109,6 +117,159 @@ static void sync_ttysize(int src, int dst);
|
||||
static void deliver_signal(pid_t pid, int signo);
|
||||
static int safe_close(int fd);
|
||||
|
||||
#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
|
||||
/*
|
||||
* Create ut_id from tty line and the id from the entry we are cloning.
|
||||
*/
|
||||
static void
|
||||
utmp_setid(const char *line, const char *old_id, char *new_id, size_t idsize)
|
||||
{
|
||||
size_t idlen;
|
||||
|
||||
/* Skip over "tty" in the id if old entry did too. */
|
||||
if (strncmp(line, "tty", 3) == 0 &&
|
||||
strncmp(old_id, "tty", idsize < 3 ? idsize : 3) != 0)
|
||||
line += 3;
|
||||
|
||||
/* Store as much as will fit, skipping parts of the beginning as needed. */
|
||||
idlen = strlen(line);
|
||||
if (idlen > idsize) {
|
||||
line += (idlen - idsize);
|
||||
idlen = idsize;
|
||||
}
|
||||
strncpy(new_id, line, idlen);
|
||||
}
|
||||
#endif /* HAVE_GETUTXID || HAVE_GETUTID */
|
||||
|
||||
/*
|
||||
* Clone a utmp entry, updating the line, id, pid and time.
|
||||
* XXX - if no existing entry, make a new one
|
||||
*/
|
||||
static int
|
||||
utmp_doclone(const char *from_line, const char *to_line)
|
||||
{
|
||||
int rval = FALSE;
|
||||
#ifdef HAVE_GETUTXID
|
||||
struct utmpx *ut_old, ut_new;
|
||||
|
||||
memset(&ut_new, 0, sizeof(ut_new));
|
||||
strncpy(ut_new.ut_line, from_line, sizeof(ut_new.ut_line));
|
||||
setutxent();
|
||||
if ((ut_old = getutxid(&ut_new)) != NULL) {
|
||||
if (ut_old != &ut_new)
|
||||
memcpy(&ut_new, ut_old, sizeof(ut_new));
|
||||
strncpy(ut_new.ut_line, to_line, sizeof(ut_new.ut_line));
|
||||
utmp_setid(to_line, ut_old->ut_id, ut_new.ut_id, sizeof(ut_new.ut_id));
|
||||
ut_new.ut_pid = getpid();
|
||||
gettimeofday(&ut_new.ut_tv, NULL);
|
||||
ut_new.ut_type = USER_PROCESS;
|
||||
|
||||
if (pututxline(&ut_new) != NULL)
|
||||
rval = TRUE;
|
||||
}
|
||||
endutxent();
|
||||
#elif HAVE_GETUTID
|
||||
struct utmp *ut_old, ut_new;
|
||||
|
||||
memset(&ut_new, 0, sizeof(ut_new));
|
||||
strncpy(ut_new.ut_line, from_line, sizeof(ut_new.ut_line));
|
||||
setutent();
|
||||
if ((ut_old = getutid(&ut_new)) != NULL) {
|
||||
if (ut_old != &ut_new)
|
||||
memcpy(&ut_new, ut_old, sizeof(ut_new));
|
||||
strncpy(ut_new.ut_line, to_line, sizeof(ut_new.ut_line));
|
||||
utmp_setid(to_line, ut_old->ut_id, ut_new.ut_id, sizeof(ut_new.ut_id));
|
||||
ut_new.ut_pid = getpid();
|
||||
ut_new.ut_time = time(NULL);
|
||||
ut_new.ut_type = USER_PROCESS;
|
||||
|
||||
if (pututline(&ut_new) != NULL)
|
||||
rval = TRUE;
|
||||
}
|
||||
endutent();
|
||||
#elif HAVE_LOGIN
|
||||
FILE *fp;
|
||||
struct utmp ut;
|
||||
|
||||
/* Find existing entry, update line and add as new. */
|
||||
if ((fp = fopen(_PATH_UTMP, "r")) != NULL) {
|
||||
while (fread(&ut, sizeof(ut), 1, fp) == 1) {
|
||||
if (ut.ut_name[0] &&
|
||||
strncmp(ut.ut_line, from_line, sizeof(ut.ut_line)) == 0) {
|
||||
strncpy(ut.ut_line, to_line, sizeof(ut.ut_line));
|
||||
login(&ut);
|
||||
rval = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
#endif
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
utmp_clone(const char *from_line, const char *to_line)
|
||||
{
|
||||
/* Strip off /dev/ prefix from to/from line as needed. */
|
||||
if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
from_line += sizeof(_PATH_DEV) - 1;
|
||||
if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
to_line += sizeof(_PATH_DEV) - 1;
|
||||
|
||||
return utmp_doclone(from_line, to_line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove (zero out) the utmp entry for a line.
|
||||
*/
|
||||
static int
|
||||
utmp_doremove(const char *line)
|
||||
{
|
||||
int rval = FALSE;
|
||||
#ifdef HAVE_GETUTXID
|
||||
struct utmpx *ut, key;
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
strncpy(key.ut_line, line, sizeof(key.ut_line));
|
||||
setutxent();
|
||||
if ((ut = getutxid(&key)) != NULL) {
|
||||
ut->ut_type = DEAD_PROCESS;
|
||||
(void)gettimeofday(&ut->ut_tv, NULL);
|
||||
if (pututxline(ut) != NULL)
|
||||
rval = TRUE;
|
||||
}
|
||||
endutxent();
|
||||
#elif HAVE_GETUTID
|
||||
struct utmp *ut, key;
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
strncpy(key.ut_line, line, sizeof(key.ut_line));
|
||||
setutent();
|
||||
if ((ut = getutid(&key)) != NULL) {
|
||||
ut->ut_type = DEAD_PROCESS;
|
||||
ut->ut_time = time(NULL);
|
||||
if (pututline(ut) != NULL)
|
||||
rval = TRUE;
|
||||
}
|
||||
endutent();
|
||||
#elif HAVE_LOGIN
|
||||
if (logout(line) != 0)
|
||||
rval = TRUE;
|
||||
#endif /* HAVE_GETUTXID */
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
utmp_remove(const char *line)
|
||||
{
|
||||
/* Strip off /dev/ prefix from to/from line as needed. */
|
||||
if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
line += sizeof(_PATH_DEV) - 1;
|
||||
|
||||
return utmp_doremove(line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup hook for error()/errorx()
|
||||
*/
|
||||
@@ -120,6 +281,7 @@ cleanup(int gotsignal)
|
||||
#ifdef HAVE_SELINUX
|
||||
selinux_restore_tty();
|
||||
#endif
|
||||
utmp_remove(slavename);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,13 +290,28 @@ cleanup(int gotsignal)
|
||||
* and slavename globals.
|
||||
*/
|
||||
void
|
||||
pty_setup(uid_t uid)
|
||||
pty_setup(uid_t uid, const char *tty)
|
||||
{
|
||||
io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
|
||||
if (io_fds[SFD_USERTTY] != -1) {
|
||||
int sfd;
|
||||
|
||||
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.
|
||||
* Temporarily point stdin to the pty slave for the benefit of
|
||||
* legacy utmp handling that uses ttyslot().
|
||||
*/
|
||||
if ((sfd = dup(STDIN_FILENO)) == -1)
|
||||
error(1, "Can't save stdin");
|
||||
if (dup2(io_fds[SFD_SLAVE], STDIN_FILENO) == -1)
|
||||
error(1, "Can't dup2 stdin");
|
||||
utmp_clone(tty, slavename);
|
||||
if (dup2(sfd, STDIN_FILENO) == -1)
|
||||
error(1, "Can't restore stdin");
|
||||
close(sfd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,6 +831,7 @@ pty_close(struct command_status *cstat)
|
||||
}
|
||||
}
|
||||
}
|
||||
utmp_remove(slavename);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user