1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64#include "libbb.h"
65#include "common_bufsiz.h"
66#include <syslog.h>
67
68#if ENABLE_SELINUX
69# include <selinux/selinux.h>
70# include <selinux/get_context_list.h>
71#
72# undef SECCLASS_CHR_FILE
73# define SECCLASS_CHR_FILE 10
74#endif
75
76#if ENABLE_PAM
77
78# undef setlocale
79
80
81# include <security/pam_appl.h>
82# include <security/pam_misc.h>
83
84# if 0
85
86
87
88
89
90
91
92
93
94
95
96static char *passwd = NULL;
97static int my_conv(int num_msg, const struct pam_message **msg,
98 struct pam_response **resp, void *data)
99{
100 int i;
101 for (i = 0; i < num_msg; i++) {
102 switch (msg[i]->msg_style) {
103 case PAM_PROMPT_ECHO_OFF:
104 if (passwd == NULL) {
105 misc_conv(num_msg, msg, resp, data);
106 passwd = xstrdup(resp[i]->resp);
107 return PAM_SUCCESS;
108 }
109
110 resp[0] = xzalloc(sizeof(struct pam_response));
111 resp[0]->resp = passwd;
112 passwd = NULL;
113 resp[0]->resp_retcode = PAM_SUCCESS;
114 resp[1] = NULL;
115 return PAM_SUCCESS;
116
117 default:
118 break;
119 }
120 }
121
122 return PAM_SUCCESS;
123}
124# endif
125
126static const struct pam_conv conv = {
127 misc_conv,
128 NULL
129};
130#endif
131
132enum {
133 TIMEOUT = 60,
134 EMPTY_USERNAME_COUNT = 10,
135
136 USERNAME_SIZE = 64,
137 TTYNAME_SIZE = 32,
138};
139
140struct globals {
141 struct termios tty_attrs;
142} FIX_ALIASING;
143#define G (*(struct globals*)bb_common_bufsiz1)
144#define INIT_G() do { setup_common_bufsiz(); } while (0)
145
146
147#if ENABLE_FEATURE_NOLOGIN
148static void die_if_nologin(void)
149{
150 FILE *fp;
151 int c;
152 int empty = 1;
153
154 fp = fopen_for_read("/etc/nologin");
155 if (!fp)
156 return;
157
158 while ((c = getc(fp)) != EOF) {
159 if (c == '\n')
160 bb_putchar('\r');
161 bb_putchar(c);
162 empty = 0;
163 }
164 if (empty)
165 puts("\r\nSystem closed for routine maintenance\r");
166
167 fclose(fp);
168 fflush_all();
169
170 tcdrain(STDOUT_FILENO);
171 exit(EXIT_FAILURE);
172}
173#else
174# define die_if_nologin() ((void)0)
175#endif
176
177#if ENABLE_SELINUX
178static void initselinux(char *username, char *full_tty,
179 security_context_t *user_sid)
180{
181 security_context_t old_tty_sid, new_tty_sid;
182
183 if (!is_selinux_enabled())
184 return;
185
186 if (get_default_context(username, NULL, user_sid)) {
187 bb_error_msg_and_die("can't get SID for %s", username);
188 }
189 if (getfilecon(full_tty, &old_tty_sid) < 0) {
190 bb_perror_msg_and_die("getfilecon(%s) failed", full_tty);
191 }
192 if (security_compute_relabel(*user_sid, old_tty_sid,
193 SECCLASS_CHR_FILE, &new_tty_sid) != 0) {
194 bb_perror_msg_and_die("security_change_sid(%s) failed", full_tty);
195 }
196 if (setfilecon(full_tty, new_tty_sid) != 0) {
197 bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid);
198 }
199}
200#endif
201
202#if ENABLE_LOGIN_SCRIPTS
203static void run_login_script(struct passwd *pw, char *full_tty)
204{
205 char *t_argv[2];
206
207 t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT");
208 if (t_argv[0]) {
209 t_argv[1] = NULL;
210 xsetenv("LOGIN_TTY", full_tty);
211 xsetenv("LOGIN_USER", pw->pw_name);
212 xsetenv("LOGIN_UID", utoa(pw->pw_uid));
213 xsetenv("LOGIN_GID", utoa(pw->pw_gid));
214 xsetenv("LOGIN_SHELL", pw->pw_shell);
215 spawn_and_wait(t_argv);
216 unsetenv("LOGIN_TTY");
217 unsetenv("LOGIN_USER");
218 unsetenv("LOGIN_UID");
219 unsetenv("LOGIN_GID");
220 unsetenv("LOGIN_SHELL");
221 }
222}
223#else
224void run_login_script(struct passwd *pw, char *full_tty);
225#endif
226
227#if ENABLE_LOGIN_SESSION_AS_CHILD && ENABLE_PAM
228static void login_pam_end(pam_handle_t *pamh)
229{
230 int pamret;
231
232 pamret = pam_setcred(pamh, PAM_DELETE_CRED);
233 if (pamret != PAM_SUCCESS) {
234 bb_error_msg("pam_%s failed: %s (%d)", "setcred",
235 pam_strerror(pamh, pamret), pamret);
236 }
237 pamret = pam_close_session(pamh, 0);
238 if (pamret != PAM_SUCCESS) {
239 bb_error_msg("pam_%s failed: %s (%d)", "close_session",
240 pam_strerror(pamh, pamret), pamret);
241 }
242 pamret = pam_end(pamh, pamret);
243 if (pamret != PAM_SUCCESS) {
244 bb_error_msg("pam_%s failed: %s (%d)", "end",
245 pam_strerror(pamh, pamret), pamret);
246 }
247}
248#endif
249
250static void get_username_or_die(char *buf, int size_buf)
251{
252 int c, cntdown;
253
254 cntdown = EMPTY_USERNAME_COUNT;
255 prompt:
256 print_login_prompt();
257
258 do {
259 c = getchar();
260 if (c == EOF)
261 exit(EXIT_FAILURE);
262 if (c == '\n') {
263 if (!--cntdown)
264 exit(EXIT_FAILURE);
265 goto prompt;
266 }
267 } while (isspace(c));
268
269 *buf++ = c;
270 if (!fgets(buf, size_buf-2, stdin))
271 exit(EXIT_FAILURE);
272 if (!strchr(buf, '\n'))
273 exit(EXIT_FAILURE);
274 while ((unsigned char)*buf > ' ')
275 buf++;
276 *buf = '\0';
277}
278
279static void motd(void)
280{
281 int fd;
282
283 fd = open(bb_path_motd_file, O_RDONLY);
284 if (fd >= 0) {
285 fflush_all();
286 bb_copyfd_eof(fd, STDOUT_FILENO);
287 close(fd);
288 }
289}
290
291static void alarm_handler(int sig UNUSED_PARAM)
292{
293
294
295
296 ndelay_on(STDOUT_FILENO);
297
298
299
300
301
302 tcsetattr_stdin_TCSANOW(&G.tty_attrs);
303 printf("\r\nLogin timed out after %u seconds\r\n", TIMEOUT);
304 fflush_all();
305
306
307 ndelay_off(STDOUT_FILENO);
308 _exit(EXIT_SUCCESS);
309}
310
311int login_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
312int login_main(int argc UNUSED_PARAM, char **argv)
313{
314 enum {
315 LOGIN_OPT_f = (1<<0),
316 LOGIN_OPT_h = (1<<1),
317 LOGIN_OPT_p = (1<<2),
318 };
319 char *fromhost;
320 char username[USERNAME_SIZE];
321 int run_by_root;
322 unsigned opt;
323 int count = 0;
324 struct passwd *pw;
325 char *opt_host = NULL;
326 char *opt_user = opt_user;
327 char *full_tty;
328 char *short_tty;
329 IF_SELINUX(security_context_t user_sid = NULL;)
330#if ENABLE_PAM
331 int pamret;
332 pam_handle_t *pamh;
333 const char *pamuser;
334 const char *failed_msg;
335 struct passwd pwdstruct;
336 char pwdbuf[256];
337 char **pamenv;
338#endif
339#if ENABLE_LOGIN_SESSION_AS_CHILD
340 pid_t child_pid;
341#endif
342
343 INIT_G();
344
345
346
347 run_by_root = !sanitize_env_if_suid();
348
349
350
351
352
353 bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS);
354
355 username[0] = '\0';
356 opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
357 if (opt & LOGIN_OPT_f) {
358 if (!run_by_root)
359 bb_error_msg_and_die("-f is for root only");
360 safe_strncpy(username, opt_user, sizeof(username));
361 }
362 argv += optind;
363 if (argv[0])
364 safe_strncpy(username, argv[0], sizeof(username));
365
366
367 if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0
368 || !isatty(STDOUT_FILENO)
369
370 ) {
371 return EXIT_FAILURE;
372 }
373
374
375 signal(SIGALRM, alarm_handler);
376 alarm(TIMEOUT);
377
378
379 full_tty = xmalloc_ttyname(STDIN_FILENO);
380 if (!full_tty)
381 full_tty = xstrdup("UNKNOWN");
382 short_tty = skip_dev_pfx(full_tty);
383
384 if (opt_host) {
385 fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
386 } else {
387 fromhost = xasprintf(" on '%s'", short_tty);
388 }
389
390
391
392
393 openlog(applet_name, LOG_PID | LOG_CONS, LOG_AUTH);
394
395 while (1) {
396
397 tcflush(0, TCIFLUSH);
398
399 if (!username[0])
400 get_username_or_die(username, sizeof(username));
401
402#if ENABLE_PAM
403 pamret = pam_start("login", username, &conv, &pamh);
404 if (pamret != PAM_SUCCESS) {
405 failed_msg = "start";
406 goto pam_auth_failed;
407 }
408
409 pamret = pam_set_item(pamh, PAM_TTY, short_tty);
410 if (pamret != PAM_SUCCESS) {
411 failed_msg = "set_item(TTY)";
412 goto pam_auth_failed;
413 }
414
415 if (opt_host) {
416 pamret = pam_set_item(pamh, PAM_RHOST, opt_host);
417 if (pamret != PAM_SUCCESS) {
418 failed_msg = "set_item(RHOST)";
419 goto pam_auth_failed;
420 }
421 }
422 if (!(opt & LOGIN_OPT_f)) {
423 pamret = pam_authenticate(pamh, 0);
424 if (pamret != PAM_SUCCESS) {
425 failed_msg = "authenticate";
426 goto pam_auth_failed;
427
428
429
430
431 }
432 }
433
434 pamret = pam_acct_mgmt(pamh, 0);
435 if (pamret != PAM_SUCCESS) {
436 failed_msg = "acct_mgmt";
437 goto pam_auth_failed;
438 }
439
440 pamuser = NULL;
441
442
443 if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) {
444 failed_msg = "get_item(USER)";
445 goto pam_auth_failed;
446 }
447 if (!pamuser || !pamuser[0])
448 goto auth_failed;
449 safe_strncpy(username, pamuser, sizeof(username));
450
451
452
453 pw = NULL;
454 getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw);
455 if (!pw)
456 goto auth_failed;
457 pamret = pam_open_session(pamh, 0);
458 if (pamret != PAM_SUCCESS) {
459 failed_msg = "open_session";
460 goto pam_auth_failed;
461 }
462 pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
463 if (pamret != PAM_SUCCESS) {
464 failed_msg = "setcred";
465 goto pam_auth_failed;
466 }
467 break;
468
469 pam_auth_failed:
470
471
472 syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg,
473 pam_strerror(pamh, pamret), pamret);
474 safe_strncpy(username, "UNKNOWN", sizeof(username));
475#else
476 pw = getpwnam(username);
477 if (!pw) {
478 strcpy(username, "UNKNOWN");
479 goto fake_it;
480 }
481
482 if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
483 goto auth_failed;
484
485 if (opt & LOGIN_OPT_f)
486 break;
487
488 if (pw->pw_uid == 0 && !is_tty_secure(short_tty))
489 goto auth_failed;
490
491
492 if (!pw->pw_passwd[0])
493 break;
494 fake_it:
495
496
497
498
499 if (ask_and_check_password(pw) > 0)
500 break;
501#endif
502 auth_failed:
503 opt &= ~LOGIN_OPT_f;
504 bb_do_delay(LOGIN_FAIL_DELAY);
505
506 puts("Login incorrect");
507 if (++count == 3) {
508 syslog(LOG_WARNING, "invalid password for '%s'%s",
509 username, fromhost);
510
511 if (ENABLE_FEATURE_CLEAN_UP)
512 free(fromhost);
513
514 return EXIT_FAILURE;
515 }
516 username[0] = '\0';
517 }
518
519 alarm(0);
520
521
522 if (pw->pw_uid != 0)
523 die_if_nologin();
524
525#if ENABLE_LOGIN_SESSION_AS_CHILD
526 child_pid = vfork();
527 if (child_pid != 0) {
528 if (child_pid < 0)
529 bb_perror_msg("vfork");
530 else {
531 if (safe_waitpid(child_pid, NULL, 0) == -1)
532 bb_perror_msg("waitpid");
533 update_utmp_DEAD_PROCESS(child_pid);
534 }
535 IF_PAM(login_pam_end(pamh);)
536 return 0;
537 }
538#endif
539
540 IF_SELINUX(initselinux(username, full_tty, &user_sid);)
541
542
543
544 fchown(0, pw->pw_uid, pw->pw_gid);
545 fchmod(0, 0600);
546
547 update_utmp(getpid(), USER_PROCESS, short_tty, username, run_by_root ? opt_host : NULL);
548
549
550 if (ENABLE_LOGIN_SCRIPTS && run_by_root)
551 run_login_script(pw, full_tty);
552
553 change_identity(pw);
554 setup_environment(pw->pw_shell,
555 (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV,
556 pw);
557
558#if ENABLE_PAM
559
560
561 pamenv = pam_getenvlist(pamh);
562 if (pamenv) while (*pamenv) {
563 putenv(*pamenv);
564 pamenv++;
565 }
566#endif
567
568 if (access(".hushlogin", F_OK) != 0)
569 motd();
570
571 if (pw->pw_uid == 0)
572 syslog(LOG_INFO, "root login%s", fromhost);
573
574 if (ENABLE_FEATURE_CLEAN_UP)
575 free(fromhost);
576
577
578
579 IF_SELINUX(set_current_security_context(user_sid);)
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600 signal(SIGINT, SIG_DFL);
601
602
603 run_shell(pw->pw_shell, 1, NULL);
604
605
606}
607