You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
516 lines
14 KiB
516 lines
14 KiB
#include <sys/types.h> |
|
#include <unistd.h> |
|
#include <grp.h> |
|
#ifndef HAVE_PAM |
|
#include <shadow.h> |
|
#include <crypt.h> |
|
#endif |
|
|
|
#include "entrance.h" |
|
|
|
#define HAVE_SHADOW 1 |
|
|
|
static char *_mcookie = NULL; |
|
static const char *_dname = NULL; |
|
static char **env; |
|
static char *_login = NULL; |
|
static unsigned char _logged = 0; |
|
//static Eina_List *_user_list = NULL; |
|
static pid_t _session_pid; |
|
static Eina_List *_xsessions = NULL; |
|
static int _entrance_session_userid_set(struct passwd *pwd); |
|
|
|
static void _entrance_session_run(struct passwd *pwd, const char *cmd, const char *cookie); |
|
|
|
static void _entrance_session_desktops_scan_file(const char *path); |
|
static void _entrance_session_desktops_scan(const char *dir); |
|
static void _entrance_session_desktops_init(void); |
|
//static void _entrance_session_desktops_shutdown(void); |
|
static const char *_entrance_session_find_command(const char *path, const char *session); |
|
static struct passwd *_entrance_session_session_open(); |
|
|
|
long |
|
entrance_session_seed_get(void) |
|
{ |
|
struct timespec ts; |
|
long pid = getpid(); |
|
long tm = time(NULL); |
|
if (clock_gettime(CLOCK_MONOTONIC, &ts)) |
|
ts.tv_sec = ts.tv_nsec = 0; |
|
return pid + tm + (ts.tv_sec ^ ts.tv_nsec); |
|
} |
|
|
|
static int |
|
_entrance_session_cookie_add(const char *mcookie, const char *display, |
|
const char *xauth_cmd, const char *auth_file) |
|
{ |
|
char buf[PATH_MAX]; |
|
FILE *cmd; |
|
|
|
if (!xauth_cmd || !auth_file) return 1; |
|
snprintf(buf, sizeof(buf), "%s -f %s -q", xauth_cmd, auth_file); |
|
PT("write auth on display %s with file %s\n", display, auth_file); |
|
cmd = popen(buf, "w"); |
|
if (!cmd) |
|
{ |
|
PT("write auth fail !\n"); |
|
return 1; |
|
} |
|
fprintf(cmd, "remove %s\n", display); |
|
fprintf(cmd, "add %s . %s\n", display, mcookie); |
|
fprintf(cmd, "exit\n"); |
|
pclose(cmd); |
|
return 0; |
|
} |
|
|
|
static int |
|
_entrance_session_userid_set(struct passwd *pwd) |
|
{ |
|
if (!pwd) |
|
{ |
|
PT("no passwd !\n"); |
|
return 1; |
|
} |
|
if (initgroups(pwd->pw_name, pwd->pw_gid) != 0) |
|
{ |
|
PT("can't init group\n"); |
|
return 1; |
|
} |
|
if (setgid(pwd->pw_gid) != 0) |
|
{ |
|
PT("can't set gid\n"); |
|
return 1; |
|
} |
|
if (setuid(pwd->pw_uid) != 0) |
|
{ |
|
PT("can't set uid\n"); |
|
return 1; |
|
} |
|
|
|
/* PT("name -> %s, gid -> %d, uid -> %d\n", |
|
pwd->pw_name, pwd->pw_gid, pwd->pw_uid); */ |
|
return 0; |
|
} |
|
|
|
static Eina_Bool |
|
_entrance_session_begin(struct passwd *pwd, const char *cookie) |
|
{ |
|
PT("Session Init\n"); |
|
if (pwd->pw_shell[0] == '\0') |
|
{ |
|
setusershell(); |
|
strcpy(pwd->pw_shell, getusershell()); |
|
endusershell(); |
|
} |
|
#ifdef HAVE_PAM |
|
char *term = getenv("TERM"); |
|
if (term) entrance_pam_env_set("TERM", term); |
|
entrance_pam_env_set("HOME", pwd->pw_dir); |
|
entrance_pam_env_set("SHELL", pwd->pw_shell); |
|
entrance_pam_env_set("USER", pwd->pw_name); |
|
entrance_pam_env_set("LOGNAME", pwd->pw_name); |
|
entrance_pam_env_set("PATH", entrance_config->session_path); |
|
entrance_pam_env_set("DISPLAY", _dname);//":0.0"); |
|
entrance_pam_env_set("MAIL", ""); |
|
entrance_pam_env_set("XAUTHORITY", cookie); |
|
entrance_pam_env_set("XDG_SESSION_CLASS", "greeter"); |
|
#endif |
|
return EINA_TRUE; |
|
} |
|
|
|
static void |
|
_entrance_session_run(struct passwd *pwd, const char *cmd, const char *cookie) |
|
{ |
|
//char **tmp; |
|
char buf[PATH_MAX]; |
|
pid_t pid; |
|
pid = fork(); |
|
if (pid == 0) |
|
{ |
|
|
|
PT("Session Run\n"); |
|
#ifdef HAVE_PAM |
|
env = entrance_pam_env_list_get(); |
|
entrance_pam_end(); |
|
#else |
|
int n = 0; |
|
char *term = getenv("TERM"); |
|
env = (char **)malloc(10 * sizeof(char *)); |
|
if(term) |
|
{ |
|
snprintf(buf, sizeof(buf), "TERM=%s", term); |
|
env[n++]=strdup(buf); |
|
} |
|
snprintf(buf, sizeof(buf), "HOME=%s", pwd->pw_dir); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "SHELL=%s", pwd->pw_shell); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "USER=%s", pwd->pw_name); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "LOGNAME=%s", pwd->pw_name); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "PATH=%s", entrance_config->session_path); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "DISPLAY=%s", _dname);//":0.0"); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "MAIL="); |
|
env[n++]=strdup(buf); |
|
snprintf(buf, sizeof(buf), "XAUTHORITY=%s", cookie); |
|
env[n++]=strdup(buf); |
|
env[n++]=0; |
|
#endif |
|
snprintf(buf, sizeof(buf), |
|
"%s %s ", |
|
entrance_config->command.session_start, |
|
pwd->pw_name); |
|
if (-1 == system(buf)) |
|
PT("Error on session start command\n"); |
|
if(_entrance_session_userid_set(pwd)) return; |
|
_entrance_session_cookie_add(_mcookie, _dname,//":0", |
|
entrance_config->command.xauth_path, cookie); |
|
if (chdir(pwd->pw_dir)) |
|
{ |
|
PT("change directory for user fail"); |
|
return; |
|
} |
|
// PT("Open %s`s session\n", pwd->pw_name); |
|
snprintf(buf, sizeof(buf), "%s/.entrance_session.log", pwd->pw_dir); |
|
remove(buf); |
|
|
|
#ifdef HAVE_CONSOLEKIT |
|
snprintf(buf, sizeof(buf), PACKAGE_BIN_DIR"/entrance_ck_launch %s > %s/.entrance_session.log 2>&1", |
|
cmd, pwd->pw_dir); |
|
#else |
|
snprintf(buf, sizeof(buf), "%s %s > %s/.entrance_session.log 2>&1", |
|
entrance_config->command.session_login, cmd, pwd->pw_dir); |
|
#endif |
|
PT("Executing: %s --login -c %s \n", pwd->pw_shell, buf); |
|
execle(pwd->pw_shell, pwd->pw_shell, "--login", "-c", buf, NULL, env); |
|
PT("The Xsessions are not launched :(\n"); |
|
} |
|
} |
|
|
|
void |
|
entrance_session_end(const char *user) |
|
{ |
|
#ifdef HAVE_PAM |
|
entrance_pam_init(PACKAGE, _dname, user); |
|
#endif |
|
char buf[PATH_MAX]; |
|
snprintf(buf, sizeof(buf), |
|
"%s %s ", entrance_config->command.session_stop, user); |
|
if (-1 == system(buf)) |
|
PT("Error on session stop command\n"); |
|
entrance_session_close(EINA_TRUE); |
|
} |
|
|
|
void |
|
entrance_session_close(const Eina_Bool opened) |
|
{ |
|
#ifdef HAVE_PAM |
|
entrance_pam_close_session(opened); |
|
entrance_pam_end(); |
|
entrance_pam_shutdown(); |
|
#endif |
|
} |
|
|
|
void |
|
entrance_session_pid_set(pid_t pid) |
|
{ |
|
fprintf(stderr, "%s: session pid %d\n", PACKAGE, pid); |
|
_session_pid = pid; |
|
} |
|
|
|
pid_t |
|
entrance_session_pid_get(void) |
|
{ |
|
return _session_pid; |
|
} |
|
|
|
void |
|
entrance_session_init(const char *dname) |
|
{ |
|
_dname = dname; |
|
} |
|
|
|
static const char *dig = "0123456789abcdef"; |
|
|
|
void |
|
entrance_session_cookie(void) |
|
{ |
|
uint16_t word; |
|
uint8_t hi, lo; |
|
int i; |
|
char buf[PATH_MAX]; |
|
|
|
_mcookie = calloc(33, sizeof(char)); |
|
_mcookie[0] = 'a'; |
|
|
|
srand(entrance_session_seed_get()); |
|
for (i=0; i<32; i+=4) |
|
{ |
|
word = rand() & 0xffff; |
|
lo = word & 0xff; |
|
hi = word >> 8; |
|
_mcookie[i] = dig[lo & 0x0f]; |
|
_mcookie[i+1] = dig[lo >> 4]; |
|
_mcookie[i+2] = dig[hi & 0x0f]; |
|
_mcookie[i+3] = dig[hi >> 4]; |
|
} |
|
// remove(file); |
|
snprintf(buf, sizeof(buf), "XAUTHORITY=%s", |
|
entrance_config->command.xauth_file); |
|
putenv(strdup(buf)); |
|
//PT("cookie %s \n", _mcookie); |
|
_entrance_session_cookie_add(_mcookie, _dname, |
|
entrance_config->command.xauth_path, |
|
entrance_config->command.xauth_file); |
|
_entrance_session_desktops_init(); |
|
} |
|
|
|
void |
|
entrance_session_shutdown(void) |
|
{ |
|
Entrance_Xsession *xsession; |
|
|
|
EINA_LIST_FREE(_xsessions, xsession) |
|
{ |
|
eina_stringshare_del(xsession->name); |
|
eina_stringshare_del(xsession->icon); |
|
if (xsession->command) eina_stringshare_del(xsession->command); |
|
free(xsession); |
|
} |
|
} |
|
|
|
Eina_Bool |
|
entrance_session_authenticate(const char *login, const char *passwd) |
|
{ |
|
Eina_Bool auth; |
|
_login = strdup(login); |
|
#ifdef HAVE_PAM |
|
entrance_pam_init(PACKAGE, _dname, NULL); |
|
auth = !!(!entrance_pam_auth_set(login, passwd) |
|
&& !entrance_pam_authenticate()); |
|
#else |
|
char *enc, *v; |
|
struct passwd *pwd; |
|
|
|
pwd = getpwnam(login); |
|
endpwent(); |
|
if(!pwd) |
|
return EINA_FALSE; |
|
#ifdef HAVE_SHADOW |
|
struct spwd *spd; |
|
spd = getspnam(pwd->pw_name); |
|
endspent(); |
|
if(spd) |
|
v = spd->sp_pwdp; |
|
else |
|
#endif |
|
v = pwd->pw_passwd; |
|
if(!v || *v == '\0') |
|
return EINA_TRUE; |
|
enc = crypt(passwd, v); |
|
auth = !strcmp(enc, v); |
|
#endif |
|
eina_stringshare_del(passwd); |
|
memset((char *)passwd, 0, strlen(passwd)); |
|
return auth; |
|
} |
|
|
|
static struct passwd * |
|
_entrance_session_session_open(void) |
|
{ |
|
#ifdef HAVE_PAM |
|
if (!entrance_pam_open_session()) |
|
return getpwnam(entrance_pam_item_get(ENTRANCE_PAM_ITEM_USER)); |
|
return NULL; |
|
#else |
|
return getpwnam(entrance_session_login_get()); |
|
#endif |
|
} |
|
|
|
Eina_Bool |
|
entrance_session_login(const char *session, Eina_Bool push) |
|
{ |
|
struct passwd *pwd; |
|
const char *cmd; |
|
char buf[PATH_MAX]; |
|
|
|
pwd = _entrance_session_session_open(); |
|
endpwent(); |
|
if (!pwd) return ECORE_CALLBACK_CANCEL; |
|
_logged = EINA_TRUE; |
|
snprintf(buf, sizeof(buf), "%s/.Xauthority", pwd->pw_dir); |
|
if (!_entrance_session_begin(pwd, buf)) |
|
{ |
|
fprintf(stderr, "Entrance: couldn't open session\n"); |
|
exit(1); |
|
} |
|
if (push) entrance_history_push(pwd->pw_name, session); |
|
cmd = _entrance_session_find_command(pwd->pw_dir, session); |
|
if (!cmd) |
|
{ |
|
PT("Error !!! No command to launch, can't open a session :'(\n"); |
|
return ECORE_CALLBACK_CANCEL; |
|
} |
|
PT("launching session %s for user %s\n", cmd, _login); |
|
_entrance_session_run(pwd, cmd, buf); |
|
snprintf(buf, sizeof(buf), "ENTRANCE_USER=%s", pwd->pw_name); |
|
putenv(buf); |
|
return ECORE_CALLBACK_CANCEL; |
|
} |
|
|
|
static const char * |
|
_entrance_session_find_command(const char *path, const char *session) |
|
{ |
|
Eina_List *l; |
|
Entrance_Xsession *xsession = NULL; |
|
char buf[PATH_MAX]; |
|
if (session) |
|
{ |
|
EINA_LIST_FOREACH(_xsessions, l, xsession) |
|
{ |
|
if (!strcmp(xsession->name, session)) |
|
{ |
|
if (xsession->command) |
|
return xsession->command; |
|
} |
|
} |
|
} |
|
snprintf(buf, sizeof(buf), "%s/%s", |
|
path, ".xinitrc"); |
|
if (ecore_file_can_exec(buf)) |
|
{ |
|
if (xsession) |
|
snprintf(buf, sizeof(buf), "%s/%s %s", |
|
path, ".xinitrc", xsession->command); |
|
return eina_stringshare_add(buf); |
|
} |
|
snprintf(buf, sizeof(buf), "%s/%s", |
|
path, ".Xsession"); |
|
if (ecore_file_can_exec(buf)) |
|
{ |
|
if (xsession) |
|
snprintf(buf, sizeof(buf), "%s/%s %s", |
|
path, ".Xsession", xsession->command); |
|
return eina_stringshare_add(buf); |
|
} |
|
if (ecore_file_exists("/etc/X11/xinit/xinitrc")) |
|
{ |
|
if (xsession) |
|
{ |
|
snprintf(buf, sizeof(buf), "sh /etc/X11/xinit/xinitrc %s", |
|
xsession->command); |
|
return eina_stringshare_add(buf); |
|
} |
|
return eina_stringshare_add("sh /etc/X11/xinit/xinitrc"); |
|
} |
|
return NULL; |
|
} |
|
|
|
char * |
|
entrance_session_login_get(void) |
|
{ |
|
return _login; |
|
} |
|
|
|
int |
|
entrance_session_logged_get(void) |
|
{ |
|
return !!_logged; |
|
} |
|
|
|
Eina_List * |
|
entrance_session_list_get(void) |
|
{ |
|
return _xsessions; |
|
} |
|
|
|
static void |
|
_entrance_session_desktops_init(void) |
|
{ |
|
char buf[PATH_MAX]; |
|
Eina_List *dirs; |
|
const char *path; |
|
Entrance_Xsession *xsession; |
|
Eina_List *l; |
|
|
|
xsession = calloc(1, sizeof(Entrance_Xsession)); |
|
xsession->name = eina_stringshare_add("System"); |
|
xsession->icon = eina_stringshare_add("entrance/system"); |
|
_xsessions = eina_list_append(_xsessions, xsession); |
|
|
|
efreet_desktop_type_alias(EFREET_DESKTOP_TYPE_APPLICATION, "XSession"); |
|
PT("scanning directory: "); |
|
/* Maybee need to scan other directories ? */ |
|
_entrance_session_desktops_scan("/etc/share/xsessions"); |
|
_entrance_session_desktops_scan("/etc/X11/dm/Sessions"); |
|
snprintf(buf, sizeof(buf), "%s/xsessions", efreet_data_home_get()); |
|
_entrance_session_desktops_scan(buf); |
|
dirs = efreet_data_dirs_get(); |
|
EINA_LIST_FOREACH(dirs, l, path) |
|
{ |
|
snprintf(buf, sizeof(buf), "%s/xsessions", path); |
|
_entrance_session_desktops_scan(buf); |
|
} |
|
fprintf(stderr, "\n"); |
|
PT("scan directory end\n"); |
|
} |
|
|
|
static void |
|
_entrance_session_desktops_scan(const char *dir) |
|
{ |
|
Eina_List *files; |
|
char *filename; |
|
char path[PATH_MAX]; |
|
|
|
if (ecore_file_is_dir(dir)) |
|
{ |
|
fprintf(stderr, " %s", dir); |
|
files = ecore_file_ls(dir); |
|
EINA_LIST_FREE(files, filename) |
|
{ |
|
snprintf(path, sizeof(path), "%s/%s", dir, filename); |
|
_entrance_session_desktops_scan_file(path); |
|
free(filename); |
|
} |
|
} |
|
} |
|
|
|
static void |
|
_entrance_session_desktops_scan_file(const char *path) |
|
{ |
|
Efreet_Desktop *desktop; |
|
Eina_List *commands; |
|
Eina_List *l; |
|
Entrance_Xsession *xsession; |
|
char *command = NULL; |
|
|
|
desktop = efreet_desktop_get(path); |
|
if (!desktop) return; |
|
EINA_LIST_FOREACH(_xsessions, l, xsession) |
|
{ |
|
if (!strcmp(xsession->name, desktop->name)) |
|
{ |
|
efreet_desktop_free(desktop); |
|
return; |
|
} |
|
} |
|
|
|
commands = efreet_desktop_command_local_get(desktop, NULL); |
|
if (commands) |
|
command = eina_list_data_get(commands); |
|
if (command && desktop->name) |
|
{ |
|
xsession= calloc(1, sizeof(Entrance_Xsession)); |
|
xsession->command = eina_stringshare_add(command); |
|
xsession->name = eina_stringshare_add(desktop->name); |
|
if (desktop->icon) xsession->icon = eina_stringshare_add(desktop->icon); |
|
_xsessions = eina_list_append(_xsessions, xsession); |
|
} |
|
EINA_LIST_FREE(commands, command) |
|
free(command); |
|
efreet_desktop_free(desktop); |
|
} |
|
|
|
|