1 /*
2  * sulogin
3  *
4  * This program gives Linux machines a reasonable secure way to boot single
5  * user. It forces the user to supply the root password before a shell is
6  * started. If there is a shadow password file and the encrypted root password
7  * is "x" the shadow password will be used.
8  *
9  * Copyright (C) 1998-2003 Miquel van Smoorenburg.
10  * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
11  * Copyright (C) 2012 Werner Fink <werner@suse.de>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26  */
27 #include <sys/mman.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <pwd.h>
38 #include <shadow.h>
39 #include <termios.h>
40 #include <errno.h>
41 #include <getopt.h>
42 #include <sys/ioctl.h>
43 #ifdef HAVE_CRYPT_H
44 # include <crypt.h>
45 #endif
46 
47 #ifdef HAVE_LIBSELINUX
48 # include <selinux/selinux.h>
49 # include <selinux/get_context_list.h>
50 #endif
51 
52 #ifdef __linux__
53 # include <sys/kd.h>
54 # include <sys/param.h>
55 #endif
56 
57 #include "c.h"
58 #include "closestream.h"
59 #include "env.h"
60 #include "nls.h"
61 #include "pathnames.h"
62 #ifdef USE_PLYMOUTH_SUPPORT
63 # include "plymouth-ctrl.h"
64 #endif
65 #include "strutils.h"
66 #include "ttyutils.h"
67 #include "sulogin-consoles.h"
68 #define CONMAX		16
69 
70 static unsigned int timeout;
71 static int profile;
72 static volatile uint32_t openfd;		/* Remember higher file descriptors */
73 
74 static struct sigaction saved_sigint;
75 static struct sigaction saved_sigtstp;
76 static struct sigaction saved_sigquit;
77 static struct sigaction saved_sighup;
78 static struct sigaction saved_sigchld;
79 
80 static volatile sig_atomic_t alarm_rised;
81 static volatile sig_atomic_t sigchild;
82 
83 #ifndef IUCLC
84 # define IUCLC		0
85 #endif
86 
87 #ifndef WEXITED
88 # warning "WEXITED is missing, sulogin may not work as expected"
89 # define WEXITED 0
90 #endif
91 
locked_account_password(const char * const passwd)92 static int locked_account_password(const char * const passwd)
93 {
94 	if (passwd && (*passwd == '*' || *passwd == '!'))
95 		return 1;
96 	return 0;
97 }
98 
99 /*
100  * Fix the tty modes and set reasonable defaults.
101  */
tcinit(struct console * con)102 static void tcinit(struct console *con)
103 {
104 	int flags = 0, mode = 0;
105 	struct termios *tio = &con->tio;
106 	const int fd = con->fd;
107 #ifdef USE_PLYMOUTH_SUPPORT
108 	struct termios lock;
109 	int i = (plymouth_command(MAGIC_PING)) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
110 	if (i)
111 		plymouth_command(MAGIC_QUIT);
112 	while (i-- > 0) {
113 		/*
114 		 * With plymouth the termios flags become changed after this
115 		 * function had changed the termios.
116 		 */
117 		memset(&lock, 0, sizeof(struct termios));
118 		if (ioctl(fd, TIOCGLCKTRMIOS, &lock) < 0)
119 			break;
120 		if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
121 			break;
122 		sleep(1);
123 	}
124 	memset(&lock, 0, sizeof(struct termios));
125 	ioctl(fd, TIOCSLCKTRMIOS, &lock);
126 #endif
127 	errno = 0;
128 
129 	if (tcgetattr(fd, tio) < 0) {
130 		warn(_("tcgetattr failed"));
131 		con->flags |= CON_NOTTY;
132 		return;
133 	}
134 
135 	/* Handle lines other than virtual consoles here */
136 #if defined(KDGKBMODE)
137 	if (ioctl(fd, KDGKBMODE, &mode) < 0)
138 #endif
139 	{
140 		speed_t ispeed, ospeed;
141 		struct winsize ws;
142 		errno = 0;
143 
144 		/* this is a modem line */
145 		con->flags |= CON_SERIAL;
146 
147 		/* Flush input and output queues on modem lines */
148 		tcflush(fd, TCIOFLUSH);
149 
150 		ispeed = cfgetispeed(tio);
151 		ospeed = cfgetospeed(tio);
152 
153 		if (!ispeed) ispeed = TTYDEF_SPEED;
154 		if (!ospeed) ospeed = TTYDEF_SPEED;
155 
156 		tio->c_cflag = CREAD | CS8 | HUPCL | (tio->c_cflag & CLOCAL);
157 		tio->c_iflag = 0;
158 		tio->c_lflag = 0;
159 		tio->c_oflag &= OPOST | ONLCR;
160 
161 		cfsetispeed(tio, ispeed);
162 		cfsetospeed(tio, ospeed);
163 
164 #ifdef HAVE_STRUCT_TERMIOS_C_LINE
165 		tio->c_line         = 0;
166 #endif
167 		tio->c_cc[VTIME]    = 0;
168 		tio->c_cc[VMIN]     = 1;
169 
170 		if (ioctl(fd, TIOCGWINSZ, &ws) == 0) {
171 			int update = 0;
172 
173 			if (ws.ws_row == 0) {
174 				ws.ws_row = 24;
175 				update++;
176 			}
177 			if (ws.ws_col == 0) {
178 				ws.ws_col = 80;
179 				update++;
180 			}
181 			if (update)
182 				ignore_result( ioctl(fd, TIOCSWINSZ, &ws) );
183 		}
184 
185 		setlocale(LC_CTYPE, "POSIX");
186 		goto setattr;
187 	}
188 #if defined(IUTF8) && defined(KDGKBMODE)
189 	/* Handle mode of current keyboard setup, e.g. for UTF-8 */
190 	switch(mode) {
191 	case K_UNICODE:
192 		setlocale(LC_CTYPE, "C.UTF-8");
193 		flags |= UL_TTY_UTF8;
194 		break;
195 	case K_RAW:
196 	case K_MEDIUMRAW:
197 	case K_XLATE:
198 	default:
199 		setlocale(LC_CTYPE, "POSIX");
200 		break;
201 	}
202 #else
203 	setlocale(LC_CTYPE, "POSIX");
204 #endif
205 	reset_virtual_console(tio, flags);
206 setattr:
207 	if (tcsetattr(fd, TCSANOW, tio))
208 		warn(_("tcsetattr failed"));
209 
210 	/* Enable blocking mode for read and write */
211 	if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
212 		ignore_result( fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) );
213 }
214 
215 /*
216  * Finalize the tty modes on modem lines.
217  */
tcfinal(struct console * con)218 static void tcfinal(struct console *con)
219 {
220 	struct termios *tio = &con->tio;
221 	const int fd = con->fd;
222 
223 	if ((con->flags & CON_SERIAL) == 0) {
224 		xsetenv("TERM", "linux", 1);
225 		return;
226 	}
227 	if (con->flags & CON_NOTTY) {
228 		xsetenv("TERM", "dumb", 1);
229 		return;
230 	}
231 
232 #if defined (__s390__) || defined (__s390x__)
233 	xsetenv("TERM", "dumb", 1);
234 #else
235 	xsetenv("TERM", "vt102", 1);
236 #endif
237 	tio->c_iflag |= (IXON | IXOFF);
238 	tio->c_lflag |= (ICANON | ISIG | ECHO|ECHOE|ECHOK|ECHOKE);
239 	tio->c_oflag |= OPOST;
240 
241 	tio->c_cc[VINTR]    = CINTR;
242 	tio->c_cc[VQUIT]    = CQUIT;
243 	tio->c_cc[VERASE]   = con->cp.erase;
244 	tio->c_cc[VKILL]    = con->cp.kill;
245 	tio->c_cc[VEOF]     = CEOF;
246 #ifdef VSWTC
247 	tio->c_cc[VSWTC]    = _POSIX_VDISABLE;
248 #elif defined(VSWTCH)
249 	tio->c_cc[VSWTCH]   = _POSIX_VDISABLE;
250 #endif
251 	tio->c_cc[VSTART]   = CSTART;
252 	tio->c_cc[VSTOP]    = CSTOP;
253 	tio->c_cc[VSUSP]    = CSUSP;
254 	tio->c_cc[VEOL]     = _POSIX_VDISABLE;
255 
256 	if (con->cp.eol == CR) {
257 		tio->c_iflag |= ICRNL;
258 		tio->c_iflag &= ~(INLCR|IGNCR);
259 		tio->c_oflag |= ONLCR;
260 		tio->c_oflag &= ~(OCRNL|ONLRET);
261 	}
262 
263 	switch (con->cp.parity) {
264 	default:
265 	case 0:
266 		tio->c_cflag &= ~(PARODD | PARENB);
267 		tio->c_iflag &= ~(INPCK | ISTRIP);
268 		break;
269 	case 1:				/* odd parity */
270 		tio->c_cflag |= PARODD;
271 		/* fallthrough */
272 	case 2:				/* even parity */
273 		tio->c_cflag |= PARENB;
274 		tio->c_iflag |= (INPCK | ISTRIP);
275 		/* fallthrough */
276 	case (1 | 2):			/* no parity bit */
277 		tio->c_cflag &= ~CSIZE;
278 		tio->c_cflag |= CS7;
279 		break;
280 	}
281 
282 	/* Set line attributes */
283 	tcsetattr(fd, TCSANOW, tio);
284 }
285 
286 /*
287  * Called at timeout.
288  */
alrm_handler(int sig)289 static void alrm_handler(int sig __attribute__((unused)))
290 {
291 	/* Timeout expired */
292 	alarm_rised++;
293 }
294 
chld_handler(int sig)295 static void chld_handler(int sig __attribute__((unused)))
296 {
297 	sigchild++;
298 }
299 
mask_signal(int signal,void (* handler)(int),struct sigaction * origaction)300 static void mask_signal(int signal, void (*handler)(int),
301 		struct sigaction *origaction)
302 {
303 	struct sigaction newaction;
304 
305 	newaction.sa_handler = handler;
306 	sigemptyset(&newaction.sa_mask);
307 	newaction.sa_flags = 0;
308 
309 	sigaction(signal, &newaction, origaction);
310 }
311 
unmask_signal(int signal,struct sigaction * sa)312 static void unmask_signal(int signal, struct sigaction *sa)
313 {
314 	sigaction(signal, sa, NULL);
315 }
316 
317 /*
318  * See if an encrypted password is valid. The encrypted password is checked for
319  * traditional-style DES and FreeBSD-style MD5 encryption.
320  */
valid(const char * pass)321 static int valid(const char *pass)
322 {
323 	const char *s;
324 	char id[5];
325 	size_t len;
326 	off_t off;
327 
328 	if (pass[0] == 0)
329 		return 1;
330 	if (pass[0] != '$')
331 		goto check_des;
332 
333 	/*
334 	 * up to 4 bytes for the signature e.g. $1$
335 	 */
336 	for (s = pass+1; *s && *s != '$'; s++);
337 
338 	if (*s++ != '$')
339 		return 0;
340 
341 	if ((off = (off_t)(s-pass)) > 4 || off < 3)
342 		return 0;
343 
344 	memset(id, '\0', sizeof(id));
345 	strncpy(id, pass, off);
346 
347 	/*
348 	 * up to 16 bytes for the salt
349 	 */
350 	for (; *s && *s != '$'; s++);
351 
352 	if (*s++ != '$')
353 		return 0;
354 
355 	if ((off_t)(s-pass) > 16)
356 		return 0;
357 
358 	len = strlen(s);
359 
360 	/*
361 	 * the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
362 	 */
363 	if ((strcmp(id, "$1$") == 0) && (len < 22 || len > 24))
364 		return 0;
365 
366 	/*
367 	 * the SHA-256 hash 43 bytes
368 	 */
369 	if ((strcmp(id, "$5$") == 0) && (len < 42 || len > 44))
370 		return 0;
371 
372 	/*
373 	 * the SHA-512 hash 86 bytes
374 	 */
375 	if ((strcmp(id, "$6$") == 0) && (len < 85 || len > 87))
376 		return 0;
377 
378 	/*
379 	 * e.g. Blowfish hash
380 	 */
381 	return 1;
382 check_des:
383 	if (strlen(pass) != 13)
384 		return 0;
385 
386 	for (s = pass; *s; s++) {
387 		if ((*s < '0' || *s > '9') &&
388 		    (*s < 'a' || *s > 'z') &&
389 		    (*s < 'A' || *s > 'Z') &&
390 		    *s != '.' && *s != '/')
391 			return 0;
392 	}
393 	return 1;
394 }
395 
396 /*
397  * Set a variable if the value is not NULL.
398  */
set(char ** var,char * val)399 static inline void set(char **var, char *val)
400 {
401 	if (val)
402 		*var = val;
403 }
404 
405 /*
406  * Get the root password entry.
407  */
getrootpwent(int try_manually)408 static struct passwd *getrootpwent(int try_manually)
409 {
410 	static struct passwd pwd;
411 	struct passwd *pw;
412 	struct spwd *spw;
413 	FILE *fp;
414 	static char line[2 * BUFSIZ];
415 	static char sline[2 * BUFSIZ];
416 	char *p;
417 
418 	/*
419 	 * First, we try to get the password the standard way using normal
420 	 * library calls.
421 	 */
422 	if ((pw = getpwnam("root")) &&
423 	    !strcmp(pw->pw_passwd, "x") &&
424 	    (spw = getspnam("root")))
425 		pw->pw_passwd = spw->sp_pwdp;
426 
427 	if (pw || !try_manually)
428 		return pw;
429 
430 	/*
431 	 * If we come here, we could not retrieve the root password through
432 	 * library calls and we try to read the password and shadow files
433 	 * manually.
434 	 */
435 	pwd.pw_name = "root";
436 	pwd.pw_passwd = "";
437 	pwd.pw_gecos = "Super User";
438 	pwd.pw_dir = "/";
439 	pwd.pw_shell = "";
440 	pwd.pw_uid = 0;
441 	pwd.pw_gid = 0;
442 
443 	if ((fp = fopen(_PATH_PASSWD, "r")) == NULL) {
444 		warn(_("cannot open %s"), _PATH_PASSWD);
445 		return &pwd;
446 	}
447 
448 	/*
449 	 * Find root in the password file.
450 	 */
451 	while ((p = fgets(line, sizeof(line), fp)) != NULL) {
452 		if (strncmp(line, "root:", 5) != 0)
453 			continue;
454 		p += 5;
455 		set(&pwd.pw_passwd, strsep(&p, ":"));
456 		strsep(&p, ":");
457 		strsep(&p, ":");
458 		set(&pwd.pw_gecos, strsep(&p, ":"));
459 		set(&pwd.pw_dir, strsep(&p, ":"));
460 		set(&pwd.pw_shell, strsep(&p, "\n"));
461 		p = line;
462 		break;
463 	}
464 	fclose(fp);
465 
466 	/*
467 	 * If the encrypted password is valid or not found, return.
468 	 */
469 	if (p == NULL) {
470 		warnx(_("%s: no entry for root\n"), _PATH_PASSWD);
471 		return &pwd;
472 	}
473 	if (valid(pwd.pw_passwd))
474 		return &pwd;
475 
476 	/*
477 	 * The password is invalid. If there is a shadow password, try it.
478 	 */
479 	*pwd.pw_passwd = '\0';
480 	if ((fp = fopen(_PATH_SHADOW_PASSWD, "r")) == NULL) {
481 		warn(_("cannot open %s"), _PATH_PASSWD);
482 		return &pwd;
483 	}
484 	while ((p = fgets(sline, sizeof(sline), fp)) != NULL) {
485 		if (strncmp(sline, "root:", 5) != 0)
486 			continue;
487 		p += 5;
488 		set(&pwd.pw_passwd, strsep(&p, ":"));
489 		break;
490 	}
491 	fclose(fp);
492 
493 	/*
494 	 * If the password is still invalid, NULL it, and return.
495 	 */
496 	if (p == NULL) {
497 		warnx(_("%s: no entry for root"), _PATH_SHADOW_PASSWD);
498 		*pwd.pw_passwd = '\0';
499 	}
500 	/* locked account passwords are valid too */
501 	if (!locked_account_password(pwd.pw_passwd) && !valid(pwd.pw_passwd)) {
502 		warnx(_("%s: root password garbled"), _PATH_SHADOW_PASSWD);
503 		*pwd.pw_passwd = '\0';
504 	}
505 	return &pwd;
506 }
507 
508 /*
509  * Ask by prompt for the password.
510  */
doprompt(const char * crypted,struct console * con,int deny)511 static void doprompt(const char *crypted, struct console *con, int deny)
512 {
513 	struct termios tty;
514 
515 	if (con->flags & CON_SERIAL) {
516 		tty = con->tio;
517 		/*
518 		 * For prompting: map NL in output to CR-NL
519 		 * otherwise we may see stairs in the output.
520 		 */
521 		tty.c_oflag |= (ONLCR | OPOST);
522 		tcsetattr(con->fd, TCSADRAIN, &tty);
523 	}
524 	if (!con->file) {
525 		con->file = fdopen(con->fd, "r+");
526 		if (!con->file)
527 			goto err;
528 	}
529 
530 	if (deny)
531 		fprintf(con->file, _("\nCannot open access to console, the root account is locked.\n"
532 				     "See sulogin(8) man page for more details.\n\n"
533 				     "Press Enter to continue.\n"));
534 	else {
535 #if defined(USE_ONELINE)
536 		if (crypted[0] && !locked_account_password(crypted))
537 			fprintf(con->file, _("Give root password for login: "));
538 		else
539 			fprintf(con->file, _("Press Enter for login: "));
540 #else
541 		if (crypted[0] && !locked_account_password(crypted))
542 			fprintf(con->file, _("Give root password for maintenance\n"));
543 		else
544 			fprintf(con->file, _("Press Enter for maintenance\n"));
545 		fprintf(con->file, _("(or press Control-D to continue): "));
546 #endif
547 	}
548 	fflush(con->file);
549 err:
550 	if (con->flags & CON_SERIAL)
551 		tcsetattr(con->fd, TCSADRAIN, &con->tio);
552 }
553 
554 /*
555  * Make sure to have an own session and controlling terminal
556  */
setup(struct console * con)557 static void setup(struct console *con)
558 {
559 	int fd = con->fd;
560 	const pid_t pid = getpid(), pgrp = getpgid(0), ppgrp =
561 	    getpgid(getppid()), ttypgrp = tcgetpgrp(fd);
562 
563 	if (con->flags & CON_NOTTY)
564 		return;
565 
566 	/*
567 	 * Only go through this trouble if the new
568 	 * tty doesn't fall in this process group.
569 	 */
570 	if (pgrp != ttypgrp && ppgrp != ttypgrp) {
571 		if (pid != getsid(0)) {
572 			if (pid == getpgid(0))
573 				setpgid(0, getpgid(getppid()));
574 			setsid();
575 		}
576 
577 		mask_signal(SIGHUP, SIG_IGN, &saved_sighup);
578 		if (ttypgrp > 0)
579 			ioctl(STDIN_FILENO, TIOCNOTTY, (char *)1);
580 		unmask_signal(SIGHUP, &saved_sighup);
581 		if (fd > STDIN_FILENO)  close(STDIN_FILENO);
582 		if (fd > STDOUT_FILENO) close(STDOUT_FILENO);
583 		if (fd > STDERR_FILENO) close(STDERR_FILENO);
584 
585 		ioctl(fd, TIOCSCTTY, (char *)1);
586 		tcsetpgrp(fd, ppgrp);
587 	}
588 	dup2(fd, STDIN_FILENO);
589 	dup2(fd, STDOUT_FILENO);
590 	dup2(fd, STDERR_FILENO);
591 	con->fd = STDIN_FILENO;
592 
593 	for (fd = STDERR_FILENO+1; fd < 32; fd++) {
594 		if (openfd & (1<<fd)) {
595 			close(fd);
596 			openfd &= ~(1<<fd);
597 		}
598 	}
599 }
600 
601 /*
602  * Ask for the password. Note that there is no default timeout as we normally
603  * skip this during boot.
604  */
getpasswd(struct console * con)605 static const char *getpasswd(struct console *con)
606 {
607 	struct sigaction sa;
608 	struct termios tty;
609 	static char pass[128], *ptr;
610 	struct chardata *cp;
611 	const char *ret = pass;
612 	unsigned char tc;
613 	char c, ascval;
614 	int eightbit;
615 	const int fd = con->fd;
616 
617 	if (con->flags & CON_NOTTY)
618 		goto out;
619 	cp = &con->cp;
620 	tty = con->tio;
621 
622 	tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
623 	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG);
624 	tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0);
625 
626 	sigemptyset(&sa.sa_mask);
627 	sa.sa_handler = alrm_handler;
628 	sa.sa_flags = 0;
629 	sigaction(SIGALRM, &sa, NULL);
630 
631 	if (timeout)
632 		alarm(timeout);
633 
634 	ptr = &pass[0];
635 	cp->eol = *ptr = '\0';
636 
637 	eightbit = ((con->flags & CON_SERIAL) == 0 || (tty.c_cflag & (PARODD|PARENB)) == 0);
638 	while (cp->eol == '\0') {
639 		if (read(fd, &c, 1) < 1) {
640 			if (errno == EINTR || errno == EAGAIN) {
641 				if (alarm_rised) {
642 					ret = NULL;
643 					goto quit;
644 				}
645 				xusleep(250000);
646 				continue;
647 			}
648 			ret = NULL;
649 			switch (errno) {
650 			case 0:
651 			case EIO:
652 			case ESRCH:
653 			case EINVAL:
654 			case ENOENT:
655 				break;
656 			default:
657 				warn(_("cannot read %s"), con->tty);
658 				break;
659 			}
660 			goto quit;
661 		}
662 
663 		if (eightbit)
664 			ascval = c;
665 		else if (c != (ascval = (c & 0177))) {
666 			uint32_t bits, mask;
667 			for (bits = 1, mask = 1; mask & 0177; mask <<= 1) {
668 				if (mask & ascval)
669 					bits++;
670 			}
671 			cp->parity |= ((bits & 1) ? 1 : 2);
672 		}
673 
674 		switch (ascval) {
675 		case 0:
676 			*ptr = '\0';
677 			goto quit;
678 		case CR:
679 		case NL:
680 			*ptr = '\0';
681 			cp->eol = ascval;
682 			break;
683 		case BS:
684 		case CERASE:
685 			cp->erase = ascval;
686 			if (ptr > &pass[0])
687 				ptr--;
688 			break;
689 		case CKILL:
690 			cp->kill = ascval;
691 			while (ptr > &pass[0])
692 				ptr--;
693 			break;
694 		case CEOF:
695 			ret = NULL;
696 			goto quit;
697 		default:
698 			if ((size_t)(ptr - &pass[0]) >= (sizeof(pass) -1 )) {
699 				 fprintf(stderr, "sulogin: input overrun at %s\n\r", con->tty);
700 				 ret = NULL;
701 				 goto quit;
702 			}
703 			*ptr++ = ascval;
704 			break;
705 		}
706 	}
707 quit:
708 	alarm(0);
709 	if (tc)
710 		tcsetattr(fd, TCSAFLUSH, &con->tio);
711 	tcfinal(con);
712 	printf("\r\n");
713 out:
714 	return ret;
715 }
716 
717 /*
718  * Password was OK, execute a shell.
719  */
sushell(struct passwd * pwd)720 static void sushell(struct passwd *pwd)
721 {
722 	char shell[PATH_MAX];
723 	char home[PATH_MAX];
724 	char const *p;
725 	char const *su_shell;
726 
727 	/*
728 	 * Set directory and shell.
729 	 */
730 	if (chdir(pwd->pw_dir) != 0) {
731 		warn(_("%s: change directory failed"), pwd->pw_dir);
732 		printf(_("Logging in with home = \"/\".\n"));
733 
734 		if (chdir("/") != 0)
735 			warn(_("change directory to system root failed"));
736 	}
737 
738 	if ((p = getenv("SUSHELL")) != NULL)
739 		su_shell = p;
740 	else if ((p = getenv("sushell")) != NULL)
741 		su_shell = p;
742 	else {
743 		if (pwd->pw_shell[0])
744 			su_shell = pwd->pw_shell;
745 		else
746 			su_shell = "/bin/sh";
747 	}
748 	if ((p = strrchr(su_shell, '/')) == NULL)
749 		p = su_shell;
750 	else
751 		p++;
752 
753 	snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
754 
755 	/*
756 	 * Set some important environment variables.
757 	 */
758 	if (getcwd(home, sizeof(home)) == NULL)
759 		strcpy(home, "/");
760 
761 	xsetenv("HOME", home, 1);
762 	xsetenv("LOGNAME", "root", 1);
763 	xsetenv("USER", "root", 1);
764 	if (!profile)
765 		xsetenv("SHLVL","0",1);
766 
767 	/*
768 	 * Try to execute a shell.
769 	 */
770 	xsetenv("SHELL", su_shell, 1);
771 	unmask_signal(SIGINT, &saved_sigint);
772 	unmask_signal(SIGTSTP, &saved_sigtstp);
773 	unmask_signal(SIGQUIT, &saved_sigquit);
774 	mask_signal(SIGHUP, SIG_DFL, NULL);
775 
776 #ifdef HAVE_LIBSELINUX
777 	if (is_selinux_enabled() > 0) {
778 		security_context_t scon=NULL;
779 		char *seuser=NULL;
780 		char *level=NULL;
781 		if (getseuserbyname("root", &seuser, &level) == 0) {
782 			if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
783 				if (setexeccon(scon) != 0)
784 					warnx(_("setexeccon failed"));
785 				freecon(scon);
786 			}
787 		}
788 		free(seuser);
789 		free(level);
790 	}
791 #endif
792 	execl(su_shell, shell, NULL);
793 	warn(_("failed to execute %s"), su_shell);
794 
795 	xsetenv("SHELL", "/bin/sh", 1);
796 	execl("/bin/sh", profile ? "-sh" : "sh", NULL);
797 	warn(_("failed to execute %s"), "/bin/sh");
798 }
799 
usage(void)800 static void usage(void)
801 {
802 	FILE *out = stdout;
803 	fputs(USAGE_HEADER, out);
804 	fprintf(out, _(
805 		" %s [options] [tty device]\n"), program_invocation_short_name);
806 
807 	fputs(USAGE_SEPARATOR, out);
808 	fputs(_("Single-user login.\n"), out);
809 
810 	fputs(USAGE_OPTIONS, out);
811 	fputs(_(" -p, --login-shell        start a login shell\n"
812 		" -t, --timeout <seconds>  max time to wait for a password (default: no limit)\n"
813 		" -e, --force              examine password files directly if getpwnam(3) fails\n"),
814 		out);
815 
816 	fputs(USAGE_SEPARATOR, out);
817 	printf(USAGE_HELP_OPTIONS(26));
818 	printf(USAGE_MAN_TAIL("sulogin(8)"));
819 
820 	exit(EXIT_SUCCESS);
821 }
822 
main(int argc,char ** argv)823 int main(int argc, char **argv)
824 {
825 	struct list_head *ptr, consoles;
826 	struct console *con;
827 	char *tty = NULL;
828 	struct passwd *pwd;
829 	const struct timespec sigwait = { .tv_sec = 0, .tv_nsec = 50000000 };
830 	siginfo_t status = { 0 };
831 	sigset_t set;
832 	int c, reconnect = 0;
833 	int opt_e = 0;
834 	int wait = 0;
835 	pid_t pid;
836 
837 	static const struct option longopts[] = {
838 		{ "login-shell",  no_argument,       NULL, 'p' },
839 		{ "timeout",      required_argument, NULL, 't' },
840 		{ "force",        no_argument,       NULL, 'e' },
841 		{ "help",         no_argument,       NULL, 'h' },
842 		{ "version",      no_argument,       NULL, 'V' },
843 		{ NULL, 0, NULL, 0 }
844 	};
845 
846 	INIT_LIST_HEAD(&consoles);
847 
848 	/*
849 	 * If we are init we need to set up a own session.
850 	 */
851 	if ((pid = getpid()) == 1) {
852 		setsid();
853 		ignore_result( ioctl(STDIN_FILENO, TIOCSCTTY, (char *) 1) );
854 	}
855 
856 	setlocale(LC_ALL, "");
857 	bindtextdomain(PACKAGE, LOCALEDIR);
858 	textdomain(PACKAGE);
859 	close_stdout_atexit();
860 
861 	/*
862 	 * See if we have a timeout flag.
863 	 */
864 	while ((c = getopt_long(argc, argv, "ehpt:V", longopts, NULL)) != -1) {
865 		switch(c) {
866 		case 't':
867 			timeout = strtou32_or_err(optarg, _("invalid timeout argument"));
868 			break;
869 		case 'p':
870 			profile = 1;
871 			break;
872 		case 'e':
873 			opt_e = 1;
874 			break;
875 		case 'V':
876 			print_version(EXIT_SUCCESS);
877 		case 'h':
878 			usage();
879 		default:
880 			/* Do not exit! getopt prints a warning. */
881 			break;
882 		}
883 	}
884 
885 	if (geteuid() != 0)
886 		errx(EXIT_FAILURE, _("only superuser can run this program"));
887 
888 	mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
889 	mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
890 	mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
891 	mask_signal(SIGHUP,  SIG_IGN, &saved_sighup);
892 
893 
894 	emergency_do_mounts();
895 	atexit( emergency_do_umounts );
896 
897 	/*
898 	 * See if we need to open an other tty device.
899 	 */
900 	if (optind < argc)
901 		tty = argv[optind];
902 
903 	if (!tty || *tty == '\0')
904 		tty = getenv("CONSOLE");
905 
906 	/*
907 	 * Detect possible consoles, use stdin as fallback.
908 	 * If an optional tty is given, reconnect it to stdin.
909 	 */
910 	reconnect = detect_consoles(tty, STDIN_FILENO, &consoles);
911 
912 	/*
913 	 * If previous stdin was not the specified tty and therefore reconnected
914 	 * to the specified tty also reconnect stdout and stderr.
915 	 */
916 	if (reconnect) {
917 		if (isatty(STDOUT_FILENO) == 0)
918 			dup2(STDOUT_FILENO, STDIN_FILENO);
919 		if (isatty(STDERR_FILENO) == 0)
920 			dup2(STDOUT_FILENO, STDERR_FILENO);
921 	}
922 
923 	/*
924 	 * Should not happen
925 	 */
926 	if (list_empty(&consoles)) {
927 		if (!errno)
928 			errno = ENOENT;
929 		err(EXIT_FAILURE, _("cannot open console"));
930 	}
931 
932 	/*
933 	 * Get the root password.
934 	 */
935 	if ((pwd = getrootpwent(opt_e)) == NULL) {
936 		warnx(_("cannot open password database"));
937 		sleep(2);
938 		return EXIT_FAILURE;
939 	}
940 
941 	/*
942 	 * Ask for the password on the consoles.
943 	 */
944 	list_for_each(ptr, &consoles) {
945 		con = list_entry(ptr, struct console, entry);
946 		if (con->id >= CONMAX)
947 			break;
948 		if (con->fd >= 0) {
949 			openfd |= (1 << con->fd);
950 			tcinit(con);
951 			continue;
952 		}
953 		if ((con->fd = open(con->tty, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
954 			continue;
955 		openfd |= (1 << con->fd);
956 		tcinit(con);
957 	}
958 	ptr = (&consoles)->next;
959 
960 	if (ptr->next == &consoles) {
961 		con = list_entry(ptr, struct console, entry);
962 		goto nofork;
963 	}
964 
965 
966 	mask_signal(SIGCHLD, chld_handler, &saved_sigchld);
967 	do {
968 		con = list_entry(ptr, struct console, entry);
969 		if (con->id >= CONMAX)
970 			break;
971 
972 		switch ((con->pid = fork())) {
973 		case 0:
974 			mask_signal(SIGCHLD, SIG_DFL, NULL);
975 		nofork:
976 			setup(con);
977 			while (1) {
978 				const char *passwd = pwd->pw_passwd;
979 				const char *answer;
980 				int doshell = 0;
981 				int deny = !opt_e && locked_account_password(pwd->pw_passwd);
982 
983 				doprompt(passwd, con, deny);
984 
985 				if ((answer = getpasswd(con)) == NULL)
986 					break;
987 				if (deny)
988 					exit(EXIT_FAILURE);
989 
990 				/* no password or locked account */
991 				if (!passwd[0] || locked_account_password(passwd))
992 					doshell++;
993 				else {
994 					const char *cryptbuf;
995 					cryptbuf = crypt(answer, passwd);
996 					if (cryptbuf == NULL)
997 						warn(_("crypt failed"));
998 					else if (strcmp(cryptbuf, pwd->pw_passwd) == 0)
999 						doshell++;
1000 				}
1001 
1002 				if (doshell) {
1003 					/* sushell() unmask signals */
1004 					sushell(pwd);
1005 
1006 					mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
1007 					mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
1008 					mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
1009 
1010 					fprintf(stderr, _("cannot execute su shell\n\n"));
1011 					break;
1012 				}
1013 				fprintf(stderr, _("Login incorrect\n\n"));
1014 			}
1015 			if (alarm_rised) {
1016 				tcfinal(con);
1017 				warnx(_("Timed out\n\n"));
1018 			}
1019 			/*
1020 			 * User pressed Control-D.
1021 			 */
1022 			exit(0);
1023 		case -1:
1024 			warn(_("fork failed"));
1025 			/* fallthrough */
1026 		default:
1027 			break;
1028 		}
1029 
1030 		ptr = ptr->next;
1031 
1032 	} while (ptr != &consoles);
1033 
1034 	do {
1035 		int ret;
1036 
1037 		status.si_pid = 0;
1038 		ret = waitid(P_ALL, 0, &status, WEXITED);
1039 
1040 		if (ret == 0)
1041 			break;
1042 		if (ret < 0) {
1043 			if (errno == ECHILD)
1044 				break;
1045 			if (errno == EINTR)
1046 				continue;
1047 		}
1048 
1049 		errx(EXIT_FAILURE, _("cannot wait on su shell\n\n"));
1050 
1051 	} while (1);
1052 
1053 	list_for_each(ptr, &consoles) {
1054 		con = list_entry(ptr, struct console, entry);
1055 
1056 		if (con->fd < 0)
1057 			continue;
1058 		if (con->pid < 0)
1059 			continue;
1060 		if (con->pid == status.si_pid)
1061 			con->pid = -1;
1062 		else {
1063 			kill(con->pid, SIGTERM);
1064 			wait++;
1065 		}
1066 	}
1067 
1068 	sigemptyset(&set);
1069 	sigaddset(&set, SIGCHLD);
1070 
1071 	do {
1072 		int signum, ret;
1073 
1074 		if (!wait)
1075 			break;
1076 
1077 		status.si_pid = 0;
1078 		ret = waitid(P_ALL, 0, &status, WEXITED|WNOHANG);
1079 
1080 		if (ret < 0) {
1081 			if (errno == ECHILD)
1082 				break;
1083 			if (errno == EINTR)
1084 				continue;
1085 		}
1086 
1087 		if (!ret && status.si_pid > 0) {
1088 			list_for_each(ptr, &consoles) {
1089 				con = list_entry(ptr, struct console, entry);
1090 
1091 				if (con->fd < 0)
1092 					continue;
1093 				if (con->pid < 0)
1094 					continue;
1095 				if (con->pid == status.si_pid) {
1096 					con->pid = -1;
1097 					wait--;
1098 				}
1099 			}
1100 			continue;
1101 		}
1102 
1103 		signum = sigtimedwait(&set, NULL, &sigwait);
1104 		if (signum != SIGCHLD && signum < 0 && errno == EAGAIN)
1105 			break;
1106 
1107 	} while (1);
1108 
1109 	mask_signal(SIGCHLD, SIG_DFL, NULL);
1110 	return EXIT_SUCCESS;
1111 }
1112