---
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