Blame login.c

Ørjan Malde d16cc0
/* mlogin: minimalistic login                */
Ørjan Malde d16cc0
/* Copyright (c) 2019  Ørjan Malde           */
Ørjan Malde d16cc0
/* Released under LGPL, see COPYRIGHT.MLOGIN */
Ørjan Malde d16cc0
Ørjan Malde 24d238
#include <sys/types.h>
Ørjan Malde 24d238
#include <unistd.h>
Ørjan Malde 24d238
#include <stdlib.h>
Ørjan Malde 24d238
#include <stdio.h>
Ørjan Malde 24d238
#include <stdbool.h>
Ørjan Malde 24d238
#include <string.h>
Ørjan Malde 24d238
#include <grp.h>
Ørjan Malde 24d238
#include <pwd.h>
Ørjan Malde 24d238
#include <errno.h>
Ørjan Malde 24d238
#include <signal.h>
Ørjan Malde 24d238
#ifdef __midipix__
Ørjan Malde 24d238
#define IFLAG 1
Ørjan Malde 24d238
#else
Ørjan Malde 24d238
#define IFLAG 0
Ørjan Malde 24d238
#endif
Ørjan Malde 24d238
Ørjan Malde 24d238
#include "login.h"
16ae2b
#include "motd.h"
c95639
#include "os/os.h"
7ab29a
b86465
static bool do_login(struct passwd* pwd, int pflag)
b86465
{
7ab29a
	char *	comspec;
7ab29a
	size_t	envlen;
7ab29a
	char **	envp;
7ab29a
	char *	envstrs;
7ab29a
	char *	envptrs[8];
7ab29a
	char	envbuff[3072];
7ab29a
b86465
	if(*pwd->pw_shell == '\0')
b86465
		pwd->pw_shell = "/bin/sh"; /* if /bin/sh doesn't exist, I do not care. blow up. */
b86465
b86465
	if(chdir(pwd->pw_dir) < 0) {
aefc6a
		printf("no home directory %s!\n", pwd->pw_dir); /* handle -EPERM, -ENOMEM, -ESYMLNK */
b86465
b86465
		if(chdir("/") == -1) {
b86465
			printf("chdir failed with %s", strerror(errno));
b86465
			return false;
7ab29a
		} else {
7ab29a
			pwd->pw_dir = "/";
7ab29a
		}
7ab29a
	}
b86465
7ab29a
	if(pflag) {
7ab29a
		envp = environ;
7ab29a
7ab29a
		(void)setenv("HOME", pwd->pw_dir, 1);
7ab29a
		(void)setenv("SHELL", pwd->pw_shell, 1);
7ab29a
		(void)setenv("TERM", "xterm", 0); /* rrrr. needs researching */
7ab29a
		(void)setenv("LOGNAME", pwd->pw_name, 1);
7ab29a
		(void)setenv("USER", pwd->pw_name, 1);
7ab29a
		(void)setenv("PATH", "/local/sbin:/local/bin:/sbin:/bin", 0);
7ab29a
	} else {
7ab29a
		envlen  = snprintf(envbuff,0,"HOME=%s",pwd->pw_dir) + 1;
7ab29a
		envlen += snprintf(envbuff,0,"SHELL=%s",pwd->pw_shell) + 1;
7ab29a
		envlen += snprintf(envbuff,0,"TERM=%s","xterm") + 1;
7ab29a
		envlen += snprintf(envbuff,0,"LOGNAME=%s",pwd->pw_name) + 1;
7ab29a
		envlen += snprintf(envbuff,0,"USER=%s",pwd->pw_name) + 1;
7ab29a
		envlen += snprintf(envbuff,0,"PATH=%s","/local/sbin:/local/bin:/sbin:/bin") + 1;
7ab29a
7ab29a
		if ((comspec = getenv("ComSpec")) || (comspec = getenv("COMSSPEC")))
7ab29a
			envlen += snprintf(envbuff,0,"COMSPEC=%s",comspec) + 1;
7ab29a
7ab29a
		if (envlen <= sizeof(envbuff)) {
7ab29a
			envp    = envptrs;
7ab29a
			envstrs = envbuff;
7ab29a
		} else if ((envstrs = calloc(envlen,1))) {
7ab29a
			envp    = envptrs;
7ab29a
		} else {
7ab29a
			return false;
7ab29a
		}
b86465
7ab29a
		envp[0]  = envstrs;
7ab29a
		envstrs += sprintf(envstrs,"HOME=%s",pwd->pw_dir) + 1;
7ab29a
7ab29a
		envp[1]  = envstrs;
7ab29a
		envstrs += sprintf(envstrs,"SHELL=%s",pwd->pw_shell) + 1;
7ab29a
7ab29a
		envp[2]  = envstrs;
7ab29a
		envstrs += sprintf(envstrs,"TERM=%s","xterm") + 1;
7ab29a
7ab29a
		envp[3]  = envstrs;
7ab29a
		envstrs += sprintf(envstrs,"LOGNAME=%s",pwd->pw_name) + 1;
7ab29a
7ab29a
		envp[4]  = envstrs;
7ab29a
		envstrs += sprintf(envstrs,"USER=%s",pwd->pw_name) + 1;
7ab29a
7ab29a
		envp[5]  = envstrs;
7ab29a
		envstrs += sprintf(envstrs,"PATH=%s","/local/sbin:/local/bin:/sbin:/bin") + 1;
7ab29a
7ab29a
		envp[6] = 0;
7ab29a
		envp[7] = 0;
7ab29a
7ab29a
		if (comspec) {
7ab29a
			envp[6]  = envstrs;
7ab29a
			envstrs += sprintf(envstrs,"COMSPEC=%s",comspec) + 1;
7ab29a
		}
7ab29a
	}
7ab29a
7ab29a
	(void)signal(SIGTSTP, SIG_DFL);
7ab29a
	(void)signal(SIGQUIT, SIG_DFL);
7ab29a
	(void)signal(SIGINT, SIG_DFL);
7ab29a
16ae2b
	motd();
16ae2b
7ab29a
	execve(
7ab29a
		pwd->pw_shell,
7ab29a
		(char *[]){pwd->pw_shell,"-l",0},
7ab29a
		envp);
7ab29a
7ab29a
	return false;
Ørjan Malde 24d238
}
Ørjan Malde 24d238
Ørjan Malde 24d238
int main(int argc, char **argv)
Ørjan Malde 24d238
{
Ørjan Malde 24d238
	/* we don't want ^D etc to mess up the logic */
Ørjan Malde 24d238
	(void)signal(SIGTSTP, SIG_IGN);
Ørjan Malde 24d238
	(void)signal(SIGQUIT, SIG_IGN);
Ørjan Malde 24d238
	(void)signal(SIGINT, SIG_IGN);
Ørjan Malde 24d238
Ørjan Malde 24d238
	struct passwd *pwd;
Ørjan Malde 24d238
	char* username = NULL;
Ørjan Malde 24d238
	int c;
d382df
	int pflag, iflag = 0;
Ørjan Malde 24d238
Ørjan Malde 24d238
	while((c = getopt(argc, argv, "pfh:iw")) != -1)
Ørjan Malde 24d238
		switch(c) {
Ørjan Malde 24d238
			case 'p':
Ørjan Malde 24d238
				pflag = 1; break;
Ørjan Malde 24d238
			case 'f':
d382df
				(void)0; break; /* unused, pointless currently */
Ørjan Malde 24d238
			case 'h':
Ørjan Malde 24d238
				if(getuid()) {
Ørjan Malde 24d238
					exit(1);
Ørjan Malde 24d238
				}
Ørjan Malde 24d238
				break;
Ørjan Malde 24d238
			case 'i':
Ørjan Malde 24d238
				iflag = IFLAG; break;
Ørjan Malde 24d238
			default:
Ørjan Malde 24d238
			case '?':
Ørjan Malde 24d238
				usage();
Ørjan Malde 24d238
				break;
Ørjan Malde 24d238
		}
82a7c0
	argv += optind;
Ørjan Malde 24d238
c2d308
	if(*argv)
Ørjan Malde 24d238
		username = *argv;
Ørjan Malde 24d238
	else {
Ørjan Malde 24d238
		printf("login: ");
Ørjan Malde 24d238
		fflush(0);
Ørjan Malde 24d238
		(void)scanf("%ms", &username);
Ørjan Malde 24d238
	}
Ørjan Malde 24d238
	pwd = getpwnam(username);
276bd5
9a3e75
	/* guard against account probing */
9a3e75
	if(!pwd) {
7add4b
		char* pw = getpass("Password: ");
b86465
		explicit_bzero(pw, strlen(pw));
9a3e75
		endpwent();
9a3e75
		puts("Login incorrect.");
b86465
		exit(1);
b86465
	}
b86465
9a3e75
	/* midipix: are we spawning a shell? */
9a3e75
	if(!iflag) {
9a3e75
		char* pw = getpass("Password: ");
9a3e75
		if(!(*pwd->pw_passwd == '\0' && !strlen(pw))) { /* TODO: check for shadow passwords and locked accounts */
9a3e75
			char* pw_encrypted = crypt(pw, pwd->pw_passwd);
9a3e75
			/* if(timingsafe_memcmp(pw_encrypted, pwd->pw_passwd, strlen(pw_encrypted))) { */
9a3e75
			if(memcmp(pw_encrypted, pwd->pw_passwd, strlen(pw_encrypted)) != 0) {
9a3e75
				puts("Login incorrect.");
9a3e75
				explicit_bzero(pw, strlen(pw));
9a3e75
				exit(1);
9a3e75
			}
9a3e75
			explicit_bzero(pw, strlen(pw));
9a3e75
		}
9a3e75
	}
9a3e75
Ørjan Malde 24d238
	endpwent();
Ørjan Malde 24d238
9a3e75
	/* authenticated; attempt to set user context and spawn user shell */
c95639
	if(switch_user_context(pwd, username) == 0) {
b86465
		if(!do_login(pwd, pflag)) {
b86465
			puts("failed to spawn shell.");
Ørjan Malde 24d238
		}
Ørjan Malde 24d238
	}
Ørjan Malde 24d238
	puts("could not switch to specified user.");
Ørjan Malde 24d238
}
Ørjan Malde 24d238
034530
void usage(void)
034530
{
d74de0
	puts("login -p		do not the destroy the environment");
d74de0
	puts("login -f		do not perform secondary authentication (noop)");
d74de0
	puts("login -h		pass remote server name to utmp (noop)");
Ørjan Malde 24d238
	exit(0);
Ørjan Malde 24d238
}