[PATCH] agetty: improve login(1) argv[]

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

 



* fix regression: missing username should not be reported (EPERM) if
  -n/--skip-login is given and username is NULL.

* don't compose login options *string* if we can use argv *array* (the
  string is necessary only for --login-options).

* don't overwrite --login-options by --autologin

  The old code silently ignores login-options and "login -f <username>"
  is always used.

  The new code uses:
    a)	"login -f <username>"    by default
    b)	"login <login-options>"  for --login-options + --autologin

  where for b) the username from "--autologin <username>" is used to
  replace \u magic string in <login-options>.

* the \u could be used more then once in one login argv string, for
  example: agetty --login-options "-o user=\\u,name=\\u --foo"

* the space in --login-options is correctly ignored, for example
  agetty --login-options " hello world ".

Signed-off-by: Karel Zak <kzak@xxxxxxxxxx>
---
 term-utils/agetty.8 |   15 +++--
 term-utils/agetty.c |  178 ++++++++++++++++++++++++++++++++-------------------
 2 files changed, 121 insertions(+), 72 deletions(-)

diff --git a/term-utils/agetty.8 b/term-utils/agetty.8
index 4ccb28a..c43f456 100644
--- a/term-utils/agetty.8
+++ b/term-utils/agetty.8
@@ -87,9 +87,11 @@ whatever init(8) may have set, and is inherited by login and the shell.
 Assume that the tty is 8-bit clean, hence disable parity detection.
 .TP
 \-a, \-\-autologin \fIusername\fP
-Log the specified user automatically in without asking for a login
-name and password. Check the \-f option from
-\fB/bin/login\fP for this.
+Log the specified user automatically in without asking for a login name and
+password. The \-f \fIusername\fP option is added to the \fB/bin/login\fP
+command line by default. The \-\-login-options option changes this default
+behaviour and then only \\u is replaced by the \fIusername\fP and no other
+option is added to the login command line.
 .TP
 \-c, \-\-noreset
 Don't reset terminal cflags (control modes). See \fItermios(3)\fP for more
@@ -160,9 +162,10 @@ is run as root.
 .TP
 \-o, \-\-login\-options \fI"login_options"\fP
 Options  that  are passed to the login program.  \\u is replaced
-by the login name. Defaults to "-- \\u", which is suitable for
-\fB/bin/login\fP.  Please read the SECURITY NOTICE below if
-you want to use this.
+by the login name. The default \fB/bin/login\fP command line
+is "/bin/login -- <username>".
+
+Please read the SECURITY NOTICE below if you want to use this.
 .TP
 \-p, \-\-login\-pause
 Wait for any key before dropping to the login prompt.  Can be combined
diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index 203668e..5d5bd62 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -100,7 +100,7 @@
 
 /* Login prompt. */
 #define LOGIN		"login: "
-#define ARRAY_SIZE_MAX	16		/* Numbers of args for login beside "-- \\u" */
+#define LOGIN_ARGV_MAX	16		/* Numbers of args for login */
 
 /* Some shorthands for control characters. */
 #define CTL(x)		(x ^ 0100)	/* Assumes ASCII dialect */
@@ -262,9 +262,8 @@ static void log_err(const char *, ...) __attribute__((__noreturn__))
 static void log_warn (const char *, ...)
 				__attribute__((__format__(printf, 1, 2)));
 static ssize_t append(char *dest, size_t len, const char  *sep, const char *src);
-static void checkname (const char* nm);
-static void replacename (char** arr, const char* nm);
-static void mkarray (char** arr, char* str);
+static void check_username (const char* nm);
+static void login_options_to_argv(char *argv[], int *argc, char *str, char *username);
 
 /* Fake hostname for ut_host specified on command line. */
 static char *fakehost;
