blob: 62c1293ed72a9029612806867ea202bbec4ea8a7 [file] [log] [blame]
/* login.c - Start a session on the system.
*
* Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
*
* No support for PAM/securetty/selinux/login script/issue/utmp
* Relies on libcrypt for hash calculation.
USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
config LOGIN
bool "login"
default y
help
usage: login [-p] [-h host] [-f USERNAME] [USERNAME]
Log in as a user, prompting for username and password if necessary.
-p Preserve environment
-h The name of the remote host for this login
-f login as USERNAME without authentication
*/
#define FOR_login
#include "toys.h"
GLOBALS(
char *h, *f;
int login_timeout, login_fail_timeout;
)
static void login_timeout_handler(int sig __attribute__((unused)))
{
printf("\nLogin timed out after %d seconds.\n", TT.login_timeout);
xexit();
}
void login_main(void)
{
int count, tty = tty_fd();
char *username, *pass = 0, *ss;
struct passwd *pwd = 0;
// we read user/password from stdin, but tty can be stderr?
if (tty == -1) error_exit("no tty");
openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
xsignal(SIGALRM, login_timeout_handler);
if (TT.f) username = TT.f;
else username = *toys.optargs;
for (count = 0; count < 3; count++) {
alarm(TT.login_timeout = 60);
tcflush(0, TCIFLUSH);
if (!username) {
if (gethostname(toybuf, sizeof(toybuf)-1)) *toybuf = 0;
printf("%s%slogin: ", *toybuf ? toybuf : "", *toybuf ? " " : "");
fflush(stdout);
if(!fgets(toybuf, sizeof(toybuf)-1, stdin)) xexit();
// Remove trailing \n and so on
for (ss = toybuf; *ss; ss++) if (*ss<=' ' || *ss==':') break;
*ss = 0;
if (!*(username = toybuf)) {
username = 0;
continue;
}
}
// If user exists and isn't locked
if ((pwd = getpwnam(username))) {
// Pre-authenticated or passwordless
if (TT.f || !*pwd->pw_passwd) break;
// fetch shadow password if necessary
if (*(pass = pwd->pw_passwd) == 'x') {
struct spwd *spwd = getspnam (username);
if (spwd) {
pass = spwd->sp_pwdp;
// empty shadow password
if (pass && !*pass) break;
}
}
} else if (TT.f) error_exit("bad -f '%s'", TT.f);
// Verify password. (Prompt for password _before_ checking disable state.)
if (!read_password(toybuf, sizeof(toybuf), "Password: ")) {
int x = pass && (ss = crypt(toybuf, pass)) && !strcmp(pass, ss);
// password go bye-bye now.
memset(toybuf, 0, sizeof(toybuf));
if (x) break;
}
syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", username,
ttyname(tty), TT.h ? "from " : "", TT.h ? : "");
sleep(3);
puts("Login incorrect");
username = 0;
pwd = 0;
}
alarm(0);
if (!pwd) error_exit("max retries (3)");
// Check twice because "this file exists" is a security test, and in
// theory filehandle exhaustion or other error could make open/read fail.
if (pwd->pw_uid && !access("/etc/nologin", R_OK)) {
ss = readfile("/etc/nologin", toybuf, sizeof(toybuf));
puts ((ss && *ss) ? ss : "nologin");
free(ss);
toys.exitval = 1;
return;
}
if (fchown(tty, pwd->pw_uid, pwd->pw_gid) || fchmod(tty, 0600))
printf("can't claim tty");
xsetuser(pwd);
reset_env(pwd, !FLAG(p));
// Message of the day
if ((ss = readfile("/etc/motd", 0, 0))) puts(ss);
syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
ttyname(tty), TT.h ? "from" : "", TT.h ? : "");
// not using xexec(), login calls absolute path from filesystem so must exec()
execl(pwd->pw_shell, xmprintf("-%s", pwd->pw_shell), (char *)0);
perror_exit("exec shell '%s'", pwd->pw_shell);
}