• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* login.c - Start a session on the system.
2  *
3  * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
4  *
5  * No support for PAM/securetty/selinux/login script/issue/utmp
6  * Relies on libcrypt for hash calculation.
7 
8 USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
9 
10 config LOGIN
11   bool "login"
12   default y
13   depends on TOYBOX_SHADOW
14   help
15     usage: login [-p] [-h host] [-f USERNAME] [USERNAME]
16 
17     Log in as a user, prompting for username and password if necessary.
18 
19     -p	Preserve environment
20     -h	The name of the remote host for this login
21     -f	login as USERNAME without authentication
22 */
23 
24 #define FOR_login
25 #include "toys.h"
26 
27 GLOBALS(
28   char *h, *f;
29 
30   int login_timeout, login_fail_timeout;
31 )
32 
login_timeout_handler(int sig)33 static void login_timeout_handler(int sig __attribute__((unused)))
34 {
35   printf("\nLogin timed out after %d seconds.\n", TT.login_timeout);
36   xexit();
37 }
38 
login_main(void)39 void login_main(void)
40 {
41   int hh = FLAG(h), count, tty = tty_fd();
42   char *username, *pass = 0, *ss;
43   struct passwd *pwd = 0;
44 
45   // we read user/password from stdin, but tty can be stderr?
46   if (tty == -1) error_exit("no tty");
47 
48   openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
49   xsignal(SIGALRM, login_timeout_handler);
50 
51   if (TT.f) username = TT.f;
52   else username = *toys.optargs;
53   for (count = 0; count < 3; count++) {
54     alarm(TT.login_timeout = 60);
55     tcflush(0, TCIFLUSH);
56 
57     if (!username) {
58       if (gethostname(toybuf, sizeof(toybuf)-1)) *toybuf = 0;
59       printf("%s%slogin: ", *toybuf ? toybuf : "", *toybuf ? " " : "");
60       fflush(stdout);
61 
62       if(!fgets(toybuf, sizeof(toybuf)-1, stdin)) xexit();
63 
64       // Remove trailing \n and so on
65       for (ss = toybuf; *ss; ss++) if (*ss<=' ' || *ss==':') break;
66       *ss = 0;
67       if (!*(username = toybuf)) {
68         username = 0;
69         continue;
70       }
71     }
72 
73     // If user exists and isn't locked
74     if ((pwd = getpwnam(username))) {
75       // Pre-authenticated or passwordless
76       if (TT.f || !*pwd->pw_passwd) break;
77 
78       // fetch shadow password if necessary
79       if (*(pass = pwd->pw_passwd) == 'x') {
80         struct spwd *spwd = getspnam (username);
81 
82         if (spwd) pass = spwd->sp_pwdp;
83       }
84     } else if (TT.f) error_exit("bad -f '%s'", TT.f);
85 
86     // Verify password. (Prompt for password _before_ checking disable state.)
87     if (!read_password(toybuf, sizeof(toybuf), "Password: ")) {
88       int x = pass && (ss = crypt(toybuf, pass)) && !strcmp(pass, ss);
89 
90       // password go bye-bye now.
91       memset(toybuf, 0, sizeof(toybuf));
92       if (x) break;
93     }
94 
95     syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", pwd->pw_name,
96       ttyname(tty), hh ? "from " : "", hh ? TT.h : "");
97 
98     sleep(3);
99     puts("Login incorrect");
100 
101     username = 0;
102     pwd = 0;
103   }
104 
105   alarm(0);
106   if (!pwd) error_exit("max retries (3)");
107 
108   // Check twice because "this file exists" is a security test, and in
109   // theory filehandle exhaustion or other error could make open/read fail.
110   if (pwd->pw_uid && !access("/etc/nologin", R_OK)) {
111     ss = readfile("/etc/nologin", toybuf, sizeof(toybuf));
112     puts ((ss && *ss) ? ss : "nologin");
113     free(ss);
114     toys.exitval = 1;
115 
116     return;
117   }
118 
119   if (fchown(tty, pwd->pw_uid, pwd->pw_gid) || fchmod(tty, 0600))
120     printf("can't claim tty");
121   xsetuser(pwd);
122   reset_env(pwd, !FLAG(p));
123 
124   // Message of the day
125   if ((ss = readfile("/etc/motd", 0, 0))) puts(ss);
126 
127   syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
128     ttyname(tty), hh ? "from" : "", hh ? TT.h : "");
129 
130   // not using xexec(), login calls absolute path from filesystem so must exec()
131   execl(pwd->pw_shell, xmprintf("-%s", pwd->pw_shell), (char *)0);
132   perror_exit("exec shell '%s'", pwd->pw_shell);
133 }
134