From 81bc0a21dc77c35b054359e0c04817268fea7a1e Mon Sep 17 00:00:00 2001 From: Dan Cross Date: Wed, 13 Jan 2021 23:55:47 +0000 Subject: [PATCH] talkd: Find users in more than one talk request. talkd was written to use `utmpentry` from `who`, which caches the results of read the `utmpx` file. However, talkd is usually invoked from inetd `wait` mode; it's possible that a user might login after `talkd` starts; with the cached utmpx data, one can't `talk` to that user. Further, consumption of the utmp data nulls it out for subsequent requests. The result is that the first talk succeeds, but subsequent requests fail. The fix is to avoid using the `utmpentry` machinery, and just read `utmp` directly every time we need to. Signed-off-by: Dan Cross --- libexec/talkd/Makefile | 5 ++-- libexec/talkd/extern.h | 2 +- libexec/talkd/process.c | 65 ++++++++++++++++++++++------------------- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/libexec/talkd/Makefile b/libexec/talkd/Makefile index 91b8a1ea79..ad6440e429 100644 --- a/libexec/talkd/Makefile +++ b/libexec/talkd/Makefile @@ -1,16 +1,15 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 # $FreeBSD: src/libexec/talkd/Makefile,v 1.6.2.2 2001/10/18 12:30:42 des Exp $ -.PATH: ${.CURDIR}/../../usr.bin/wall ${.CURDIR}/../../usr.bin/who +.PATH: ${.CURDIR}/../../usr.bin/wall PROG= ntalkd -SRCS= talkd.c announce.c process.c table.c print.c ttymsg.c utmpentry.c +SRCS= talkd.c announce.c process.c table.c print.c ttymsg.c MAN= talkd.8 DPADD= ${LIBUTIL} LDADD= -lutil CFLAGS+=-I${.CURDIR}/../../usr.bin/wall -CFLAGS+=-I${.CURDIR}/../../usr.bin/who .include diff --git a/libexec/talkd/extern.h b/libexec/talkd/extern.h index 015ae6b692..d3c2b31102 100644 --- a/libexec/talkd/extern.h +++ b/libexec/talkd/extern.h @@ -30,7 +30,7 @@ int delete_invite(unsigned int); void do_announce(CTL_MSG *, CTL_RESPONSE *); CTL_MSG *find_match(CTL_MSG *request); CTL_MSG *find_request(CTL_MSG *request); -int find_user(const char *name, char *tty); +int find_user(const char *name, char *tty, size_t ttylen); void insert_table(CTL_MSG *, CTL_RESPONSE *); int new_id(void); int print_mesg(const char *, CTL_MSG *, const char *); diff --git a/libexec/talkd/process.c b/libexec/talkd/process.c index 1be86379e2..c444bba136 100644 --- a/libexec/talkd/process.c +++ b/libexec/talkd/process.c @@ -50,7 +50,7 @@ #include #include #include -#include "utmpentry.h" +#include #include "extern.h" @@ -140,7 +140,7 @@ do_announce(CTL_MSG *mp, CTL_RESPONSE *rp) int result; /* see if the user is logged */ - result = find_user(mp->r_name, mp->r_tty); + result = find_user(mp->r_name, mp->r_tty, sizeof(mp->r_tty)); if (result != SUCCESS) { rp->answer = result; return; @@ -177,43 +177,48 @@ do_announce(CTL_MSG *mp, CTL_RESPONSE *rp) * Search utmpx for the local user */ int -find_user(const char *name, char *tty) +find_user(const char *name, char *tty, size_t ttylen) { - struct utmpentry *ep = NULL; /* avoid gcc warnings */ + struct utmpx *ut; /* avoid gcc warnings */ int status; struct stat statb; - time_t best = 0; - char ftty[sizeof(_PATH_DEV) + sizeof(ep->line)]; + time_t best; + char ftty[sizeof(_PATH_DEV) + _UTX_LINESIZE]; - getutentries(NULL, &ep); + if (ttylen > sizeof(ftty)) + ttylen = sizeof(ftty); -#define SCMPN(a, b) strncmp(a, b, sizeof (a)) + best = 0; status = NOT_HERE; - (void) strcpy(ftty, _PATH_DEV); - for (; ep; ep = ep->next) - if (SCMPN(ep->name, name) == 0) { - if (*tty == '\0' || best != 0) { - if (best == 0) - status = PERMISSION_DENIED; - /* no particular tty was requested */ - (void) strcpy(ftty + sizeof(_PATH_DEV) - 1, - ep->line); - if (stat(ftty, &statb) == 0) { - if (!(statb.st_mode & 020)) - continue; - if (statb.st_atime > best) { - best = statb.st_atime; - (void) strcpy(tty, ep->line); - status = SUCCESS; - continue; - } + strlcpy(ftty, _PATH_DEV, sizeof(ftty)); + setutxent(); + while ((ut = getutxent()) != NULL) { + if (ut->ut_type != USER_PROCESS) + continue; + if (strncmp(ut->ut_name, name, sizeof(ut->ut_name)) != 0) + continue; + if (*tty == '\0' || best != 0) { + if (best == 0) + status = PERMISSION_DENIED; + /* no particular tty was requested */ + strlcat(ftty, ut->ut_line, sizeof(ftty)); + if (stat(ftty, &statb) == 0) { + if (!(statb.st_mode & 020)) + continue; + if (statb.st_atime > best) { + best = statb.st_atime; + strlcpy(tty, ut->ut_line, ttylen); + status = SUCCESS; + continue; } } - if (strcmp(ep->line, tty) == 0) { - status = SUCCESS; - break; - } } + if (strcmp(ut->ut_line, tty) == 0) { + status = SUCCESS; + break; + } + } + endutxent(); return (status); } -- 2.28.0