You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ly/src/config.c

692 lines
15 KiB
C

#define _XOPEN_SOURCE 700
#include "config.h"
#include "cylgom.h"
#include "ini.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h> // login max length
#include <security/pam_appl.h>
struct lang lang = {0};
struct config config = {0};
char* info_line = NULL;
u16 compute_box_main_width()
{
u16 login_len = strlen(lang.login);
u16 password_len = strlen(lang.password);
u16 label_len = login_len > password_len ? login_len : password_len;
return 2 * config.margin_box_main_h + config.input_len + 1 + label_len;
}
// smart-dup for config loaders
void cfg_dup(char** name, const char* value)
{
// this is not a mistake, struct was initialized with zeros
// empty fields are zero-valued pointers because of that
// we probably don't care about that, but let's pretend systems
// where NULL != 0 actually exist and are used.
if (*name != 0)
{
free(*name);
}
*name = strdup(value);
}
int config_lang_handler(void* user, const char* section, const char* name, const char* value)
{
(void)(user);
if (strcmp(section, "box_main") == 0)
{
if (strcmp(name, "login") == 0)
{
cfg_dup(&lang.login, value);
}
else if (strcmp(name, "password") == 0)
{
cfg_dup(&lang.password, value);
}
else if (strcmp(name, "f1") == 0)
{
cfg_dup(&lang.f1, value);
}
else if (strcmp(name, "f2") == 0)
{
cfg_dup(&lang.f2, value);
}
else if (strcmp(name, "shell") == 0)
{
cfg_dup(&lang.shell, value);
}
else if (strcmp(name, "xinitrc") == 0)
{
cfg_dup(&lang.xinitrc, value);
}
else if (strcmp(name, "logout") == 0)
{
cfg_dup(&lang.logout, value);
}
else if (strcmp(name, "capslock") == 0)
{
cfg_dup(&lang.capslock, value);
}
else if (strcmp(name, "numlock") == 0)
{
cfg_dup(&lang.numlock, value);
}
else if (strcmp(name, "err_pam_buf") == 0)
{
cfg_dup(&lang.err_pam_buf, value);
}
else if (strcmp(name, "err_pam_sys") == 0)
{
cfg_dup(&lang.err_pam_sys, value);
}
else if (strcmp(name, "err_pam_auth") == 0)
{
cfg_dup(&lang.err_pam_auth, value);
}
else if (strcmp(name, "err_pam_cred_insufficient") == 0)
{
cfg_dup(&lang.err_pam_cred_insufficient, value);
}
else if (strcmp(name, "err_pam_authinfo_unavail") == 0)
{
cfg_dup(&lang.err_pam_authinfo_unavail, value);
}
else if (strcmp(name, "err_pam_maxtries") == 0)
{
cfg_dup(&lang.err_pam_maxtries, value);
}
else if (strcmp(name, "err_pam_user_unknown") == 0)
{
cfg_dup(&lang.err_pam_user_unknown, value);
}
else if (strcmp(name, "err_pam_acct_expired") == 0)
{
cfg_dup(&lang.err_pam_acct_expired, value);
}
else if (strcmp(name, "err_pam_authok_reqd") == 0)
{
cfg_dup(&lang.err_pam_authok_reqd, value);
}
else if (strcmp(name, "err_pam_perm_denied") == 0)
{
cfg_dup(&lang.err_pam_perm_denied, value);
}
else if (strcmp(name, "err_pam_cred_err") == 0)
{
cfg_dup(&lang.err_pam_cred_err, value);
}
else if (strcmp(name, "err_pam_cred_expired") == 0)
{
cfg_dup(&lang.err_pam_cred_expired, value);
}
else if (strcmp(name, "err_pam_cred_unavail") == 0)
{
cfg_dup(&lang.err_pam_cred_unavail, value);
}
else if (strcmp(name, "err_pam_session") == 0)
{
cfg_dup(&lang.err_pam_session, value);
}
else if (strcmp(name, "err_pam_abort") == 0)
{
cfg_dup(&lang.err_pam_abort, value);
}
else if (strcmp(name, "err_perm_group") == 0)
{
cfg_dup(&lang.err_perm_group, value);
}
else if (strcmp(name, "err_perm_user") == 0)
{
cfg_dup(&lang.err_perm_user, value);
}
else if (strcmp(name, "err_perm_dir") == 0)
{
cfg_dup(&lang.err_perm_dir, value);
}
else if (strcmp(name, "err_console_dev") == 0)
{
cfg_dup(&lang.err_console_dev, value);
}
}
return 1;
}
void config_lang_patch()
{
if (lang.login == 0)
{
lang.login = strdup("login:");
}
if (lang.password == 0)
{
lang.password = strdup("password:");
}
if (lang.f1 == 0)
{
lang.f1 = strdup("F1 shutdown");
}
if (lang.f2 == 0)
{
lang.f2 = strdup("F2 reboot");
}
if (lang.shell == 0)
{
lang.shell = strdup("shell");
}
if (lang.xinitrc == 0)
{
lang.xinitrc = strdup("xinitrc");
}
if (lang.logout == 0)
{
lang.logout = strdup("logout");
}
if (lang.capslock == 0)
{
lang.capslock = strdup("capslock");
}
if (lang.numlock == 0)
{
lang.numlock = strdup("numlock");
}
if (lang.err_pam_buf == 0)
{
lang.err_pam_buf = strdup("memory buffer error");
}
if (lang.err_pam_sys == 0)
{
lang.err_pam_sys = strdup("system error");
}
if (lang.err_pam_auth == 0)
{
lang.err_pam_auth = strdup("authentication error");
}
if (lang.err_pam_cred_insufficient == 0)
{
lang.err_pam_cred_insufficient = strdup("insufficient credentials");
}
if (lang.err_pam_authinfo_unavail == 0)
{
lang.err_pam_authinfo_unavail = strdup("failed to get user info");
}
if (lang.err_pam_maxtries == 0)
{
lang.err_pam_maxtries = strdup("reached maximum tries limit");
}
if (lang.err_pam_user_unknown == 0)
{
lang.err_pam_user_unknown = strdup("unknown user");
}
if (lang.err_pam_acct_expired == 0)
{
lang.err_pam_acct_expired = strdup("account expired");
}
if (lang.err_pam_authok_reqd == 0)
{
lang.err_pam_authok_reqd = strdup("token expired");
}
if (lang.err_pam_perm_denied == 0)
{
lang.err_pam_perm_denied = strdup("permission denied");
}
if (lang.err_pam_cred_err == 0)
{
lang.err_pam_cred_err = strdup("failed to set credentials");
}
if (lang.err_pam_cred_expired == 0)
{
lang.err_pam_cred_expired = strdup("credentials expired");
}
if (lang.err_pam_cred_unavail == 0)
{
lang.err_pam_cred_unavail = strdup("failed to get credentials");
}
if (lang.err_pam_session == 0)
{
lang.err_pam_session = strdup("session error");
}
if (lang.err_pam_abort == 0)
{
lang.err_pam_abort = strdup("pam transaction aborted");
}
if (lang.err_perm_group == 0)
{
lang.err_perm_group = strdup("failed to downgrade group permissions");
}
if (lang.err_perm_user == 0)
{
lang.err_perm_user = strdup("failed to downgrade user permissions");
}
if (lang.err_perm_dir == 0)
{
lang.err_perm_dir = strdup("failed to change current directory");
}
if (lang.err_console_dev == 0)
{
lang.err_console_dev = strdup("failed to access console");
}
}
void config_lang_free()
{
free(lang.login);
free(lang.password);
free(lang.f1);
free(lang.f2);
free(lang.shell);
free(lang.xinitrc);
free(lang.logout);
free(lang.capslock);
free(lang.numlock);
free(lang.err_pam_buf);
free(lang.err_pam_sys);
free(lang.err_pam_auth);
free(lang.err_pam_cred_insufficient);
free(lang.err_pam_authinfo_unavail);
free(lang.err_pam_maxtries);
free(lang.err_pam_user_unknown);
free(lang.err_pam_acct_expired);
free(lang.err_pam_authok_reqd);
free(lang.err_pam_perm_denied);
free(lang.err_pam_cred_err);
free(lang.err_pam_cred_expired);
free(lang.err_pam_cred_unavail);
free(lang.err_pam_session);
free(lang.err_pam_abort);
free(lang.err_perm_group);
free(lang.err_perm_user);
free(lang.err_perm_dir);
free(lang.err_console_dev);
}
int config_config_handler(void* user, const char* section, const char* name, const char* value)
{
(void)(user);
if (strcmp(section, "box_main") == 0)
{
if (strcmp(name, "margin_box_main_h") == 0)
{
config.margin_box_main_h = abs(atoi(value));
}
else if (strcmp(name, "margin_box_main_v") == 0)
{
config.margin_box_main_v = abs(atoi(value));
}
else if (strcmp(name, "input_len") == 0)
{
config.input_len = abs(atoi(value));
}
else if (strcmp(name, "bg") == 0)
{
config.bg = strtoul(value, NULL, 16);
}
else if (strcmp(name, "fg") == 0)
{
config.fg = strtoul(value, NULL, 16);
}
else if (strcmp(name, "max_desktop_len") == 0)
{
config.max_desktop_len = abs(atoi(value));
}
else if (strcmp(name, "max_login_len") == 0)
{
config.max_login_len = abs(atoi(value));
}
else if (strcmp(name, "max_password_len") == 0)
{
config.max_password_len = abs(atoi(value));
}
else if (strcmp(name, "min_refresh_delta") == 0)
{
config.min_refresh_delta = abs(atoi(value));
}
else if (strcmp(name, "blank_box") == 0)
{
config.blank_box = (atoi(value) > 0) ? true : false;
}
else if (strcmp(name, "force_update") == 0)
{
config.force_update = (atoi(value) > 0) ? true : false;
}
else if (strcmp(name, "animate") == 0)
{
config.animate = abs(atoi(value));
}
else if (strcmp(name, "xsessions") == 0)
{
cfg_dup(&config.xsessions, value);
}
else if (strcmp(name, "service_name") == 0)
{
cfg_dup(&config.service_name, value);
}
else if (strcmp(name, "tty_id") == 0)
{
config.tty_id = abs(atoi(value));
}
else if (strcmp(name, "x_cmd") == 0)
{
cfg_dup(&config.x_cmd, value);
}
else if (strcmp(name, "x_cmd_setup") == 0)
{
cfg_dup(&config.x_cmd_setup, value);
}
else if (strcmp(name, "mcookie_cmd") == 0)
{
cfg_dup(&config.mcookie_cmd, value);
}
else if (strcmp(name, "xauthority") == 0)
{
cfg_dup(&config.xauthority, value);
}
else if (strcmp(name, "path") == 0)
{
cfg_dup(&config.path, value);
}
else if (strcmp(name, "shutdown_cmd") == 0)
{
cfg_dup(&config.shutdown_cmd, value);
}
else if (strcmp(name, "console_dev") == 0)
{
cfg_dup(&config.console_dev, value);
}
else if (strcmp(name, "tty") == 0)
{
config.tty = abs(atoi(value));
}
else if (strcmp(name, "save") == 0)
{
config.save = (atoi(value) > 0) ? true : false;
}
else if (strcmp(name, "load") == 0)
{
config.load = (atoi(value) > 0) ? true : false;
}
else if (strcmp(name, "save_file") == 0)
{
cfg_dup(&config.save_file, value);
}
else if (strcmp(name, "custom_res") == 0)
{
config.custom_res = (atoi(value) > 0) ? true : false;
}
else if (strcmp(name, "res_width") == 0)
{
config.res_width = abs(atoi(value));
}
else if (strcmp(name, "res_height") == 0)
{
config.res_height = abs(atoi(value));
}
else if (strcmp(name, "hide_x") == 0)
{
config.hide_x = (atoi(value) > 0) ? true : false;
}
else if (strcmp(name, "hide_x_save_log") == 0)
{
cfg_dup(&config.hide_x_save_log, value);
}
else if (strcmp(name, "lang") == 0)
{
cfg_dup(&config.lang, value);
}
}
return 1;
}
void config_config_patch()
{
if (config.margin_box_main_h == 0)
{
config.margin_box_main_h = 2;
}
if (config.margin_box_main_v == 0)
{
config.margin_box_main_v = 1;
}
if (config.input_len == 0)
{
config.input_len = 34;
}
if (config.bg == 0)
{
config.bg = 0x000000;
}
if (config.fg == 0)
{
config.fg = 0xffffff;
}
if (config.max_desktop_len == 0)
{
// arbitrary one
config.max_desktop_len = 100;
}
if (config.max_login_len == 0)
{
// for "useradd" the max is 32
config.max_login_len = 32;
#ifdef LOGIN_NAME_MAX
if (config.max_login_len < LOGIN_NAME_MAX)
{
// the posix standard specifies it includes the terminating NULL
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/limits.h.html
config.max_login_len = LOGIN_NAME_MAX - 1;
}
#endif
#ifdef _POSIX_LOGIN_NAME_MAX
if (config.max_login_len < _POSIX_LOGIN_NAME_MAX)
{
config.max_login_len = _POSIX_LOGIN_NAME_MAX - 1;
}
#endif
}
if (config.max_password_len == 0)
{
// for "passwd" the max is 200
// https://github.com/shadow-maint/shadow/blob/master/src/passwd.c#L217
// for "sudo" it is 255
// https://www.sudo.ws/repos/sudo/file/tip/include/sudo_plugin.h
// https://www.sudo.ws/repos/sudo/file/tip/src/sudo.c
// "su" and "login" user linux-pam and do not seem to have a limit
config.max_password_len = 255;
}
if (config.min_refresh_delta == 0)
{
config.min_refresh_delta = 1000;
}
// commenting theses because the defaults are 0
//#if 0
if (config.blank_box == 0)
{
config.blank_box = false;
}
if (config.force_update == 0)
{
config.force_update = false;
}
if (config.animate == 0)
{
config.animate = 0;
}
//#endif
if (config.xsessions == 0)
{
config.xsessions = strdup("/usr/share/xsessions");
}
if (config.service_name == 0)
{
config.service_name = strdup("login");
}
if (config.tty_id == 0)
{
config.tty_id = 2;
}
if (config.x_cmd == 0)
{
config.x_cmd = strdup("/usr/bin/X");
}
if (config.x_cmd_setup == 0)
{
config.x_cmd_setup = strdup("/etc/ly/xsetup.sh");
}
if (config.mcookie_cmd == 0)
{
config.mcookie_cmd = strdup("/usr/bin/mcookie");
}
if (config.xauthority == 0)
{
config.xauthority = strdup(".lyxauth");
}
if (config.path == 0)
{
config.path = strdup("/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/env");
}
if (config.shutdown_cmd == 0)
{
config.shutdown_cmd = strdup("/sbin/shutdown");
}
if (config.console_dev == 0)
{
config.console_dev = strdup("/dev/console");
}
if (config.tty == 0)
{
config.tty = 2;
}
if (config.save_file == 0)
{
config.save_file = strdup("/etc/ly/ly.save");
}
if ((config.res_width == 0) || (config.res_height == 0))
{
config.custom_res = false;
}
if (config.hide_x_save_log == 0)
{
config.hide_x_save_log = strdup("/dev/null");
}
if (config.lang == 0)
{
config.lang = strdup("/etc/ly/lang/en.ini");
}
// fill secret parameters
config.box_main_w = compute_box_main_width();
config.box_main_h = 9;
}
void config_config_free()
{
free(config.xsessions);
free(config.service_name);
free(config.x_cmd);
free(config.x_cmd_setup);
free(config.mcookie_cmd);
free(config.xauthority);
free(config.path);
free(config.shutdown_cmd);
free(config.console_dev);
free(config.save_file);
free(config.hide_x_save_log);
free(config.lang);
}
// loads the ini configs
void config_load(const char* file_config)
{
// we don't care about this function's success
ini_parse(file_config, config_config_handler, NULL);
ini_parse(config.lang, config_lang_handler, NULL);
// because we check for missing strings anyway
config_lang_patch(); // config patch depends on lang
config_config_patch(); // so we call them in this order
}
void set_error(enum err error)
{
switch (error)
{
case ERR_PERM_GROUP:
info_line = lang.err_perm_group;
break;
case ERR_PERM_USER:
info_line = lang.err_perm_user;
break;
case ERR_PERM_DIR:
info_line = lang.err_perm_dir;
break;
default:
info_line = lang.err_pam_abort;
break;
}
}
void pam_diagnose(int error)
{
switch (error)
{
case PAM_BUF_ERR:
info_line = lang.err_pam_buf;
break;
case PAM_SYSTEM_ERR:
info_line = lang.err_pam_sys;
break;
case PAM_AUTH_ERR:
info_line = lang.err_pam_auth;
break;
case PAM_CRED_INSUFFICIENT:
info_line = lang.err_pam_cred_insufficient;
break;
case PAM_AUTHINFO_UNAVAIL:
info_line = lang.err_pam_authinfo_unavail;
break;
case PAM_MAXTRIES:
info_line = lang.err_pam_maxtries;
break;
case PAM_USER_UNKNOWN:
info_line = lang.err_pam_user_unknown;
break;
case PAM_ACCT_EXPIRED:
info_line = lang.err_pam_acct_expired;
break;
case PAM_NEW_AUTHTOK_REQD:
info_line = lang.err_pam_authok_reqd;
break;
case PAM_PERM_DENIED:
info_line = lang.err_pam_perm_denied;
break;
case PAM_CRED_ERR:
info_line = lang.err_pam_cred_err;
break;
case PAM_CRED_EXPIRED:
info_line = lang.err_pam_cred_expired;
break;
case PAM_CRED_UNAVAIL:
info_line = lang.err_pam_cred_unavail;
break;
case PAM_SESSION_ERR:
info_line = lang.err_pam_session;
break;
case PAM_ABORT:
default:
info_line = lang.err_pam_abort;
break;
}
}