mrrl-logincaps

MRRL version of logincaps
git clone https://ccx.te2000.cz/git/mrrl-logincaps
Log | Files | Refs

commit af03c2323d74bd1c2d0e63ddf801e7af4c314aad
parent e15477fc4f2fe0e3370ab91cbe74b6352154a707
Author: Jan Pobříslo <ccx@te2000.cz>
Date:   Fri,  8 Jan 2021 19:30:41 +0000

move login.c to separate directory so toybox sources can be included, fix null pwd reference
Diffstat:
Dlogin.c | 226-------------------------------------------------------------------------------
Alogin/login.c | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 229 insertions(+), 226 deletions(-)

diff --git a/login.c b/login.c @@ -1,226 +0,0 @@ -/* 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. - * - * TODO: this command predates "pending" but needs cleanup. It #defines - * random stuff, calls exit() form a signal handler... yeah. - -USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) - -config LOGIN - bool "login" - default y - depends on TOYBOX_SHADOW - 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 *hostname; - char *username; - - 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); - exit(0); -} - -void login_main(void) -{ - char *forbid[] = { - "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD", - "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH", - "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL" - }; - int hh = toys.optflags&FLAG_h, count, tty; - int pipefd[2] = {-1, -1}; - int child_pid; - char uu[33], *username, *pass = 0, *ss; - struct passwd *pwd = 0; - char *loginexec = 0; - unsigned char use_loginexec = 0; - - for (tty=0; tty<3; tty++) if (isatty(tty)) break; - if (tty == 3) error_exit("no tty"); - - for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]); - - openlog("login", LOG_PID | LOG_CONS, LOG_AUTH); - xsignal(SIGALRM, login_timeout_handler); - - if (TT.username) username = TT.username; - else username = *toys.optargs; - for (count = 0; count < 3; count++) { - alarm(TT.login_timeout = 60); - tcflush(0, TCIFLUSH); - - if (!username) { - int i; - - memset(username = uu, 0, sizeof(uu)); - gethostname(uu, sizeof(uu)-1); - printf("%s%slogin: ", *uu ? uu : "", *uu ? " " : ""); - fflush(stdout); - - if(!fgets(uu, sizeof(uu)-1, stdin)) _exit(1); - - // Remove trailing \n and so on - for (i = 0; i<sizeof(uu); i++) if (uu[i]<=' ' || uu[i]==':') uu[i]=0; - if (!*uu) { - username = 0; - continue; - } - } - - // If user exists and isn't locked - pwd = getpwnam(username); - if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') { - - // Pre-authenticated or passwordless - if (TT.username || !*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; - } - } else if (TT.username) error_exit("bad -f '%s'", TT.username); - - loginexec = xmprintf("%s/loginexec", pwd->pw_dir); - use_loginexec = !access(loginexec, X_OK); - - // 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); - - if (x && use_loginexec) { - if(!pipe(pipefd)) { - if((child_pid = fork())) { - if(child_pid == -1) { - /* error */ - perror("fork"); - close(pipefd[0]); - close(pipefd[1]); - pipefd[0] = pipefd[1] = -1; - } else { - /* parent */ - close(pipefd[1]); - } - } else { - /* child */ - dup2(pipefd[1], 1); - xprintf("%s\n", toybuf); - exit(0); - } - } else { - /* creating pipe failed */ - perror("pipe"); - pipefd[0] = pipefd[1] = -1; - } - if (!access("/etc/loginexec", X_OK)) { - if (!(toys.optflags&FLAG_p)) { - char *term = getenv("TERM"); - - clearenv(); - if (term) setenv("TERM", term, 1); - } - - setenv("USER", pwd->pw_name, 1); - setenv("LOGNAME", pwd->pw_name, 1); - setenv("HOME", pwd->pw_dir, 1); - setenv("SHELL", pwd->pw_shell, 1); - if(pipefd[0] >= 0) { - setenv("LOGINPASS_FD", xmprintf("%d", pipefd[0]), 1); - } - /* TODO */ - /* set UID, GID and GIDLIST env variables */ - - alarm(0); // remove pending SIGALRM for stale login - - execl("/etc/loginexec", "/etc/loginexec", loginexec, (char *)0); - } - } - // password go bye-bye now. - memset(toybuf, 0, sizeof(toybuf)); - if (x) break; - } - - syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", pwd->pw_name, - ttyname(tty), hh ? "from " : "", hh ? TT.hostname : ""); - - sleep(3); - puts("Login incorrect"); - - username = 0; - pwd = 0; - } - - alarm(0); - // This had password data in it, and we reuse for motd below - memset(toybuf, 0, sizeof(toybuf)); - - 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; - } - - xsetuser(pwd); - - if (chdir(pwd->pw_dir)) printf("bad $HOME: %s\n", pwd->pw_dir); - - if (!(toys.optflags&FLAG_p)) { - char *term = getenv("TERM"); - - clearenv(); - if (term) setenv("TERM", term, 1); - } - - setenv("USER", pwd->pw_name, 1); - setenv("LOGNAME", pwd->pw_name, 1); - setenv("HOME", pwd->pw_dir, 1); - setenv("SHELL", pwd->pw_shell, 1); - if(pipefd[0] >= 0) { - setenv("LOGINPASS_FD", xmprintf("%d", pipefd[0]), 1); - } - - // Message of the day - if ((ss = readfile("/etc/motd", 0, 0))) { - puts(ss); - free(ss); - } - - syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name, - ttyname(tty), hh ? "from" : "", hh ? TT.hostname : ""); - - if(use_loginexec) { - execl(loginexec, loginexec, (char *)0); - } else { - // 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); - } -} diff --git a/login/login.c b/login/login.c @@ -0,0 +1,229 @@ +/* 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. + * + * TODO: this command predates "pending" but needs cleanup. It #defines + * random stuff, calls exit() form a signal handler... yeah. + +USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) + +config LOGIN + bool "login" + default y + depends on TOYBOX_SHADOW + 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 *hostname; + char *username; + + 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); + exit(0); +} + +void login_main(void) +{ + char *forbid[] = { + "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD", + "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH", + "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL" + }; + int hh = toys.optflags&FLAG_h, count, tty; + int pipefd[2] = {-1, -1}; + int child_pid; + char uu[33], *username, *pass = 0, *ss; + struct passwd *pwd = 0; + char *loginexec = 0; + unsigned char use_loginexec = 0; + + for (tty=0; tty<3; tty++) if (isatty(tty)) break; + if (tty == 3) error_exit("no tty"); + + for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]); + + openlog("login", LOG_PID | LOG_CONS, LOG_AUTH); + xsignal(SIGALRM, login_timeout_handler); + + if (TT.username) username = TT.username; + else username = *toys.optargs; + for (count = 0; count < 3; count++) { + alarm(TT.login_timeout = 60); + tcflush(0, TCIFLUSH); + + if (!username) { + int i; + + memset(username = uu, 0, sizeof(uu)); + gethostname(uu, sizeof(uu)-1); + printf("%s%slogin: ", *uu ? uu : "", *uu ? " " : ""); + fflush(stdout); + + if(!fgets(uu, sizeof(uu)-1, stdin)) _exit(1); + + // Remove trailing \n and so on + for (i = 0; i<sizeof(uu); i++) if (uu[i]<=' ' || uu[i]==':') uu[i]=0; + if (!*uu) { + username = 0; + continue; + } + } + + // If user exists and isn't locked + pwd = getpwnam(username); + if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') { + + // Pre-authenticated or passwordless + if (TT.username || !*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; + } + + loginexec = xmprintf("%s/loginexec", pwd->pw_dir); + use_loginexec = !access(loginexec, X_OK); + + } else if (TT.username) error_exit("bad -f '%s'", TT.username); + + + // 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); + + if (x && use_loginexec) { + if(!pipe(pipefd)) { + if((child_pid = fork())) { + if(child_pid == -1) { + /* error */ + perror("fork"); + close(pipefd[0]); + close(pipefd[1]); + pipefd[0] = pipefd[1] = -1; + } else { + /* parent */ + close(pipefd[1]); + } + } else { + /* child */ + dup2(pipefd[1], 1); + xprintf("%s\n", toybuf); + exit(0); + } + } else { + /* creating pipe failed */ + perror("pipe"); + pipefd[0] = pipefd[1] = -1; + } + if (!access("/etc/loginexec", X_OK)) { + if (!(toys.optflags&FLAG_p)) { + char *term = getenv("TERM"); + + clearenv(); + if (term) setenv("TERM", term, 1); + } + + setenv("USER", pwd->pw_name, 1); + setenv("LOGNAME", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", pwd->pw_shell, 1); + if(pipefd[0] >= 0) { + setenv("LOGINPASS_FD", xmprintf("%d", pipefd[0]), 1); + } + /* TODO */ + /* set UID, GID and GIDLIST env variables */ + + alarm(0); // remove pending SIGALRM for stale login + + execl("/etc/loginexec", "/etc/loginexec", loginexec, (char *)0); + } + } + // password go bye-bye now. + memset(toybuf, 0, sizeof(toybuf)); + if (x) break; + } + + syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", + pwd ? pwd->pw_name : "UNKNOWN", + ttyname(tty), hh ? "from " : "", hh ? TT.hostname : ""); + + sleep(3); + puts("Login incorrect"); + + username = 0; + pwd = 0; + } + + alarm(0); + // This had password data in it, and we reuse for motd below + memset(toybuf, 0, sizeof(toybuf)); + + 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; + } + + xsetuser(pwd); + + if (chdir(pwd->pw_dir)) printf("bad $HOME: %s\n", pwd->pw_dir); + + if (!(toys.optflags&FLAG_p)) { + char *term = getenv("TERM"); + + clearenv(); + if (term) setenv("TERM", term, 1); + } + + setenv("USER", pwd->pw_name, 1); + setenv("LOGNAME", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", pwd->pw_shell, 1); + if(pipefd[0] >= 0) { + setenv("LOGINPASS_FD", xmprintf("%d", pipefd[0]), 1); + } + + // Message of the day + if ((ss = readfile("/etc/motd", 0, 0))) { + puts(ss); + free(ss); + } + + syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name, + ttyname(tty), hh ? "from" : "", hh ? TT.hostname : ""); + + if(use_loginexec) { + execl(loginexec, loginexec, (char *)0); + } else { + // 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); + } +}