Allow overriding the login session, refactor special users.
This commit is contained in:
parent
2799f04cad
commit
d3aee98c1a
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||||
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
|
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
|
||||||
|
* Copyright (c) 2023 dzwdz.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -87,6 +88,8 @@ static inline void arrow_initialize()
|
||||||
|
|
||||||
static struct textbox textbox_username;
|
static struct textbox textbox_username;
|
||||||
static struct textbox textbox_password;
|
static struct textbox textbox_password;
|
||||||
|
static char* username = NULL;
|
||||||
|
static char* session = NULL;
|
||||||
|
|
||||||
struct glogin
|
struct glogin
|
||||||
{
|
{
|
||||||
|
@ -605,7 +608,7 @@ static void think(struct glogin* state)
|
||||||
}
|
}
|
||||||
if ( result )
|
if ( result )
|
||||||
{
|
{
|
||||||
if ( !login(textbox_username.text) )
|
if ( !login(username, session) )
|
||||||
state->warning = strerror(errno);
|
state->warning = strerror(errno);
|
||||||
state->stage = STAGE_USERNAME;
|
state->stage = STAGE_USERNAME;
|
||||||
textbox_reset(&textbox_username);
|
textbox_reset(&textbox_username);
|
||||||
|
@ -626,24 +629,28 @@ static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
||||||
{
|
{
|
||||||
if ( codepoint == '\n' )
|
if ( codepoint == '\n' )
|
||||||
{
|
{
|
||||||
|
enum special_action action;
|
||||||
state->warning = NULL;
|
state->warning = NULL;
|
||||||
switch ( state->stage )
|
switch ( state->stage )
|
||||||
{
|
{
|
||||||
case STAGE_USERNAME:
|
case STAGE_USERNAME:
|
||||||
if ( !strcmp(textbox_username.text, "exit") )
|
free(username);
|
||||||
exit(0);
|
free(session);
|
||||||
if ( !strcmp(textbox_username.text, "poweroff") )
|
username = NULL;
|
||||||
exit(0);
|
session = NULL;
|
||||||
if ( !strcmp(textbox_username.text, "reboot") )
|
if ( !parse_username(textbox_username.text, &username,
|
||||||
exit(1);
|
&session, &action) )
|
||||||
if ( !strcmp(textbox_username.text, "halt") )
|
{
|
||||||
exit(2);
|
state->warning = "Invalid username";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_special(action);
|
||||||
state->stage = STAGE_PASSWORD;
|
state->stage = STAGE_PASSWORD;
|
||||||
textbox_reset(&textbox_password);
|
textbox_reset(&textbox_password);
|
||||||
break;
|
break;
|
||||||
case STAGE_PASSWORD:
|
case STAGE_PASSWORD:
|
||||||
state->stage = STAGE_CHECKING;
|
state->stage = STAGE_CHECKING;
|
||||||
if ( !check_begin(&state->chk, textbox_username.text,
|
if ( !check_begin(&state->chk, username,
|
||||||
textbox_password.text, true) )
|
textbox_password.text, true) )
|
||||||
{
|
{
|
||||||
state->stage = STAGE_USERNAME;
|
state->stage = STAGE_USERNAME;
|
||||||
|
|
|
@ -34,6 +34,9 @@ script if it exists and is executable, otherwise attempting
|
||||||
.Pa /etc/session ,
|
.Pa /etc/session ,
|
||||||
and ultimately falling back on the user's shell from
|
and ultimately falling back on the user's shell from
|
||||||
.Xr passwd 5 .
|
.Xr passwd 5 .
|
||||||
|
It can be overriden by suffixing the username with a colon and the name of the
|
||||||
|
program to launch.
|
||||||
|
If the program name is skipped, the login shell is launched.
|
||||||
.Pp
|
.Pp
|
||||||
Type a special username to perform special options:
|
Type a special username to perform special options:
|
||||||
.Pp
|
.Pp
|
||||||
|
|
103
login/login.c
103
login/login.c
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015, 2018, 2022 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2015, 2018, 2022 Jonas 'Sortie' Termansen.
|
||||||
|
* Copyright (c) 2023 dzwdz.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -201,7 +203,7 @@ static int setcloexecfrom(int from)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool login(const char* username)
|
bool login(const char* username, const char* session)
|
||||||
{
|
{
|
||||||
char login_pid[sizeof(pid_t) * 3];
|
char login_pid[sizeof(pid_t) * 3];
|
||||||
snprintf(login_pid, sizeof(login_pid), "%" PRIiPID, getpid());
|
snprintf(login_pid, sizeof(login_pid), "%" PRIiPID, getpid());
|
||||||
|
@ -217,6 +219,8 @@ bool login(const char* username)
|
||||||
char* login_shell;
|
char* login_shell;
|
||||||
if ( asprintf(&login_shell, "-%s", pwd->pw_shell) < 0 )
|
if ( asprintf(&login_shell, "-%s", pwd->pw_shell) < 0 )
|
||||||
return close(pipe_fds[0]), close(pipe_fds[1]), false;
|
return close(pipe_fds[0]), close(pipe_fds[1]), false;
|
||||||
|
if ( session && *session == '\0' )
|
||||||
|
session = login_shell;
|
||||||
sigset_t oldset, sigttou;
|
sigset_t oldset, sigttou;
|
||||||
sigemptyset(&sigttou);
|
sigemptyset(&sigttou);
|
||||||
sigaddset(&sigttou, SIGTTOU);
|
sigaddset(&sigttou, SIGTTOU);
|
||||||
|
@ -252,11 +256,14 @@ bool login(const char* username)
|
||||||
tcsetpgrp(0, getpgid(0)) ||
|
tcsetpgrp(0, getpgid(0)) ||
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL) < 0 ||
|
sigprocmask(SIG_SETMASK, &oldset, NULL) < 0 ||
|
||||||
settermmode(0, TERMMODE_NORMAL) < 0 ||
|
settermmode(0, TERMMODE_NORMAL) < 0 ||
|
||||||
(execlp("./.session", "./.session", (const char*) NULL) < 0 &&
|
(session ?
|
||||||
errno != ENOENT && errno != EACCES) ||
|
execlp(session + (session[0] == '-'), session, (const char*) NULL) < 0
|
||||||
(execlp("/etc/session", "/etc/session", (const char*) NULL) < 0 &&
|
:
|
||||||
errno != ENOENT && errno != EACCES) ||
|
(execlp("./.session", "./.session", (const char*) NULL) < 0 &&
|
||||||
execlp(pwd->pw_shell, login_shell, (const char*) NULL));
|
errno != ENOENT && errno != EACCES) ||
|
||||||
|
(execlp("/etc/session", "/etc/session", (const char*) NULL) < 0 &&
|
||||||
|
errno != ENOENT && errno != EACCES) ||
|
||||||
|
execlp(pwd->pw_shell, login_shell, (const char*) NULL)));
|
||||||
write(pipe_fds[1], &errno, sizeof(errno));
|
write(pipe_fds[1], &errno, sizeof(errno));
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
|
@ -318,6 +325,61 @@ static bool read_terminal_line(char* buffer, size_t size)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool parse_username(const char* input,
|
||||||
|
char** username,
|
||||||
|
char** session,
|
||||||
|
enum special_action* action)
|
||||||
|
{
|
||||||
|
*username = NULL;
|
||||||
|
*session = NULL;
|
||||||
|
*action = SPECIAL_ACTION_NONE;
|
||||||
|
if ( !strcmp(input, "exit") )
|
||||||
|
return *action = SPECIAL_ACTION_POWEROFF, true;
|
||||||
|
else if ( !strcmp(input, "poweroff") )
|
||||||
|
return *action = SPECIAL_ACTION_POWEROFF, true;
|
||||||
|
else if ( !strcmp(input, "reboot") )
|
||||||
|
return *action = SPECIAL_ACTION_REBOOT, true;
|
||||||
|
else if ( !strcmp(input, "halt") )
|
||||||
|
return *action = SPECIAL_ACTION_HALT, true;
|
||||||
|
|
||||||
|
// Skip leading spaces to allow logging in as special accounts.
|
||||||
|
while ( isspace(*input) )
|
||||||
|
input++;
|
||||||
|
char* colon = strchr(input, ':');
|
||||||
|
if ( !colon )
|
||||||
|
{
|
||||||
|
*username = strdup(input);
|
||||||
|
return *username != NULL;
|
||||||
|
}
|
||||||
|
if ( strchr(colon + 1, ':') )
|
||||||
|
{
|
||||||
|
// Input contains more than one colon.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*username = strndup(input, colon - input);
|
||||||
|
if ( !*username )
|
||||||
|
return false;
|
||||||
|
*session = strdup(colon + 1);
|
||||||
|
if ( !*session )
|
||||||
|
{
|
||||||
|
free(*username);
|
||||||
|
*username = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_special(enum special_action action)
|
||||||
|
{
|
||||||
|
switch ( action )
|
||||||
|
{
|
||||||
|
case SPECIAL_ACTION_NONE: return;
|
||||||
|
case SPECIAL_ACTION_POWEROFF: exit(0);
|
||||||
|
case SPECIAL_ACTION_REBOOT: exit(1);
|
||||||
|
case SPECIAL_ACTION_HALT: exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int textual(void)
|
int textual(void)
|
||||||
{
|
{
|
||||||
unsigned int termmode = TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 |
|
unsigned int termmode = TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 |
|
||||||
|
@ -326,6 +388,9 @@ int textual(void)
|
||||||
err(2, "settermmode");
|
err(2, "settermmode");
|
||||||
unsigned int pw_termmode = termmode & ~(TERMMODE_ECHO);
|
unsigned int pw_termmode = termmode & ~(TERMMODE_ECHO);
|
||||||
|
|
||||||
|
char* username = NULL;
|
||||||
|
char* session = NULL;
|
||||||
|
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
char hostname[HOST_NAME_MAX + 1];
|
char hostname[HOST_NAME_MAX + 1];
|
||||||
|
@ -333,9 +398,9 @@ int textual(void)
|
||||||
gethostname(hostname, sizeof(hostname));
|
gethostname(hostname, sizeof(hostname));
|
||||||
printf("%s login: ", hostname);
|
printf("%s login: ", hostname);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
char username[256];
|
char input[256];
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if ( !read_terminal_line(username, sizeof(username)) )
|
if ( !read_terminal_line(input, sizeof(input)) )
|
||||||
{
|
{
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if ( errno && errno != EINTR )
|
if ( errno && errno != EINTR )
|
||||||
|
@ -347,14 +412,17 @@ int textual(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !strcmp(username, "exit") )
|
enum special_action action;
|
||||||
exit(0);
|
free(username);
|
||||||
if ( !strcmp(username, "poweroff") )
|
free(session);
|
||||||
exit(0);
|
username = NULL;
|
||||||
if ( !strcmp(username, "reboot") )
|
session = NULL;
|
||||||
exit(1);
|
if ( !parse_username(input, &username, &session, &action) )
|
||||||
if ( !strcmp(username, "halt") )
|
{
|
||||||
exit(2);
|
printf("Invalid username\n\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
handle_special(action);
|
||||||
|
|
||||||
if ( settermmode(0, pw_termmode) < 0 )
|
if ( settermmode(0, pw_termmode) < 0 )
|
||||||
err(2, "settermmode");
|
err(2, "settermmode");
|
||||||
|
@ -389,11 +457,10 @@ int textual(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !login(username) )
|
if ( !login(username, session) )
|
||||||
{
|
{
|
||||||
warn("logging in as %s", username);
|
warn("logging in as %s", username);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
|
||||||
|
* Copyright (c) 2023 dzwdz.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -35,7 +36,15 @@ struct check
|
||||||
bool pipe_nonblock;
|
bool pipe_nonblock;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool login(const char* username);
|
enum special_action
|
||||||
|
{
|
||||||
|
SPECIAL_ACTION_NONE,
|
||||||
|
SPECIAL_ACTION_POWEROFF,
|
||||||
|
SPECIAL_ACTION_REBOOT,
|
||||||
|
SPECIAL_ACTION_HALT,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool login(const char* username, const char* session);
|
||||||
bool check_real(const char* username, const char* password);
|
bool check_real(const char* username, const char* password);
|
||||||
bool check_begin(struct check* chk,
|
bool check_begin(struct check* chk,
|
||||||
const char* username,
|
const char* username,
|
||||||
|
@ -46,4 +55,10 @@ bool check(const char* username, const char* password);
|
||||||
int graphical(void);
|
int graphical(void);
|
||||||
int textual(void);
|
int textual(void);
|
||||||
|
|
||||||
|
bool parse_username(const char* input,
|
||||||
|
char** out_username,
|
||||||
|
char** out_session,
|
||||||
|
enum special_action* action);
|
||||||
|
void handle_special(enum special_action action);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue