--- Makefile | 3 ++ st.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8fc9674..8680e04 100644 --- a/Makefile +++ b/Makefile _AT_@ -5,6 +5,7 @@ include config.mk SRC = st.c OBJ = ${SRC:.c=.o} +GROUP = utmp all: options st _AT_@ -44,6 +45,8 @@ install: all _AT_mkdir -p ${DESTDIR}${PREFIX}/bin _AT_cp -f st ${DESTDIR}${PREFIX}/bin _AT_chmod 755 ${DESTDIR}${PREFIX}/bin/st + _AT_chgrp $(GROUP) ${DESTDIR}${PREFIX}/bin/st + _AT_chmod g+s ${DESTDIR}${PREFIX}/bin/st _AT_echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 _AT_mkdir -p ${DESTDIR}${MANPREFIX}/man1 _AT_sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1 diff --git a/st.c b/st.c index 46db942..8641a7a 100644 --- a/st.c +++ b/st.c _AT_@ -1,8 +1,10 @@ /* See LICENSE for licence details. */ #define _XOPEN_SOURCE 600 +#define _POSIX_SAVED_IDS #include <ctype.h> #include <errno.h> #include <fcntl.h> +#include <grp.h> #include <limits.h> #include <locale.h> #include <pwd.h> _AT_@ -19,6 +21,7 @@ #include <sys/types.h> #include <sys/wait.h> #include <time.h> +#include <utmpx.h> #include <unistd.h> #include <X11/Xatom.h> #include <X11/Xlib.h> _AT_@ -266,6 +269,9 @@ static void initenv(void); static void execsh(void); static void sigchld(int); static void run(void); +static void delutmp(void); +static void addutmp(int); +static struct utmpx *findutmp(int); static void csidump(void); static void csihandle(void); _AT_@ -374,6 +380,9 @@ static STREscape strescseq; static int cmdfd; static pid_t pid; static Selection sel; +static gid_t egid, gid; +struct utmpx utmp; +struct passwd *pass; static int iofd = -1; static char **opt_cmd = NULL; static char *opt_io = NULL; _AT_@ -900,6 +909,7 @@ void sigchld(int a) { int stat = 0; + delutmp(); if(waitpid(pid, &stat, 0) < 0) die("Waiting for pid %hd failed: %s\n", pid, SERRNO); _AT_@ -910,14 +920,86 @@ sigchld(int a) { } } + +/* + * From utmp(5) + * xterm and other terminal emulators directly create a USER_PROCESS + * record and generate the ut_id by using the string that suffix part of + * the terminal name (the characters following /dev/[pt]ty). If they find + * a DEAD_PROCESS for this ID, they recycle it, otherwise they create a new + * entry. If they can, they will mark it as DEAD_PROCESS on exiting and it + * is advised that they null ut_line, ut_time, ut_user, and ut_host as well. +*/ + +struct utmpx * +findutmp(int type) { + struct utmpx *r; + + utmp.ut_type = type; + setutxent(); + for(;;) { + /* + * we can not use getutxline because we can search in + * DEAD_PROCESS to + */ + if(!(r = getutxid(&utmp))) + break; + if(!strcmp(r->ut_line, utmp.ut_line)) + break; + memset(r, 0, sizeof(*r)); /* for Solaris, IRIX64 and HPUX */ + } + return r; +} + +void +addutmp(int fd) { + uint id; + char *pts = ptsname(fd), *cp, buf[5] = {'x'}; + + for(cp = pts + strlen(pts) - 1; isdigit(*cp); --cp) + /* nothing */; + if((id = atoi(++cp)) > 999 || strlen(pts + 5) > sizeof(utmp.ut_line)) + die("Incorrect pts name %s\n", pts); + sprintf(buf + 1, "%03d", id); + strncpy(utmp.ut_id, buf, 4); + strcpy(utmp.ut_line, pts + 5); /* remove /dev/ part of the string */ + + if(!findutmp(DEAD_PROCESS)) + findutmp(USER_PROCESS); + + utmp.ut_type = USER_PROCESS; + strcpy(utmp.ut_user, pass->pw_name); + utmp.ut_pid = pid; + utmp.ut_tv.tv_sec = time(NULL); + utmp.ut_tv.tv_usec = 0; + /* don't use no standard fields host and session */ + + setgid(egid); + if(!pututxline(&utmp)) + perror("add utmp entry"); + setgid(gid); + endutxent(); +} + +void +delutmp(void) { + struct utmpx *r; + + setutxent(); + if((r = getutxline(&utmp)) != NULL) { + r->ut_type = DEAD_PROCESS; + r->ut_tv.tv_usec = r->ut_tv.tv_sec = 0; + setgid(egid); + pututxline(r); + setgid(gid); + } + endutxent(); +} + void initenv(void) { - const struct passwd *pass = getpwuid(getuid()); char buff[sizeof(long) * 8]; - if(!pass) - die("Process is running with an incorrect uid\n"); - unsetenv("COLUMNS"); unsetenv("LINES"); unsetenv("TERMCAP"); _AT_@ -943,7 +1025,13 @@ void ttynew(void) { int m, s; struct winsize w = {term.row, term.col, 0, 0}; + uid_t id = getuid(); + pass = getpwuid(id); + if(!pass || !pass->pw_name || + strlen(pass->pw_name) + 1 > sizeof(utmp.ut_user)) { + die("Process is running with an incorrect uid %d\n", id); + } /* seems to work fine on linux, openbsd and freebsd */ if(openpty(&m, &s, NULL, NULL, &w) < 0) die("openpty failed: %s\n", SERRNO); _AT_@ -967,6 +1055,7 @@ ttynew(void) { default: close(s); cmdfd = m; + addutmp(cmdfd); signal(SIGCHLD, sigchld); if(opt_io) { iofd = (!strcmp(opt_io, "-")) ? _AT_@ -2761,6 +2850,9 @@ main(int argc, char *argv[]) { int i, bitm, xr, yr; uint wr, hr; + egid = getegid(); + gid = getgid(); + setgid(gid); xw.fw = xw.fh = xw.fx = xw.fy = 0; xw.isfixed = False; -- 1.7.10.4 --Fba/0zbH8Xs+Fj9o--Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Tue Oct 09 2012 - 19:00:07 CEST