@@ -278,19 +277,18 @@ FILE *dbf;
 
 int main(int argc, char **argv)
 {
-	char *logname = NULL;			/* login name, given to /bin/login */
-	char  logcmd[NAME_MAX+1];
-	char *logarr[ARRAY_SIZE_MAX + 2];	/* arguments plus "-- \\u" */
+	char *username = NULL;			/* login name, given to /bin/login */
 	struct chardata chardata;		/* will be set by get_logname() */
 	struct termios termios;			/* terminal mode bits */
 	static struct options options = {
 		.flags  =  F_ISSUE,		/* show /etc/issue (SYSV_STYLE) */
 		.login  =  _PATH_LOGIN,		/* default login program */
-		.logopt = "-- \\u",		/* escape for user name */
 		.tty    = "tty1",		/* default tty line */
 		.term   =  DEFAULT_VCTERM,	/* terminal type */
 		.issue  =  ISSUE		/* default issue file */
 	};
+	char *login_argv[LOGIN_ARGV_MAX + 1];
+	int login_argc = 0;
 	struct sigaction sa, sa_hup, sa_quit, sa_int;
 	sigset_t set;
 
@@ -315,6 +313,8 @@ int main(int argc, char **argv)
 	/* Parse command-line arguments. */
 	parse_args(argc, argv, &options);
 
+	login_argv[login_argc++] = options.login;	/* set login program name */
+
 	/* Update the utmp file. */
 #ifdef	SYSV_STYLE
 	update_utmp(&options);
@@ -379,16 +379,15 @@ int main(int argc, char **argv)
 	chardata = init_chardata;
 	if ((options.flags & F_NOPROMPT) == 0) {
 		if (options.autolog) {
-			/* Do the auto login */
+			/* Do the auto login. */
 			debug("doing auto login\n");
 			do_prompt(&options, &termios);
 			printf("%s%s (automatic login)\n", LOGIN, options.autolog);
-			logname = options.autolog;
-			options.logopt = "-f \\u";
+			username = options.autolog;
 		} else {
 			/* Read the login name. */
 			debug("reading login name\n");
-			while ((logname =
+			while ((username =
 				get_logname(&options, &termios, &chardata)) == 0)
 				if ((options.flags & F_VCONSOLE) == 0)
 					next_speed(&options, &termios);
@@ -410,13 +409,25 @@ int main(int argc, char **argv)
 	sigaction(SIGQUIT, &sa_quit, NULL);
 	sigaction(SIGINT, &sa_int, NULL);
 
-	*logcmd = '\0';
-	append(logcmd, sizeof(logcmd), NULL, options.login);
-	append(logcmd, sizeof(logcmd), " ", options.logopt);
+	if (username)
+		check_username(username);
+
+	if (options.logopt) {
+		/*
+		 * The --login-options completely overwrites the default
+		 * way how aggety composes login(1) command line.
+		 */
+		login_options_to_argv(login_argv, &login_argc,
+				      options.logopt, username);
+	} else if (username) {
+		if (options.autolog)
+			login_argv[login_argc++] = "-f";
+		else
+			login_argv[login_argc++] = "--";
+		login_argv[login_argc++] = username;
+	}
 
-	checkname(logname);
-	mkarray(logarr, logcmd);
-	replacename(logarr, logname);
+	login_argv[login_argc] = NULL;	/* last login argv */
 
 	if (options.chroot) {
 		if (chroot(options.chroot) < 0)
@@ -435,8 +446,87 @@ int main(int argc, char **argv)
 	}
 
 	/* Let the login program take care of password validation. */
-	execv(options.login, logarr);
-	log_err(_("%s: can't exec %s: %m"), options.tty, options.login);
+	execv(options.login, login_argv);
+	log_err(_("%s: can't exec %s: %m"), options.tty, login_argv[0]);
+}
+
+/*
+ * Returns : @str if \u not found
+ *         : @username if @str equal to "\u"
+ *         : newly allocated string if \u mixed with something other
+ */
+static char *replace_u(char *str, char *username)
+{
+	char *entry = NULL, *p = str;
+	size_t usz = username ? strlen(username) : 0;
+
+	while (*p) {
+		size_t sz;
+		char *tp, *old = entry;
+
+		if (memcmp(p, "\\u", 2)) {
+			p++;
+			continue;	/* no \u */
+		}
+		sz = strlen(str);
+
+		if (p == str && sz == 2)
+			/* 'str' contains only '\u' */
+			return username;
+
+		tp = entry = malloc(sz + usz);
+		if (!tp)
+			log_err(_("failed to allocate memory: %m"));
+
+		if (p != str) {
+			/* copy chars befor \u */
+			memcpy(tp, str, p - str);
+			tp += p - str;
+		}
+		if (usz) {
+			/* copy username */
+			memcpy(tp, username, usz);
+			tp += usz;
+		}
+		if (*(p + 2))
+			/* copy chars after \u + \0 */
+			memcpy(tp, p + 2, sz - (p - str) - 1);
+		else
+			*tp = '\0';
+
+		p = tp;
+		str = entry;
+		free(old);
+	}
+
+	return entry ? entry : str;
+}
+
+static void login_options_to_argv(char *argv[], int *argc,
+				  char *str, char *username)
+{
+	char *p;
+	int i = *argc;
+
+	while (str && isspace(*str))
+		str++;
+	p = str;
+
+	while (p && *p && i < LOGIN_ARGV_MAX) {
+		if (isspace(*p)) {
+			*p = '\0';
+			while (isspace(*++p))
+				;
+			if (*p) {
+				argv[i++] = replace_u(str, username);
+				str = p;
+			}
+		} else
+			p++;
+	}
+	if (str && *str && i < LOGIN_ARGV_MAX)
+		argv[i++] = replace_u(str, username);
+	*argc = i;
 }
 
 /* Parse command-line arguments. */
@@ -1832,12 +1922,13 @@ static ssize_t append(char *dest, size_t len, const char  *sep, const char *src)
 
 	return dsz + ssz + sz;
 }
+
 /*
  * Do not allow the user to pass an option as a user name
  * To be more safe: Use `--' to make sure the rest is
  * interpreted as non-options by the program, if it supports it.
  */
-static void checkname(const char* nm)
+static void check_username(const char* nm)
 {
 	const char *p = nm;
 	if (!nm)
@@ -1854,48 +1945,3 @@ err:
 	log_err("checkname: %m");
 }
 
-static void replacename(char** arr, const char* nm)
-{
-	const char *p;
-	char *tmp;
-	while ((p = *arr)) {
-		const char *p1 = p;
-		while (*p1) {
-			if (memcmp(p1, "\\u", 2) == 0) {
-				tmp = malloc(strlen(p) + strlen(nm));
-				if (!tmp)
-					log_err(_("failed to allocate memory: %m"));
-				if (p1 != p)
-					memcpy(tmp, p, (p1 - p));
-				*(tmp + (p1 - p)) = 0;
-				strcat(tmp, nm);
-				strcat(tmp, p1+2);
-				*arr = tmp;
-			}
-			p1++;
-		}
-		arr++;
-	}
-}
-
-static void mkarray(char** arr, char* str)
-{
-	char* p = str;
-	char* start = p;
-	int i = 0;
-
-	while (*p && i < ARRAY_SIZE_MAX) {
-		if (isspace(*p)) {
-			*p = 0;
-			while (isspace(*++p))
-				;
-			if (*p) {
-				arr[i++] = start;
-				start = p;
-			}
-		} else
-			p++;
-	}
-	arr[i++] = start;
-	arr[i++] = (char*) 0;
-}
-- 
1.7.6

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