[PATCH 3/8] Proper session on the terminal line

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Ensure a proper session on the terminal line, that is do a
vhangup() and become the controlling terminal.  After this
determine if the terminal line a virtual console by using
the ioctl TIOCMGET to get the status modem bits of a serial
line which is a invalid argument on a virtual console.

Signed-off-by: Werner Fink <werner@xxxxxxx>
---
 term-utils/agetty.8 |    3 +
 term-utils/agetty.c |  144 +++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 113 insertions(+), 34 deletions(-)

diff --git a/term-utils/agetty.8 b/term-utils/agetty.8
index 21a07a0..d30f7ce 100644
--- a/term-utils/agetty.8
+++ b/term-utils/agetty.8
@@ -172,6 +172,9 @@ Wait for the user or the modem to send a carriage-return or a
 linefeed character before sending the \fI/etc/issue\fP (or other) file
 and the login prompt. Very useful in connection with the \-I option.
 .TP
+\-\-nohangup
+Do not call vhangup() for a virtually hangup of the specified terminal.
+.TP
 \-\-version
 Output version information and exit.
 .TP
diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index 35ef1c2..6ce7abd 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -16,6 +16,7 @@
 #include <termios.h>
 #include <signal.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -28,6 +29,7 @@
 #include <sys/socket.h>
 #include <netdb.h>
 #include <langinfo.h>
+#include <grp.h>
 
 #include "strutils.h"
 #include "nls.h"
