|
Ø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 |
#define _GNU_SOURCE
|
|
Ø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 |
#include <windows.h>
|
|
Ørjan Malde |
7d9c4e |
#include <ctype.h>
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
#define IFLAG 1
|
|
Ørjan Malde |
24d238 |
#define WFLAG 1
|
|
Ørjan Malde |
24d238 |
#else
|
|
Ørjan Malde |
24d238 |
#define IFLAG 0
|
|
Ørjan Malde |
24d238 |
#define WFLAG 0
|
|
Ørjan Malde |
24d238 |
#endif
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
#include "login.h"
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
static char* get_win32_username(void)
|
|
Ørjan Malde |
24d238 |
{
|
|
Ørjan Malde |
24d238 |
#ifdef __midipix__
|
|
Ørjan Malde |
24d238 |
size_t i;
|
|
Ørjan Malde |
24d238 |
char usernam[257];
|
|
Ørjan Malde |
24d238 |
unsigned int usernam_siz = sizeof(usernam);
|
|
Ørjan Malde |
24d238 |
if(GetUserNameA(usernam, &usernam_siz) == 0)
|
|
Ørjan Malde |
24d238 |
return "";
|
|
Ørjan Malde |
24d238 |
for(i = 0; i < 257; i++)
|
|
Ørjan Malde |
24d238 |
usernam[i] = tolower(usernam[i]);
|
|
Ørjan Malde |
24d238 |
return strdup(usernam);
|
|
Ørjan Malde |
24d238 |
#else
|
|
Ørjan Malde |
24d238 |
return "";
|
|
Ørjan Malde |
24d238 |
#endif
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
/* force memset */
|
|
Ørjan Malde |
24d238 |
static void __attribute__((optimize("O0"))) memset_noopt(void* mem, int c, size_t memsiz)
|
|
Ørjan Malde |
24d238 |
{
|
|
Ørjan Malde |
24d238 |
memset(mem, c, memsiz);
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
static bool switch_user_context(struct passwd* pw, const char* username)
|
|
Ørjan Malde |
24d238 |
{
|
|
Ørjan Malde |
24d238 |
/* temporary */
|
|
Ørjan Malde |
d27f17 |
#ifndef INSECURE
|
|
Ørjan Malde |
24d238 |
if(initgroups(username, pw->pw_gid) == -1) {
|
|
Ørjan Malde |
24d238 |
printf("initgroups failed: %s", strerror(errno));
|
|
Ørjan Malde |
24d238 |
exit(1);
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
#endif
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
#ifdef INSECURE
|
|
Ørjan Malde |
24d238 |
if((setuid(pw->pw_uid) != -1) && (setgid(pw->pw_gid) != -1))
|
|
Ørjan Malde |
24d238 |
return true;
|
|
Ørjan Malde |
24d238 |
return false;
|
|
Ørjan Malde |
24d238 |
#else
|
|
Ørjan Malde |
24d238 |
gid_t oldgid = getegid();
|
|
Ørjan Malde |
24d238 |
uid_t olduid = geteuid();
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
if((setegid(pw->pw_gid) != -1) && (setgid(pw->pw_gid) != -1) && (seteuid(pw->pw_uid) != -1) && (setuid(pw->pw_uid) != -1)) {
|
|
Ørjan Malde |
24d238 |
gid_t newgid = getgid();
|
|
Ørjan Malde |
24d238 |
uid_t newuid = getuid();
|
|
Ørjan Malde |
24d238 |
#ifdef debug
|
|
Ørjan Malde |
24d238 |
printf("old gid %d\n", oldgid);
|
|
Ørjan Malde |
24d238 |
printf("old uid %d\n", olduid);
|
|
Ørjan Malde |
24d238 |
printf("new gid %d\n", newgid);
|
|
Ørjan Malde |
24d238 |
printf("new uid %d\n", newuid);
|
|
Ørjan Malde |
24d238 |
#endif
|
|
Ørjan Malde |
24d238 |
if((newgid == oldgid) && (newuid == olduid))
|
|
Ørjan Malde |
24d238 |
return true;
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
return false;
|
|
Ørjan Malde |
24d238 |
#endif
|
|
Ø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;
|
|
Ørjan Malde |
24d238 |
int pflag, fflag, iflag, wflag = 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':
|
|
Ørjan Malde |
24d238 |
fflag = 1; 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 |
case 'w':
|
|
Ørjan Malde |
24d238 |
wflag = WFLAG; break;
|
|
Ørjan Malde |
24d238 |
default:
|
|
Ørjan Malde |
24d238 |
case '?':
|
|
Ørjan Malde |
24d238 |
usage();
|
|
Ørjan Malde |
24d238 |
break;
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
argv += optind;
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
if(wflag)
|
|
Ørjan Malde |
24d238 |
username = get_win32_username();
|
|
Ørjan Malde |
24d238 |
else 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 |
|
|
Ørjan Malde |
24d238 |
if(!iflag)
|
|
Ørjan Malde |
24d238 |
{
|
|
Ørjan Malde |
24d238 |
char* pw = getpass("Password: ");
|
|
Ørjan Malde |
24d238 |
if(pwd) {
|
|
Ørjan Malde |
24d238 |
/* if hash == 0 then authenticated = true */
|
|
|
276bd5 |
if(!(*pwd->pw_passwd == '\0' && !strlen(pw))) {
|
|
Ørjan Malde |
24d238 |
char* pw_encrypted = crypt(pw, pwd->pw_passwd);
|
|
|
276bd5 |
if(!timingsafe_memcmp(pw_encrypted, pwd->pw_passwd, strlen(pw_encrypted))) {
|
|
|
276bd5 |
puts("Login incorrect.");
|
|
|
276bd5 |
memset_noopt(pw, 0, strlen(pw));
|
|
|
276bd5 |
exit(1);
|
|
|
276bd5 |
}
|
|
Ørjan Malde |
24d238 |
}
|
|
|
276bd5 |
memset_noopt(pw, 0, strlen(pw));
|
|
Ørjan Malde |
24d238 |
} else {
|
|
|
276bd5 |
/* user doesn't exist, bail */
|
|
|
276bd5 |
puts("Login incorrect.");
|
|
|
276bd5 |
memset_noopt(pw, 0, strlen(pw));
|
|
|
276bd5 |
exit(1);
|
|
Ørjan Malde |
24d238 |
}
|
|
|
276bd5 |
}
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
endpwent();
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
/* authenticated, attempt to set user context and spawn user shell */
|
|
Ørjan Malde |
24d238 |
if(switch_user_context(pwd, username)) {
|
|
Ørjan Malde |
24d238 |
if(*pwd->pw_shell == '\0')
|
|
Ørjan Malde |
24d238 |
pwd->pw_shell = "/bin/sh"; /* if /bin/sh doesn't exist, I do not care. blow up. */
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
if(chdir(pwd->pw_dir) < 0) {
|
|
Ørjan Malde |
24d238 |
printf("no home directory %s!\n", pwd->pw_dir); // handle -EPERM, -ENOMEM, -ESYMLNK
|
|
Ørjan Malde |
24d238 |
if(chdir("/") == -1) {
|
|
Ørjan Malde |
24d238 |
printf("chdir failed with %s", strerror(errno));
|
|
Ørjan Malde |
24d238 |
exit(1); /* no-one can save you now */
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
pwd->pw_dir = "/";
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
if(!pflag)
|
|
Ørjan Malde |
24d238 |
(void)clearenv();
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
(void)setenv("HOME", pwd->pw_dir, 1);
|
|
Ørjan Malde |
24d238 |
(void)setenv("SHELL", pwd->pw_shell, 1);
|
|
Ørjan Malde |
24d238 |
(void)setenv("TERM", "xterm", 0); /* rrrr. needs researching */
|
|
Ørjan Malde |
24d238 |
(void)setenv("LOGNAME", pwd->pw_name, 1);
|
|
Ørjan Malde |
24d238 |
(void)setenv("USER", pwd->pw_name, 1);
|
|
Ørjan Malde |
24d238 |
#if 0
|
|
Ørjan Malde |
24d238 |
(void)setenv("PS1", "$ ", 0);
|
|
Ørjan Malde |
24d238 |
#endif
|
|
Ørjan Malde |
24d238 |
(void)setenv("PATH", "/local/sbin:/local/bin:/sbin:/bin", 0);
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
e3ae58 |
(void)signal(SIGTSTP, SIG_DFL);
|
|
Ørjan Malde |
e3ae58 |
(void)signal(SIGQUIT, SIG_DFL);
|
|
Ørjan Malde |
e3ae58 |
(void)signal(SIGINT, SIG_DFL);
|
|
Ørjan Malde |
e3ae58 |
|
|
Ørjan Malde |
8162bc |
execlp(pwd->pw_shell, "-i", (const char*)NULL);
|
|
Ørjan Malde |
24d238 |
printf("login failed with error: %s", strerror(errno));
|
|
Ørjan Malde |
24d238 |
exit(1);
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
puts("could not switch to specified user.");
|
|
Ørjan Malde |
24d238 |
}
|
|
Ørjan Malde |
24d238 |
|
|
Ørjan Malde |
24d238 |
void usage(void) {
|
|
Ørjan Malde |
24d238 |
puts("login -w (acquire username through Win32)");
|
|
Ørjan Malde |
24d238 |
puts("login -p (preserve environment)");
|
|
Ørjan Malde |
24d238 |
puts("login -f (no secondary authentication, unused)");
|
|
Ørjan Malde |
24d238 |
puts("login -h (pass remote server name to login, unused)");
|
|
Ørjan Malde |
24d238 |
exit(0);
|
|
Ørjan Malde |
24d238 |
}
|