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