@@ -146,6 +148,8 @@ struct options {
 #define F_KEEPSPEED	(1<<9)	/* follow baud rate from kernel */
 #define F_KEEPCFLAGS	(1<<10)	/* reuse c_cflags setup from kernel */
 #define F_EIGHTBITS	(1<<11)	/* Assume 8bit-clean tty */
+#define F_VCONSOLE	(1<<12)	/* This is a virtual console */
+#define F_NOHANGUP	(1<<13)	/* No not call vhangup(2) */
 
 /* Storage for things detected while the login name was read. */
 struct chardata {
@@ -258,11 +262,20 @@ int main(int argc, char **argv)
 		0, 		/* no baud rates known yet */
 		{ 0 }
 	};
+	struct sigaction sa, sa_hup, sa_quit, sa_int;
+	sigset_t set;
 
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags = SA_RESTART;
+	sigemptyset (&sa.sa_mask);
+	sigaction(SIGHUP, &sa, &sa_hup);
+	sigaction(SIGQUIT, &sa, &sa_quit);
+	sigaction(SIGINT, &sa, &sa_int);
+
 #ifdef DEBUGGING
 	dbf = fopen("/dev/ttyp0", "w");
 	for (int i = 1; i < argc; i++)
@@ -272,10 +285,6 @@ int main(int argc, char **argv)
 	/* Parse command-line arguments. */
 	parse_args(argc, argv, &options);
 
-#ifdef __linux__
-	setsid();
-#endif
-
 	/* Update the utmp file. */
 #ifdef	SYSV_STYLE
 	update_utmp(&options);
@@ -286,6 +295,12 @@ int main(int argc, char **argv)
 	/* Open the tty as standard { input, output, error }. */
 	open_tty(options.tty, &termios, &options);
 
+	/* unmask SIGHUP if inherited */
+	sigemptyset(&set);
+	sigaddset(&set, SIGHUP);
+	sigprocmask(SIG_UNBLOCK, &set, NULL);
+	sigaction(SIGHUP, &sa_hup, NULL);
+
 	tcsetpgrp(STDIN_FILENO, getpid());
 	/* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
 	debug("calling termio_init\n");
@@ -295,7 +310,7 @@ int main(int argc, char **argv)
 	if (options.flags & F_INITSTRING) {
 		debug("writing init string\n");
 		safe_write(STDIN_FILENO, options.initstring,
-			       strlen(options.initstring));
+			   strlen(options.initstring));
 	}
 
 	if (!(options.flags & F_LOCAL))
@@ -365,7 +380,8 @@ static void parse_args(int argc, char **argv, struct options *op)
 		VERSION_OPTION = CHAR_MAX + 1,
 		HELP_OPTION
 	};
-	static const struct option longopts[] = {
+	const struct option longopts[] = {
+		{  "nohangup",	     no_argument,  &nipple,  F_NOHANGUP	    },
 		{  "8bits",	     no_argument,	 0,  '8'  },
 		{  "noreset",	     no_argument,	 0,  'c'  },
 		{  "issue-file",     required_argument,  0,  'f'  },
@@ -634,43 +650,101 @@ static void update_utmp(struct options *op)
 /* Set up tty as stdin, stdout & stderr. */
 static void open_tty(char *tty, struct termios *tp, struct options *op)
 {
-	/* Get rid of the present outputs. */
-	close(STDOUT_FILENO);
-	close(STDERR_FILENO);
-	errno = 0;
+	const pid_t pid = getpid();
+	int serial;
 
-	/*
-	 * Set up new standard input, unless we are given an already opened
-	 * port.
-	 */
-	if (strcmp(tty, "-")) {
+	/* Set up new standard input, unless we are given an already opened port. */
+
+	if (strcmp(tty, "-") != 0) {
+		char buf[PATH_MAX+1];
+		struct group *gr = NULL;
 		struct stat st;
+		int fd, len;
+		pid_t tid;
+		gid_t gid = 0;
+
+		/* Use tty group if available */
+		if ((gr = getgrnam("tty")))
+			gid = gr->gr_gid;
+
+		if (((len = snprintf(buf, sizeof(buf), "/dev/%s", tty)) >= (int)sizeof(buf)) || (len < 0))
+			error(_("/dev/%s: cannot open as standard input: %m"), tty);
+
+		/*
+		 * There is always a race between this reset and the call to
+		 * vhangup() that s.o. can use to get access to your tty.
+		 * Linux login(1) will change tty permissions. Use root owner and group
+		 * with permission -rw------- for the period between getty and login.
+		 */
+		if (chown (buf, 0, gid) || chmod (buf, (gid ? 0660 : 0600))) {
+			if (errno == EROFS)
+				warn("%s: %m", buf);
+			else
+				error("%s: %m", buf);
+		}
+
+		/* Open the tty as standard input. */
+		if ((fd = open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0)) < 0)
+			error(_("/dev/%s: cannot open as standard input: %m"), tty);
 
-		/* Sanity checks. */
-		if (chdir("/dev"))
-			error(_("/dev: chdir() failed: %m"));
-		if (stat(tty, &st) < 0)
-			error("/dev/%s: %m", tty);
+		/* Sanity checks... */
+		if (!isatty (fd))
+			error(_("/dev/%s: not a character device"), tty);
+		if (fstat(fd, &st) < 0)
+			error ("%s: %m", buf);
 		if ((st.st_mode & S_IFMT) != S_IFCHR)
 			error(_("/dev/%s: not a character device"), tty);
 
-		/* Open the tty as standard input. */
+		if (((tid = tcgetsid(fd)) < 0) || (pid != tid)) {
+			if (ioctl (fd, TIOCSCTTY, 1) == -1)
+				error("/dev/%s: cannot get controlling tty: %m", tty);
+		}
+
+		if ((op->flags & F_NOHANGUP) == 0) {
+			/*
+			 * vhangup() will replace all open file descriptors in the kernel
+			 * that point to our controlling tty by a dummy that will deny
+			 * further reading/writing to our device. It will also reset the
+			 * tty to sane defaults, so we don't have to modify the tty device
+			 * for sane settings. We also get a SIGHUP/SIGCONT.
+			 */
+			if (vhangup())
+				error("/dev/%s: vhangup() failed: %m", tty);
+			(void)ioctl(fd, TIOCNOTTY);
+		}
+
+		(void) close(fd);
 		close(STDIN_FILENO);
 		errno = 0;
 
 		debug("open(2)\n");
-		if (open(tty, O_RDWR | O_NONBLOCK, 0) != 0)
-			error(_("/dev/%s: cannot open as standard input: %m"),
-			      tty);
+		if (open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0) != 0)
+			error(_("/dev/%s: cannot open as standard input: %m"), tty);
+		if (((tid = tcgetsid(0)) < 0) || (pid != tid)) {
+			if (ioctl (0, TIOCSCTTY, 1) == -1)
+				error("/dev/%s: cannot get controlling tty: %m", tty);
+		}
+
 	} else {
+		
 		/*
 		 * Standard input should already be connected to an open port. Make
 		 * sure it is open for read/write.
 		 */
+
 		if ((fcntl(STDIN_FILENO, F_GETFL, 0) & O_RDWR) != O_RDWR)
 			error(_("%s: not open for read/write"), tty);
+
 	}
 
+	if (tcsetpgrp(STDIN_FILENO, pid))
+		error("/dev/%s: cannot set process group: %m", tty);
+
+	/* Get rid of the present outputs. */
+	close(STDOUT_FILENO);
+	close(STDERR_FILENO);
+	errno = 0;
+
 	/* Set up standard output and standard error file descriptors. */
 	debug("duping\n");
 
@@ -692,12 +766,16 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
 		error("%s: tcgetattr: %m", tty);
 
 	/*
-	 * Linux login(1) will change tty permissions. Use root owner and group
-	 * with permission -rw------- for the period between getty and login.
+	 * Detect if this is a virtual console or serial/modem line.
+	 * In case of a virtual console the ioctl TIOCMGET fails and
+	 * the error number will be set to EINVAL.
 	 */
-	ignore_result(chown(tty, 0, 0));
-	ignore_result(chmod(tty, 0600));
-	errno = 0;
+	if (ioctl(0, TIOCMGET, &serial) < 0 && (errno = EINVAL)) {
+		op->flags |= F_VCONSOLE;
+		if (!op->term)
+			op->term = DEFAULT_VCTERM;
+	} else if (!op->term)
+		op->term = DEFAULT_STERM;
 
 	setenv("TERM", op->term, 1);
 }
@@ -825,17 +903,15 @@ static void do_prompt(struct options *op, struct termios *tp)
 {
 #ifdef	ISSUE
 	FILE *fd;
-	int oflag;
-	int c;
-	struct utsname uts;
-
-	uname(&uts);
 #endif				/* ISSUE */
 
 	/* Issue not in use, start with a new line. */
 	safe_write(STDOUT_FILENO, "\r\n", 2);
+
 #ifdef	ISSUE
 	if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
+		int c, oflag;
+
 		/* Save current setting. */
 		oflag = tp->c_oflag;
 		/* Map new line in output to carriage return & new line. */
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux