mirror of
https://github.com/javalsai/lidm.git
synced 2025-08-31 18:38:00 +02:00
chore: modularize PAM
also helps with sanitizing the code flow when spawning the child, more code though
This commit is contained in:
20
.clang-tidy
20
.clang-tidy
@@ -16,15 +16,13 @@ Checks: >
|
|||||||
readability-*,
|
readability-*,
|
||||||
-readability-braces-around-statements,
|
-readability-braces-around-statements,
|
||||||
|
|
||||||
WarningsAsErrors: ''
|
WarningsAsErrors: ""
|
||||||
HeaderFilterRegex: '.*'
|
HeaderFilterRegex: ".*"
|
||||||
FormatStyle: file
|
FormatStyle: file
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: readability-magic-numbers.IgnoredIntegerValues
|
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||||
value: '0;1;2;3;10;255'
|
value: "0;1;2;3;10;255"
|
||||||
# - key: readability-magic-numbers.IgnoredValues
|
|
||||||
# value: '0;1;2;3;10;255'
|
|
||||||
- key: readability-identifier-naming.VariableCase
|
- key: readability-identifier-naming.VariableCase
|
||||||
value: lower_case
|
value: lower_case
|
||||||
- key: readability-identifier-naming.ConstantParameterCase
|
- key: readability-identifier-naming.ConstantParameterCase
|
||||||
@@ -34,14 +32,14 @@ CheckOptions:
|
|||||||
value: "UPPER_CASE"
|
value: "UPPER_CASE"
|
||||||
|
|
||||||
- key: readability-identifier-length.VariableThreshold
|
- key: readability-identifier-length.VariableThreshold
|
||||||
value: '2'
|
value: "2"
|
||||||
- key: readability-identifier-length.ParameterThreshold
|
- key: readability-identifier-length.ParameterThreshold
|
||||||
value: '2'
|
value: "2"
|
||||||
- key: readability-identifier-length.LocalConstantThreshold
|
- key: readability-identifier-length.LocalConstantThreshold
|
||||||
value: '2'
|
value: "2"
|
||||||
- key: readability-identifier-length.MemberThreshold
|
- key: readability-identifier-length.MemberThreshold
|
||||||
value: '2'
|
value: "2"
|
||||||
- key: readability-identifier-length.MinimumParameterNameLength
|
- key: readability-identifier-length.MinimumParameterNameLength
|
||||||
value: '2'
|
value: "2"
|
||||||
- key: readability-identifier-length.MinimumVariableNameLength
|
- key: readability-identifier-length.MinimumVariableNameLength
|
||||||
value: '2'
|
value: "2"
|
||||||
|
4
Makefile
4
Makefile
@@ -16,10 +16,10 @@ ALLFLAGS=$(CFLAGS) $(CPPFLAGS) -I$(IDIR)
|
|||||||
|
|
||||||
LIBS=-lpam
|
LIBS=-lpam
|
||||||
|
|
||||||
_DEPS = version.h log.h util.h ui.h ui_state.h config.h desktop.h desktop_exec.h auth.h ofield.h efield.h keys.h users.h sessions.h chvt.h macros.h launch_state.h
|
_DEPS = version.h log.h util.h ui.h ui_state.h config.h pam.h desktop.h desktop_exec.h auth.h ofield.h efield.h keys.h users.h sessions.h chvt.h macros.h launch_state.h
|
||||||
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
|
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
|
||||||
|
|
||||||
_OBJ = main.o log.o util.o ui.o ui_state.o config.o desktop.o desktop_exec.o auth.o ofield.o efield.o users.o sessions.o chvt.o launch_state.o
|
_OBJ = main.o log.o util.o ui.o ui_state.o config.o pam.o desktop.o desktop_exec.o auth.o ofield.o efield.o users.o sessions.o chvt.o launch_state.o
|
||||||
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
|
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
|
||||||
|
|
||||||
INFO_GIT_REV?=$$(git describe --long --tags --always || echo '?')
|
INFO_GIT_REV?=$$(git describe --long --tags --always || echo '?')
|
||||||
|
34
include/pam.h
Normal file
34
include/pam.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef PAM_H
|
||||||
|
#define PAM_H
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <security/_pam_types.h>
|
||||||
|
#include <security/pam_appl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
#include "sessions.h"
|
||||||
|
|
||||||
|
#define PAMH_ERR_NOERR 0
|
||||||
|
#define PAMH_ERR_ALLOC 1
|
||||||
|
#define PAMH_ERR_ERRNO 2
|
||||||
|
#define PAMH_ERR_NOERRNO 3
|
||||||
|
|
||||||
|
struct pamh_getenv_status {
|
||||||
|
char error_flag;
|
||||||
|
union {
|
||||||
|
char** envlist;
|
||||||
|
const char* errfn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Doesn't include `source`s
|
||||||
|
struct pamh_getenv_status pamh_get_complete_env(pam_handle_t* handle,
|
||||||
|
char* NNULLABLE user,
|
||||||
|
struct passwd* NNULLABLE pw,
|
||||||
|
enum session_type session_typ);
|
||||||
|
|
||||||
|
void free_envlist(char** NNULLABLE envlist);
|
||||||
|
pam_handle_t* NULLABLE get_pamh(char* NNULLABLE user, char* NNULLABLE passwd);
|
||||||
|
|
||||||
|
#endif /* PAM_H */
|
@@ -30,6 +30,8 @@ struct Vector {
|
|||||||
void** pages;
|
void** pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Vector vec_from_raw(void** raw);
|
||||||
|
void** vec_as_raw(struct Vector self);
|
||||||
extern const struct Vector VEC_NEW;
|
extern const struct Vector VEC_NEW;
|
||||||
int vec_resize(struct Vector* self, size_t size);
|
int vec_resize(struct Vector* self, size_t size);
|
||||||
int vec_reserve(struct Vector* self, size_t size);
|
int vec_reserve(struct Vector* self, size_t size);
|
||||||
|
216
src/auth.c
216
src/auth.c
@@ -7,79 +7,24 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "desktop_exec.h"
|
#include "desktop_exec.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "pam.h"
|
||||||
#include "sessions.h"
|
#include "sessions.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "unistd.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int pam_conversation(int num_msg, const struct pam_message** msg,
|
void try_source_file(struct Vector* NNULLABLE vec_envlist, char* filepath) {
|
||||||
struct pam_response** resp, void* appdata_ptr) {
|
log_printf("sourcing %s\n", filepath);
|
||||||
struct pam_response* reply =
|
FILE* file2source = fopen(filepath, "r");
|
||||||
(struct pam_response*)malloc(sizeof(struct pam_response) * num_msg);
|
if (file2source == NULL) {
|
||||||
if (!reply) {
|
log_printf("error sourcing %s\n", filepath);
|
||||||
return PAM_BUF_ERR;
|
return;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < num_msg; i++) {
|
|
||||||
reply[i].resp = NULL;
|
|
||||||
reply[i].resp_retcode = 0;
|
|
||||||
if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF ||
|
|
||||||
msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
|
|
||||||
char* input = (char*)appdata_ptr;
|
|
||||||
reply[i].resp = strdup(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*resp = reply;
|
|
||||||
return PAM_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PAM_SERVICE_FALLBACK
|
|
||||||
#define PAM_SERVICE_FALLBACK "login"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CHECK_PAM_RET(call) \
|
|
||||||
ret = (call); \
|
|
||||||
if (ret != PAM_SUCCESS) { \
|
|
||||||
pam_end(pamh, ret); \
|
|
||||||
return NULL; \
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_screen() {
|
|
||||||
printf("\x1b[H\x1b[J");
|
|
||||||
}
|
|
||||||
|
|
||||||
pam_handle_t* get_pamh(char* user, char* passwd) {
|
|
||||||
pam_handle_t* pamh = NULL;
|
|
||||||
struct pam_conv pamc = {pam_conversation, (void*)passwd};
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
char* pam_service_override = getenv("LIDM_PAM_SERVICE");
|
|
||||||
char* pam_service_name =
|
|
||||||
pam_service_override ? pam_service_override : PAM_SERVICE_FALLBACK;
|
|
||||||
|
|
||||||
CHECK_PAM_RET(pam_start(pam_service_name, user, &pamc, &pamh))
|
|
||||||
CHECK_PAM_RET(pam_authenticate(pamh, 0))
|
|
||||||
CHECK_PAM_RET(pam_acct_mgmt(pamh, 0))
|
|
||||||
CHECK_PAM_RET(pam_setcred(pamh, PAM_ESTABLISH_CRED))
|
|
||||||
CHECK_PAM_RET(pam_open_session(pamh, 0))
|
|
||||||
CHECK_PAM_RET(pam_setcred(pamh, PAM_REINITIALIZE_CRED))
|
|
||||||
|
|
||||||
return pamh;
|
|
||||||
}
|
|
||||||
#undef CHECK_PAM_RET
|
|
||||||
|
|
||||||
void* shmalloc(size_t size) {
|
|
||||||
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
|
||||||
-1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sourceFileTry(char* file) {
|
|
||||||
FILE* file2source = fopen(file, "r");
|
|
||||||
if (file2source == NULL) return;
|
|
||||||
|
|
||||||
char* line = NULL;
|
char* line = NULL;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
@@ -89,13 +34,10 @@ void sourceFileTry(char* file) {
|
|||||||
if (read == 0 || (read > 0 && *line == '#')) continue;
|
if (read == 0 || (read > 0 && *line == '#')) continue;
|
||||||
if (line[read - 1] == '\n') line[read - 1] = '\0';
|
if (line[read - 1] == '\n') line[read - 1] = '\0';
|
||||||
|
|
||||||
/* printf("Retrieved line of length %zu:\n", read); */
|
|
||||||
/* printf("%s\n", line); */
|
|
||||||
for (size_t i = 1; i < read; i++) {
|
for (size_t i = 1; i < read; i++) {
|
||||||
if (line[i] == '=') {
|
if (line[i] == '=') {
|
||||||
/* printf("FOUND '='!\n"); */
|
vec_push(vec_envlist, (void*)line);
|
||||||
line[i] = '\0';
|
line = NULL;
|
||||||
setenv(line, &line[i + 1], 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,52 +47,27 @@ void sourceFileTry(char* file) {
|
|||||||
(void)fclose(file2source);
|
(void)fclose(file2source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void moarEnv(char* user, struct session session, struct passwd* pw,
|
void source_paths(struct Vector* NNULLABLE vec_envlist,
|
||||||
struct config* config) {
|
struct Vector* NNULLABLE abs_source,
|
||||||
if (chdir(pw->pw_dir) == -1) print_errno("can't chdir to user home");
|
const char* NULLABLE user_home,
|
||||||
|
struct Vector* NNULLABLE user_source) {
|
||||||
setenv("HOME", pw->pw_dir, true);
|
for (size_t i = 0; i < abs_source->length; i++) {
|
||||||
setenv("USER", pw->pw_name, true);
|
char* path = vec_get(abs_source, i);
|
||||||
setenv("SHELL", pw->pw_shell, true);
|
try_source_file(vec_envlist, path);
|
||||||
// TERM
|
|
||||||
setenv("LOGNAME", pw->pw_name, true);
|
|
||||||
// MAIL?
|
|
||||||
|
|
||||||
// PATH?
|
|
||||||
|
|
||||||
char* xdg_session_type = "unknown";
|
|
||||||
if (session.type == SHELL) xdg_session_type = "tty";
|
|
||||||
if (session.type == XORG) xdg_session_type = "x11";
|
|
||||||
if (session.type == WAYLAND) xdg_session_type = "wayland";
|
|
||||||
setenv("XDG_SESSION_TYPE", xdg_session_type, true);
|
|
||||||
|
|
||||||
printf("\n\n\n\n\x1b[1m");
|
|
||||||
for (size_t i = 0; i < config->behavior.source.length; i++) {
|
|
||||||
/* printf("DEBUG(source)!!!! %d %s\n", i, (char*)vec_get(&behavior->source,
|
|
||||||
* i)); */
|
|
||||||
sourceFileTry((char*)vec_get(&config->behavior.source, i));
|
|
||||||
}
|
}
|
||||||
/* printf("\n"); */
|
|
||||||
|
|
||||||
if (pw->pw_dir) {
|
if (user_home)
|
||||||
const char* home = pw->pw_dir;
|
for (size_t i = 0; i < user_source->length; i++) {
|
||||||
size_t home_len = strlen(home);
|
char* path = NULL;
|
||||||
|
asprintf(&path, "%s/%s", user_home, (char*)vec_get(user_source, i));
|
||||||
for (size_t i = 0; i < config->behavior.user_source.length; i++) {
|
if (!path) {
|
||||||
const char* filename = (char*)vec_get(&config->behavior.user_source, i);
|
log_puts("alloc failure on user source\n");
|
||||||
size_t filename_len = strlen(filename);
|
continue;
|
||||||
|
}
|
||||||
size_t path_len = home_len + 1 + filename_len + 1; // nullbyte and slash
|
try_source_file(vec_envlist, path);
|
||||||
char* path = malloc(path_len);
|
}
|
||||||
if (!path) continue; // can't bother
|
else {
|
||||||
|
log_puts("user has no home\n");
|
||||||
memcpy(path, home, home_len);
|
|
||||||
path[home_len] = '/'; // assume pw_dir doesn't start with '/' :P
|
|
||||||
memcpy(&path[home_len + 1], filename, filename_len);
|
|
||||||
path[path_len - 1] = '\0';
|
|
||||||
|
|
||||||
sourceFileTry(path);
|
|
||||||
free(path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +80,6 @@ void moarEnv(char* user, struct session session, struct passwd* pw,
|
|||||||
/*setenv("XDG_SESSION_ID", "1", true);*/
|
/*setenv("XDG_SESSION_ID", "1", true);*/
|
||||||
/*setenv("XDG_SESSION_DESKTOP", , true);*/
|
/*setenv("XDG_SESSION_DESKTOP", , true);*/
|
||||||
/*setenv("XDG_SEAT", "seat0", true);*/
|
/*setenv("XDG_SEAT", "seat0", true);*/
|
||||||
}
|
|
||||||
|
|
||||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||||
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
||||||
@@ -196,41 +112,31 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool* reach_session = shmalloc(sizeof(bool));
|
struct pamh_getenv_status env_ret =
|
||||||
if (reach_session == NULL) {
|
pamh_get_complete_env(pamh, user, pw, session.type);
|
||||||
perror("error allocating shared memory");
|
if (env_ret.error_flag != PAMH_ERR_NOERR) {
|
||||||
|
if (env_ret.error_flag == PAMH_ERR_ALLOC) {
|
||||||
|
print_err("allocator error");
|
||||||
|
} else if (env_ret.error_flag == PAMH_ERR_ERRNO) {
|
||||||
|
print_errno(env_ret.errfn);
|
||||||
|
} else if (env_ret.error_flag == PAMH_ERR_NOERRNO) {
|
||||||
|
print_err(env_ret.errfn);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist);
|
||||||
|
source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir,
|
||||||
|
&config->behavior.user_source);
|
||||||
|
char** envlist = (char**)vec_as_raw(envlist_vec);
|
||||||
|
if (!envlist) {
|
||||||
|
print_err("vec alloc error");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*reach_session = false;
|
|
||||||
|
|
||||||
uint pid = fork();
|
uint pid = fork();
|
||||||
if (pid == 0) { // child
|
if (pid == 0) { // child
|
||||||
char* term = NULL;
|
if (chdir(pw->pw_dir) == -1) print_errno("can't chdir to user home");
|
||||||
char* getterm = getenv("TERM");
|
|
||||||
// TODO: handle malloc error
|
|
||||||
if (getterm != NULL) term = strdup(getterm);
|
|
||||||
if (clearenv() != 0) {
|
|
||||||
print_errno("clearenv");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
char** envlist = pam_getenvlist(pamh);
|
|
||||||
if (envlist == NULL) {
|
|
||||||
print_errno("pam_getenvlist");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; envlist[i] != NULL; i++) {
|
|
||||||
putenv(envlist[i]);
|
|
||||||
}
|
|
||||||
// FIXME: path hotfix
|
|
||||||
putenv("PATH=/bin:/usr/bin");
|
|
||||||
if (term != NULL) {
|
|
||||||
setenv("TERM", term, true);
|
|
||||||
free(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
free((void*)envlist);
|
|
||||||
moarEnv(user, session, pw, config);
|
|
||||||
|
|
||||||
// TODO: chown stdin to user
|
// TODO: chown stdin to user
|
||||||
// does it inherit stdin from parent and
|
// does it inherit stdin from parent and
|
||||||
@@ -251,36 +157,30 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
|||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb != NULL) cb();
|
if (cb) cb();
|
||||||
|
|
||||||
*reach_session = true;
|
printf("\x1b[0m\x1b[H\x1b[J");
|
||||||
|
(void)fflush(stdout);
|
||||||
// TODO: test existence of executable with TryExec
|
|
||||||
printf("\x1b[0m");
|
|
||||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
|
||||||
if (session.type == SHELL) {
|
if (session.type == SHELL) {
|
||||||
clear_screen();
|
execle(session.exec, session.exec, NULL, envlist);
|
||||||
(void)fflush(stdout);
|
|
||||||
execlp(session.exec, session.exec, NULL);
|
|
||||||
} else if (session.type == XORG || session.type == WAYLAND) {
|
} else if (session.type == XORG || session.type == WAYLAND) {
|
||||||
clear_screen();
|
// TODO: test existence of executable with TryExec
|
||||||
(void)fflush(stdout);
|
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
execvp(desktop_exec[0], desktop_exec);
|
execve(desktop_exec[0], desktop_exec, envlist);
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
free_parsed_args(desktop_count, desktop_exec);
|
free_parsed_args(desktop_count, desktop_exec);
|
||||||
}
|
}
|
||||||
perror("exec error");
|
perror("exec error");
|
||||||
(void)fputs("failure calling session\n", stderr);
|
(void)fputs("failure calling session\n", stderr);
|
||||||
} else {
|
} else {
|
||||||
pid_t child_pid = (pid_t)pid;
|
int exit_code;
|
||||||
waitpid(child_pid, NULL, 0);
|
waitpid((pid_t)pid, &exit_code, 0);
|
||||||
|
|
||||||
pam_setcred(pamh, PAM_DELETE_CRED);
|
pam_setcred(pamh, PAM_DELETE_CRED);
|
||||||
pam_close_session(pamh, 0);
|
pam_close_session(pamh, 0);
|
||||||
pam_end(pamh, PAM_SUCCESS);
|
pam_end(pamh, PAM_SUCCESS);
|
||||||
|
|
||||||
if (*reach_session == false) return false;
|
if (exit_code != 0) return false;
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
167
src/pam.c
Normal file
167
src/pam.c
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
#include <pwd.h>
|
||||||
|
#include <security/_pam_types.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
#include "pam.h"
|
||||||
|
#include "sessions.h"
|
||||||
|
|
||||||
|
struct envpair {
|
||||||
|
const char* NNULLABLE name;
|
||||||
|
char* NULLABLE value;
|
||||||
|
};
|
||||||
|
|
||||||
|
char* NULLABLE make_env_kv(const char* NNULLABLE key, char* NNULLABLE value) {
|
||||||
|
char* buf = NULL;
|
||||||
|
asprintf(&buf, "%s=%s", key, value);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_envlist(char** NNULLABLE envlist) {
|
||||||
|
for (char** ptr = envlist; *ptr; ptr++)
|
||||||
|
free(*ptr);
|
||||||
|
free((void*)envlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NULL when allocation failure
|
||||||
|
// in any case, envlist would be freed after this function
|
||||||
|
char** NULLABLE merge_envlist(char** NNULLABLE envlist, struct envpair extra[],
|
||||||
|
size_t extra_len) {
|
||||||
|
size_t envlist_len = 0;
|
||||||
|
while (envlist[envlist_len])
|
||||||
|
envlist_len++;
|
||||||
|
|
||||||
|
size_t nonnullelems = 0;
|
||||||
|
for (size_t i = 0; i < extra_len; i++) {
|
||||||
|
if (extra[i].value) nonnullelems++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t new_envlist_len = envlist_len + nonnullelems + 1;
|
||||||
|
char** new_envlist =
|
||||||
|
(char**)realloc((void*)envlist, sizeof(char*) * new_envlist_len);
|
||||||
|
if (!new_envlist) {
|
||||||
|
free_envlist(envlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(readability-identifier-length)
|
||||||
|
size_t k = 0;
|
||||||
|
for (size_t i = 0; i < extra_len; i++) {
|
||||||
|
if (!extra[i].value) continue;
|
||||||
|
char* env_kv = make_env_kv(extra[i].name, extra[i].value);
|
||||||
|
if (!env_kv) goto free_new_envlist_extra;
|
||||||
|
new_envlist[envlist_len + k++] = env_kv;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_envlist[envlist_len + nonnullelems] = NULL;
|
||||||
|
return new_envlist;
|
||||||
|
|
||||||
|
free_new_envlist_extra:
|
||||||
|
for (size_t j = 0; j < envlist_len + k; j++) {
|
||||||
|
free(new_envlist[envlist_len + j]);
|
||||||
|
}
|
||||||
|
free((void*)new_envlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* NULLABLE xdg_ssession_type_str(enum session_type typ) {
|
||||||
|
char* xdg_session_type = NULL;
|
||||||
|
if (typ == SHELL) xdg_session_type = "tty";
|
||||||
|
if (typ == XORG) xdg_session_type = "x11";
|
||||||
|
if (typ == WAYLAND) xdg_session_type = "wayland";
|
||||||
|
return xdg_session_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FAIL_ALLOC(status) \
|
||||||
|
{ \
|
||||||
|
(status).error_flag = PAMH_ERR_ALLOC; \
|
||||||
|
return (status); \
|
||||||
|
}
|
||||||
|
#define FAIL(status, ERR, ERRFN) \
|
||||||
|
{ \
|
||||||
|
(status).error_flag = (ERR); \
|
||||||
|
(status).errfn = (ERRFN); \
|
||||||
|
return (status); \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pamh_getenv_status pamh_get_complete_env(pam_handle_t* handle,
|
||||||
|
char* NNULLABLE user,
|
||||||
|
struct passwd* NNULLABLE pw,
|
||||||
|
enum session_type session_typ) {
|
||||||
|
struct pamh_getenv_status status;
|
||||||
|
char** envlist = pam_getenvlist(handle);
|
||||||
|
if (!envlist) FAIL(status, PAMH_ERR_ERRNO, "pam_getenvlist");
|
||||||
|
|
||||||
|
struct envpair extra_env[] = {
|
||||||
|
{"TERM", getenv("TERM")},
|
||||||
|
{"PATH", getenv("PATH")},
|
||||||
|
{"HOME", pw->pw_dir},
|
||||||
|
{"USER", pw->pw_name},
|
||||||
|
{"SHELL", pw->pw_shell},
|
||||||
|
{"LOGNAME", pw->pw_name},
|
||||||
|
{"XDG_SESSION_TYPE", xdg_ssession_type_str(session_typ)}};
|
||||||
|
|
||||||
|
status.error_flag = PAMH_ERR_NOERR;
|
||||||
|
status.envlist = merge_envlist(envlist, extra_env, LEN(extra_env));
|
||||||
|
if (!status.envlist) FAIL_ALLOC(status);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef FAIL
|
||||||
|
#undef FAIL_ALLOC
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
|
||||||
|
int pam_conversation(int num_msg, const struct pam_message** msg,
|
||||||
|
struct pam_response** resp, void* appdata_ptr) {
|
||||||
|
struct pam_response* reply = malloc(sizeof(struct pam_response) * num_msg);
|
||||||
|
if (!reply) {
|
||||||
|
return PAM_BUF_ERR;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < num_msg; i++) {
|
||||||
|
reply[i].resp = NULL;
|
||||||
|
reply[i].resp_retcode = 0;
|
||||||
|
if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF ||
|
||||||
|
msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
|
||||||
|
char* input = (char*)appdata_ptr;
|
||||||
|
reply[i].resp = strdup(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*resp = reply;
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PAM_SERVICE_FALLBACK
|
||||||
|
#define PAM_SERVICE_FALLBACK "login"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CHECK_PAM_RET(call) \
|
||||||
|
ret = (call); \
|
||||||
|
if (ret != PAM_SUCCESS) { \
|
||||||
|
pam_end(pamh, ret); \
|
||||||
|
return NULL; \
|
||||||
|
}
|
||||||
|
pam_handle_t* get_pamh(char* user, char* passwd) {
|
||||||
|
pam_handle_t* pamh = NULL;
|
||||||
|
struct pam_conv pamc = {pam_conversation, (void*)passwd};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
char* pam_service_override = getenv("LIDM_PAM_SERVICE");
|
||||||
|
char* pam_service_name =
|
||||||
|
pam_service_override ? pam_service_override : PAM_SERVICE_FALLBACK;
|
||||||
|
|
||||||
|
CHECK_PAM_RET(pam_start(pam_service_name, user, &pamc, &pamh))
|
||||||
|
CHECK_PAM_RET(pam_authenticate(pamh, 0))
|
||||||
|
CHECK_PAM_RET(pam_acct_mgmt(pamh, 0))
|
||||||
|
CHECK_PAM_RET(pam_setcred(pamh, PAM_ESTABLISH_CRED))
|
||||||
|
CHECK_PAM_RET(pam_open_session(pamh, 0))
|
||||||
|
CHECK_PAM_RET(pam_setcred(pamh, PAM_REINITIALIZE_CRED))
|
||||||
|
|
||||||
|
return pamh;
|
||||||
|
}
|
||||||
|
#undef CHECK_PAM_RET
|
17
src/util.c
17
src/util.c
@@ -147,6 +147,23 @@ const struct Vector VEC_NEW = {
|
|||||||
.pages = NULL,
|
.pages = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Vector vec_from_raw(void** raw) {
|
||||||
|
size_t len = 0;
|
||||||
|
while (raw[len])
|
||||||
|
len++;
|
||||||
|
|
||||||
|
return (struct Vector){
|
||||||
|
.length = len,
|
||||||
|
.capacity = len,
|
||||||
|
.pages = raw,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void** vec_as_raw(struct Vector self) {
|
||||||
|
if (vec_push(&self, NULL) != 0) return NULL;
|
||||||
|
return self.pages;
|
||||||
|
}
|
||||||
|
|
||||||
int vec_resize(struct Vector* self, size_t size) {
|
int vec_resize(struct Vector* self, size_t size) {
|
||||||
void** new_location =
|
void** new_location =
|
||||||
(void**)realloc((void*)self->pages, size * sizeof(void*));
|
(void**)realloc((void*)self->pages, size * sizeof(void*));
|
||||||
|
Reference in New Issue
Block a user