bin/61355: login(1) does not restore terminal ownership on exit
Dorr H. Clark
dclark at applmath.scu.edu
Wed May 12 10:50:12 PDT 2004
The following reply was made to PR bin/61355; it has been noted by GNATS.
From: "Dorr H. Clark" <dclark at applmath.scu.edu>
To: freebsd-gnats-submit at FreeBSD.org, eugen at kuzbass.ru
Cc:
Subject: Re: bin/61355: login(1) does not restore terminal ownership on exit
Date: Wed, 12 May 2004 10:45:47 -0700
The fix is presented:
--- ../login_bak/login.c Fri Apr 25 19:51:03 2003
+++ ./login.c Sun May 2 04:16:06 2004
@@ -82,6 +82,9 @@
#include "login.h"
#include "pathnames.h"
+#include <sys/types.h>
+#include <utmp.h>
+
static int auth_pam(void);
static void bail(int, int);
static int export(const char *);
@@ -172,7 +175,16 @@
const char *shell = NULL;
login_cap_t *lc = NULL;
pid_t pid;
+ gid_t curr_gid;
+ char* login;
+ struct ttyent *tyTmp;
+ int fdAlt;
+ int ttyAlt;
+ struct utmp ut;
+ unsigned short int found_ut = 0;
+ FILE* utFile;
+
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGHUP, SIG_IGN);
@@ -230,6 +242,9 @@
setproctitle("-%s", getprogname());
+ curr_gid = getgid();
+ login = getlogin();
+
for (cnt = getdtablesize(); cnt > 2; cnt--)
(void)close(cnt);
@@ -246,6 +261,28 @@
else
tty = ttyn;
+ /* set the current login's information so that we can come back to
it when the new user logs out*/
+ if ((utFile = fopen(_PATH_UTMP, "r")) == NULL)
+ syslog(LOG_ERR, "failed opening (%s): may not be able to
reset user properly", _PATH_UTMP);
+ if(utFile)
+ {
+ while(fread(&ut, sizeof(ut), 1, utFile))
+ {
+ if(!strcmp(ut.ut_line, tty))
+ {
+ found_ut = 1;
+ break;
+ }
+ }
+ if(!found_ut)
+ {
+ strncpy(ut.ut_line, tty, UT_LINESIZE);
+ strncpy(ut.ut_name, login, UT_NAMESIZE);
+ strncpy(ut.ut_host, "", UT_HOSTSIZE);
+ ut.ut_time = 0;
+ }
+ (void)fclose(utFile);
+ }
/*
* Get "login-retries" & "login-backoff" from default class
*/
@@ -509,6 +546,40 @@
int status;
setproctitle("-%s [pam]", getprogname());
waitpid(pid, &status, 0);
+ pam_cleanup();
+
+ /*now change the login back to the original user*/
+ //set the tty devices back to the original owner
+ if (ttyn != tname && chflags(ttyn, 0)) if (errno != EOPNOTSUPP
&& errno != EROFS)
+ {
+ syslog(LOG_ERR, "chflags(%s): %m", ttyn);
+ printf("chflags(%s): %m", ttyn);
+ }
+ if (ttyn != tname && chown(ttyn, uid, (gr =
getgrnam(TTYGRPNAME)) ? gr->gr_gid : curr_gid))
+ {
+ if (errno != EROFS)
+ {
+ syslog(LOG_ERR, "chown(%s): %m", ttyn);
+ printf("chown(%s): %m", ttyn);
+ }
+ }
+
+ /* set the tty session */
+ setttyent();
+ for (ttyAlt = 1; (tyTmp = getttyent()) != NULL; ++ttyAlt)
+ if (strcmp(tyTmp->ty_name, ut.ut_line) == 0)
+ break;
+ endttyent();
+ if (ttyAlt > 0 && (fdAlt = open(_PATH_UTMP, O_WRONLY|O_CREAT,
0644)) >= 0)
+ {
+ (void)lseek(fdAlt, (off_t)(ttyAlt * sizeof(struct utmp)),
L_SET);
+ (void)write(fdAlt, &ut, sizeof(struct utmp));
+ (void)close(fdAlt);
+ }
+
+ /*set the login back to the initial user*/
+ setlogin(login);
+
bail(NO_SLEEP_EXIT, 0);
}
This bug occurs when a user session is launched
through the "login" binary at a shell prompt
and then terminated, the system persists in
tracking the tty ownership as the departed user
(who has already logged off).
To fix the problem, we maintain the original loginid
and set that to be the owner of the tty, using the utmp
structure as tracked in the file /var/run/utmp
so when the login session exits the original owner
of the tty is restored.
This fix should be evaluated carefully for potential
exploits, although this risk can be balanced against
the fact that the bug itself represents a security issue.
Anirban Kundu, Engineer
Dorr H. Clark, Advisor,
Graduate School of Engineering
Santa Clara University
More information about the freebsd-bugs
mailing list