17aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley/* login.c - Start a session on the system. 20b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer * 30b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com> 40b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer * 50b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer * No support for PAM/securetty/selinux/login script/issue/utmp 60b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer * Relies on libcrypt for hash calculation. 7f033f8607f156464747abe57487c1f6226f94001Rob Landley * 8f033f8607f156464747abe57487c1f6226f94001Rob Landley * TODO: this command predates "pending" but needs cleanup. It #defines 9f033f8607f156464747abe57487c1f6226f94001Rob Landley * random stuff, calls exit() form a signal handler... yeah. 100b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 113aa1d18b727ded4415d8a5f34f90a0726213aa7fRob LandleyUSE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) 120b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 130b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwerconfig LOGIN 147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bool "login" 157aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley default y 1646ddf0e34b03f7711a9c80f7a70dc8cbf732f782Isaac Dunham depends on TOYBOX_SHADOW 177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley help 183aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley usage: login [-p] [-h host] [-f USERNAME] [USERNAME] 197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 203aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley Log in as a user, prompting for username and password if necessary. 21afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley 227aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -p Preserve environment 237aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -h The name of the remote host for this login 243aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley -f login as USERNAME without authentication 250b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer*/ 260b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 27c0e56edaf256adb6c60c5a052525a1ffbb927901Rob Landley#define FOR_login 280b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer#include "toys.h" 290b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 30c0e56edaf256adb6c60c5a052525a1ffbb927901Rob LandleyGLOBALS( 317aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley char *hostname; 323aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley char *username; 332109b158f496b3ecccea34c960b45f7aeba6679eRob Landley 342109b158f496b3ecccea34c960b45f7aeba6679eRob Landley int login_timeout, login_fail_timeout; 350b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer) 360b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 370b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwerstatic void login_timeout_handler(int sig __attribute__((unused))) 380b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer{ 392109b158f496b3ecccea34c960b45f7aeba6679eRob Landley printf("\nLogin timed out after %d seconds.\n", TT.login_timeout); 407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley exit(0); 410b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer} 420b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 430b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwervoid login_main(void) 440b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer{ 453aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley char *forbid[] = { 463aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD", 473aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH", 483aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL" 493aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley }; 503aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley int hh = toys.optflags&FLAG_h, count, tty; 513aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley char uu[33], *username, *pass = 0, *ss; 523aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley struct passwd *pwd = 0; 530b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 543aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley for (tty=0; tty<3; tty++) if (isatty(tty)) break; 553aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (tty == 3) error_exit("no tty"); 560b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 573aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]); 580b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 597aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley openlog("login", LOG_PID | LOG_CONS, LOG_AUTH); 60c776bde13bb2767db2943bc3b02df737a465c035Rob Landley xsignal(SIGALRM, login_timeout_handler); 61c5e41c7d39523516c023a8def5b13907aac53cf1Rob Landley 623aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (TT.username) username = TT.username; 633aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley else username = *toys.optargs; 643aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley for (count = 0; count < 3; count++) { 653aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley alarm(TT.login_timeout = 60); 667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley tcflush(0, TCIFLUSH); 670b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 683aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (!username) { 693aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley int i; 703aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 713aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley memset(username = uu, 0, sizeof(uu)); 723aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley gethostname(uu, sizeof(uu)-1); 733aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley printf("%s%slogin: ", *uu ? uu : "", *uu ? " " : ""); 743aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley fflush(stdout); 753aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 763aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if(!fgets(uu, sizeof(uu)-1, stdin)) _exit(1); 773aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 783aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // Remove trailing \n and so on 793aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley for (i = 0; i<sizeof(uu); i++) if (uu[i]<=' ' || uu[i]==':') uu[i]=0; 803aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (!*uu) { 813aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley username = 0; 823aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley continue; 833aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } 847aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 850b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 863aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // If user exists and isn't locked 877aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley pwd = getpwnam(username); 883aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') { 890b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 903aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // Pre-authenticated or passwordless 913aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (TT.username || !*pwd->pw_passwd) break; 920b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 933aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // fetch shadow password if necessary 943aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (*(pass = pwd->pw_passwd) == 'x') { 953aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley struct spwd *spwd = getspnam (username); 960b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 973aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (spwd) pass = spwd->sp_pwdp; 983aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } 993aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } else if (TT.username) error_exit("bad -f '%s'", TT.username); 1000b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1013aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // Verify password. (Prompt for password _before_ checking disable state.) 1023aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (!read_password(toybuf, sizeof(toybuf), "Password: ")) { 1033aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley int x = pass && (ss = crypt(toybuf, pass)) && !strcmp(pass, ss); 1040b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1053aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // password go bye-bye now. 1063aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley memset(toybuf, 0, sizeof(toybuf)); 1073aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (x) break; 1083aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } 1090b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1103aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", pwd->pw_name, 1113aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley ttyname(tty), hh ? "from " : "", hh ? TT.hostname : ""); 1120b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1132109b158f496b3ecccea34c960b45f7aeba6679eRob Landley sleep(3); 1147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley puts("Login incorrect"); 1150b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1163aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley username = 0; 1172109b158f496b3ecccea34c960b45f7aeba6679eRob Landley pwd = 0; 1187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 1190b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1207aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley alarm(0); 1213aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // This had password data in it, and we reuse for motd below 1223aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley memset(toybuf, 0, sizeof(toybuf)); 1233aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 1243aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (!pwd) error_exit("max retries (3)"); 1250b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1263aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // Check twice because "this file exists" is a security test, and in 1273aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // theory filehandle exhaustion or other error could make open/read fail. 1283aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (pwd->pw_uid && !access("/etc/nologin", R_OK)) { 1293aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley ss = readfile("/etc/nologin", toybuf, sizeof(toybuf)); 1303aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley puts ((ss && *ss) ? ss : "nologin"); 1313aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley free(ss); 1323aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley toys.exitval = 1; 1333aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 1343aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley return; 1353aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } 1360b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 137afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley xsetuser(pwd); 1380b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1393aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (chdir(pwd->pw_dir)) printf("bad $HOME: %s\n", pwd->pw_dir); 1403aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 1413aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (!(toys.optflags&FLAG_p)) { 1423aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley char *term = getenv("TERM"); 1433aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 1443aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley clearenv(); 1453aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if (term) setenv("TERM", term, 1); 1463aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } 1473aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley 1483aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley setenv("USER", pwd->pw_name, 1); 1493aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley setenv("LOGNAME", pwd->pw_name, 1); 1503aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley setenv("HOME", pwd->pw_dir, 1); 1513aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley setenv("SHELL", pwd->pw_shell, 1); 1520b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1533aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley // Message of the day 1543aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley if ((ss = readfile("/etc/motd", 0, 0))) { 1553aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley puts(ss); 1563aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley free(ss); 1573aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley } 1580b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1597aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name, 1603aa1d18b727ded4415d8a5f34f90a0726213aa7fRob Landley ttyname(tty), hh ? "from" : "", hh ? TT.hostname : ""); 1610b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer 1627d6af77804adc069a83e8566250f868a6cb9786eRob Landley // not using xexec(), login calls absolute path from filesystem so must exec() 1637d6af77804adc069a83e8566250f868a6cb9786eRob Landley execl(pwd->pw_shell, xmprintf("-%s", pwd->pw_shell), (char *)0); 1647d6af77804adc069a83e8566250f868a6cb9786eRob Landley perror_exit("exec shell '%s'", pwd->pw_shell); 1650b11a16626867a362ed9aff3950650af94d1cfa7Elie De Brauwer} 166