#include "e.h" #ifdef HAVE_PAM # include # include #endif #define E_DESKLOCK_STATE_DEFAULT 0 #define E_DESKLOCK_STATE_CHECKING 1 #define E_DESKLOCK_STATE_INVALID 2 #define PASSWD_LEN 256 /**************************** private data ******************************/ typedef struct _E_Desklock_Data E_Desklock_Data; typedef struct _E_Desklock_Popup_Data E_Desklock_Popup_Data; #ifdef HAVE_PAM typedef struct _E_Desklock_Auth E_Desklock_Auth; #endif typedef struct _E_Desklock_Run E_Desklock_Run; struct _E_Desklock_Popup_Data { E_Zone *zone; Evas_Object *bg_object; Evas_Object *login_box; }; struct _E_Desklock_Data { Eina_List *elock_wnd_list; Ecore_X_Window elock_wnd; Eina_List *handlers; Ecore_Event_Handler *move_handler; Ecore_X_Window elock_grab_break_wnd; char passwd[PASSWD_LEN]; int state; Eina_Bool selected : 1; }; struct _E_Desklock_Run { E_Order *desk_run; int position; }; #ifdef HAVE_PAM struct _E_Desklock_Auth { struct { struct pam_conv conv; pam_handle_t *handle; } pam; char user[4096]; char passwd[4096]; }; #endif static E_Desklock_Data *edd = NULL; static E_Zone *last_active_zone = NULL; #ifdef HAVE_PAM static Ecore_Event_Handler *_e_desklock_exit_handler = NULL; static pid_t _e_desklock_child_pid = -1; #endif static Ecore_Exe *_e_custom_desklock_exe = NULL; static Ecore_Event_Handler *_e_custom_desklock_exe_handler = NULL; static Ecore_Poller *_e_desklock_idle_poller = NULL; static int _e_desklock_user_idle = 0; static double _e_desklock_autolock_time = 0.0; static E_Dialog *_e_desklock_ask_presentation_dia = NULL; static int _e_desklock_ask_presentation_count = 0; static Ecore_Event_Handler *_e_desklock_run_handler = NULL; static Ecore_Job *job = NULL; static Eina_List *tasks = NULL; /***********************************************************************/ static Eina_Bool _e_desklock_cb_key_down(void *data, int type, void *event); static Eina_Bool _e_desklock_cb_mouse_move(void *data, int type, void *event); static Eina_Bool _e_desklock_cb_custom_desklock_exit(void *data, int type, void *event); static Eina_Bool _e_desklock_cb_idle_poller(void *data); static Eina_Bool _e_desklock_cb_zone_add(void *data, int type, void *event); static Eina_Bool _e_desklock_cb_zone_del(void *data, int type, void *event); static Eina_Bool _e_desklock_cb_zone_move_resize(void *data, int type, void *event); static Eina_Bool _e_desklock_cb_run(void *data, int type, void *event); static void _e_desklock_popup_free(E_Desklock_Popup_Data *edp); static void _e_desklock_popup_add(E_Zone *zone); static void _e_desklock_login_box_add(E_Desklock_Popup_Data *edp); static void _e_desklock_select(void); static void _e_desklock_unselect(void); static void _e_desklock_null(void); static void _e_desklock_passwd_update(void); static void _e_desklock_backspace(void); static void _e_desklock_delete(void); static int _e_desklock_zone_num_get(void); static int _e_desklock_check_auth(void); static void _e_desklock_state_set(int state); static Eina_Bool _e_desklock_state = EINA_FALSE; #ifdef HAVE_PAM static Eina_Bool _e_desklock_cb_exit(void *data, int type, void *event); static int _desklock_auth(char *passwd); static int _desklock_pam_init(E_Desklock_Auth *da); static int _desklock_auth_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); static char *_desklock_auth_get_current_user(void); static char *_desklock_auth_get_current_host(void); #endif static void _e_desklock_ask_presentation_mode(void); EAPI int E_EVENT_DESKLOCK = 0; EINTERN int e_desklock_init(void) { Eina_List *l; E_Config_Desklock_Background *bg; /* A poller to tick every 256 ticks, watching for an idle user */ _e_desklock_idle_poller = ecore_poller_add(ECORE_POLLER_CORE, 256, _e_desklock_cb_idle_poller, NULL); if (e_config->desklock_background) e_filereg_register(e_config->desklock_background); EINA_LIST_FOREACH(e_config->desklock_backgrounds, l, bg) e_filereg_register(bg->file); E_EVENT_DESKLOCK = ecore_event_type_new(); _e_desklock_run_handler = ecore_event_handler_add(E_EVENT_DESKLOCK, _e_desklock_cb_run, NULL); return 1; } EINTERN int e_desklock_shutdown(void) { Eina_Bool waslocked = EINA_FALSE; E_Desklock_Run *task; Eina_List *l; E_Config_Desklock_Background *bg; if (edd) waslocked = EINA_TRUE; if (!x_fatal) e_desklock_hide(); if (e_config->desklock_background) e_filereg_deregister(e_config->desklock_background); if (waslocked) e_util_env_set("E_DESKLOCK_LOCKED", "locked"); ecore_event_handler_del(_e_desklock_run_handler); _e_desklock_run_handler = NULL; if (job) ecore_job_del(job); job = NULL; if (e_config->desklock_background) e_filereg_deregister(e_config->desklock_background); EINA_LIST_FOREACH(e_config->desklock_backgrounds, l, bg) e_filereg_deregister(bg->file); EINA_LIST_FREE(tasks, task) { e_object_del(E_OBJECT(task->desk_run)); free(task); } return 1; } static const char * _user_wallpaper_get(E_Zone *zone) { const E_Config_Desktop_Background *cdbg; const Eina_List *l; E_Desk *desk; desk = e_desk_current_get(zone); EINA_LIST_FOREACH(e_config->desktop_backgrounds, l, cdbg) { if ((cdbg->container > -1) && (cdbg->container != (int)zone->container->num)) continue; if ((cdbg->zone > -1) && (cdbg->zone != (int)zone->num)) continue; if ((cdbg->desk_x > -1) && (cdbg->desk_x != desk->x)) continue; if ((cdbg->desk_y > -1) && (cdbg->desk_y != desk->y)) continue; if (cdbg->file) return cdbg->file; } if (e_config->desktop_default_background) return e_config->desktop_default_background; return e_theme_edje_file_get("base/theme/desklock", "e/desklock/background"); } EAPI int e_desklock_show_autolocked(void) { if (_e_desklock_autolock_time < 1.0) _e_desklock_autolock_time = ecore_loop_time_get(); return e_desklock_show(EINA_FALSE); } EAPI int e_desklock_show(Eina_Bool suspend) { Eina_List *managers, *l, *l2, *l3; E_Manager *man; int total_zone_num; E_Event_Desklock *ev; if (_e_custom_desklock_exe) return 0; if (e_config->desklock_use_custom_desklock && e_config->desklock_custom_desklock_cmd && e_config->desklock_custom_desklock_cmd[0]) { e_menu_hide_all(); _e_custom_desklock_exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _e_desklock_cb_custom_desklock_exit, NULL); if (e_config->desklock_language) e_intl_language_set(e_config->desklock_language); if (e_config->xkb.lock_layout) e_xkb_layout_set(e_config->xkb.lock_layout); _e_custom_desklock_exe = ecore_exe_run(e_config->desklock_custom_desklock_cmd, NULL); _e_desklock_state = EINA_TRUE; /* TODO: ensure layer is correct on external desklocks? */ return 1; } #ifndef HAVE_PAM e_util_dialog_show(_("Error - no PAM support"), _("No PAM support was built into Enlightenment, so
" "desk locking is disabled.")); return 0; #endif if (edd) return 0; #ifdef HAVE_PAM if (e_config->desklock_auth_method == 1) { #endif if (!e_config->desklock_personal_passwd) { E_Zone *zone; zone = e_util_zone_current_get(e_manager_current_get()); if (zone) e_configure_registry_call("screen/screen_lock", zone->container, NULL); return 0; } #ifdef HAVE_PAM } #endif edd = E_NEW(E_Desklock_Data, 1); if (!edd) return 0; edd->elock_wnd = ecore_x_window_input_new(e_manager_current_get()->root, 0, 0, 1, 1); ecore_x_window_show(edd->elock_wnd); managers = e_manager_list(); e_menu_hide_all(); if (!e_grabinput_get(edd->elock_wnd, 0, edd->elock_wnd)) { EINA_LIST_FOREACH(managers, l, man) { Ecore_X_Window *windows; int wnum; windows = ecore_x_window_children_get(man->root, &wnum); if (windows) { int i; for (i = 0; i < wnum; i++) { Ecore_X_Window_Attributes att; memset(&att, 0, sizeof(Ecore_X_Window_Attributes)); ecore_x_window_attributes_get(windows[i], &att); if (att.visible) { ecore_x_window_hide(windows[i]); if (e_grabinput_get(edd->elock_wnd, 0, edd->elock_wnd)) { edd->elock_grab_break_wnd = windows[i]; free(windows); goto works; } ecore_x_window_show(windows[i]); } } free(windows); } } /* everything failed - can't lock */ e_util_dialog_show(_("Lock Failed"), _("Locking the desktop failed because some application
" "has grabbed either the keyboard or the mouse or both
" "and their grab is unable to be broken.")); ecore_x_window_free(edd->elock_wnd); E_FREE(edd); return 0; } works: //e_comp_block_window_add(); E_LIST_FOREACH(e_comp_list(), e_comp_override_add); e_comp_ignore_win_add(edd->elock_wnd); if (e_config->desklock_language) e_intl_language_set(e_config->desklock_language); if (e_config->xkb.lock_layout) e_xkb_layout_set(e_config->xkb.lock_layout); total_zone_num = _e_desklock_zone_num_get(); EINA_LIST_FOREACH(managers, l, man) { E_Container *con; EINA_LIST_FOREACH(man->containers, l2, con) { E_Zone *zone; EINA_LIST_FOREACH(con->zones, l3, zone) _e_desklock_popup_add(zone); } } /* handlers */ E_LIST_HANDLER_APPEND(edd->handlers, ECORE_EVENT_KEY_DOWN, _e_desklock_cb_key_down, NULL); E_LIST_HANDLER_APPEND(edd->handlers, E_EVENT_ZONE_ADD, _e_desklock_cb_zone_add, NULL); E_LIST_HANDLER_APPEND(edd->handlers, E_EVENT_ZONE_DEL, _e_desklock_cb_zone_del, NULL); E_LIST_HANDLER_APPEND(edd->handlers, E_EVENT_ZONE_MOVE_RESIZE, _e_desklock_cb_zone_move_resize, NULL); if ((total_zone_num > 1) && (e_config->desklock_login_box_zone == -2)) edd->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _e_desklock_cb_mouse_move, NULL); _e_desklock_passwd_update(); ev = E_NEW(E_Event_Desklock, 1); ev->on = 1; ev->suspend = suspend; ecore_event_add(E_EVENT_DESKLOCK, ev, NULL, NULL); e_util_env_set("E_DESKLOCK_LOCKED", "locked"); _e_desklock_state = EINA_TRUE; return 1; } EAPI void e_desklock_hide(void) { E_Event_Desklock *ev; if ((!edd) && (!_e_custom_desklock_exe)) return; E_LIST_FOREACH(e_comp_list(), e_comp_override_del); //e_comp_block_window_del(); if (e_config->desklock_language) e_intl_language_set(e_config->language); if (e_config_xkb_layout_eq(e_config->xkb.current_layout, e_config->xkb.lock_layout)) { if (e_config->xkb.sel_layout) e_xkb_layout_set(e_config->xkb.sel_layout); } _e_desklock_state = EINA_FALSE; ev = E_NEW(E_Event_Desklock, 1); ev->on = 0; ev->suspend = 1; ecore_event_add(E_EVENT_DESKLOCK, ev, NULL, NULL); if (e_config->desklock_use_custom_desklock) { _e_custom_desklock_exe = NULL; return; } if (!edd) return; if (edd->elock_grab_break_wnd) ecore_x_window_show(edd->elock_grab_break_wnd); E_FREE_LIST(edd->elock_wnd_list, _e_desklock_popup_free); E_FREE_LIST(edd->handlers, ecore_event_handler_del); if (edd->move_handler) ecore_event_handler_del(edd->move_handler); e_grabinput_release(edd->elock_wnd, edd->elock_wnd); ecore_x_window_free(edd->elock_wnd); E_FREE(edd); if (_e_desklock_autolock_time > 0.0) { if ((e_config->desklock_ask_presentation) && (e_config->desklock_ask_presentation_timeout > 0.0)) { double max, now; now = ecore_loop_time_get(); max = _e_desklock_autolock_time + e_config->desklock_ask_presentation_timeout; if (now <= max) _e_desklock_ask_presentation_mode(); } else _e_desklock_ask_presentation_count = 0; _e_desklock_autolock_time = 0.0; } e_util_env_set("E_DESKLOCK_LOCKED", "freefreefree"); } static void _e_desklock_popup_add(E_Zone *zone) { E_Desklock_Popup_Data *edp; E_Config_Desklock_Background *cbg; const char *bg; Evas *evas; cbg = eina_list_nth(e_config->desklock_backgrounds, zone->num); bg = cbg ? cbg->file : NULL; edp = E_NEW(E_Desklock_Popup_Data, 1); edp->zone = zone; evas = e_comp_get(zone)->evas; evas_event_freeze(evas); edp->bg_object = edje_object_add(evas); evas_object_name_set(edp->bg_object, "desklock->bg_object"); if ((!bg) || (!strcmp(bg, "theme_desklock_background"))) { e_theme_edje_object_set(edp->bg_object, "base/theme/desklock", "e/desklock/background"); } else if (!strcmp(bg, "theme_background")) { e_theme_edje_object_set(edp->bg_object, "base/theme/backgrounds", "e/desktop/background"); } else { const char *f; if (!strcmp(bg, "user_background")) f = _user_wallpaper_get(zone); else f = bg; if (e_util_edje_collection_exists(f, "e/desklock/background")) { edje_object_file_set(edp->bg_object, f, "e/desklock/background"); } else { if (!edje_object_file_set(edp->bg_object, f, "e/desktop/background")) { edje_object_file_set(edp->bg_object, e_theme_edje_file_get("base/theme/desklock", "e/desklock/background"), "e/desklock/background"); } } } evas_object_move(edp->bg_object, zone->x, zone->y); evas_object_resize(edp->bg_object, zone->w, zone->h); evas_object_show(edp->bg_object); E_LAYER_SET_ABOVE(edp->bg_object, E_COMP_CANVAS_LAYER_DESKLOCK); evas_object_clip_set(edp->bg_object, edp->zone->bg_clip_object); _e_desklock_login_box_add(edp); evas_event_thaw(evas); edd->elock_wnd_list = eina_list_append(edd->elock_wnd_list, edp); } static void _e_desklock_login_box_add(E_Desklock_Popup_Data *edp) { int mw, mh; E_Zone *zone, *current_zone; int total_zone_num; Evas *evas; zone = edp->zone; last_active_zone = current_zone = e_util_zone_current_get(e_manager_current_get()); total_zone_num = _e_desklock_zone_num_get(); if (total_zone_num > 1) { if ((e_config->desklock_login_box_zone == -2) && (zone != current_zone)) return; if ((e_config->desklock_login_box_zone > -1) && (e_config->desklock_login_box_zone != (int)eina_list_count(edd->elock_wnd_list))) return; } evas = evas_object_evas_get(edp->bg_object); edp->login_box = edje_object_add(evas); evas_object_name_set(edp->login_box, "desklock->login_box"); e_theme_edje_object_set(edp->login_box, "base/theme/desklock", "e/desklock/login_box"); edje_object_part_text_set(edp->login_box, "e.text.title", _("Please enter your unlock password")); edje_object_size_min_calc(edp->login_box, &mw, &mh); if (edje_object_part_exists(edp->bg_object, "e.swallow.login_box")) { edje_extern_object_min_size_set(edp->login_box, mw, mh); edje_object_part_swallow(edp->bg_object, "e.swallow.login_box", edp->login_box); } else { evas_object_resize(edp->login_box, mw, mh); evas_object_move(edp->login_box, zone->x + ((zone->w - mw) / 2), zone->y + ((zone->h - mh) / 2)); evas_object_show(edp->login_box); E_LAYER_SET_ABOVE(edp->login_box, E_COMP_CANVAS_LAYER_DESKLOCK); } evas_object_clip_set(edp->login_box, edp->zone->bg_clip_object); } static void _e_desklock_popup_free(E_Desklock_Popup_Data *edp) { if (!edp) return; evas_object_del(edp->bg_object); evas_object_del(edp->login_box); free(edp); } EAPI Eina_Bool e_desklock_state_get(void) { return _e_desklock_state; } static Eina_List * _e_desklock_popup_find(E_Zone *zone) { Eina_List *l; E_Desklock_Popup_Data *edp; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) if (edp->zone == zone) return l; return NULL; } static Eina_Bool _e_desklock_cb_zone_add(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Event_Zone_Add *ev = event; if (!edd) return ECORE_CALLBACK_PASS_ON; if ((!edd->move_handler) && (e_config->desklock_login_box_zone == -2)) edd->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _e_desklock_cb_mouse_move, NULL); if (!_e_desklock_popup_find(ev->zone)) _e_desklock_popup_add(ev->zone); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_desklock_cb_zone_del(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Event_Zone_Del *ev = event; Eina_List *l; if (!edd) return ECORE_CALLBACK_PASS_ON; if ((eina_list_count(e_container_current_get(e_manager_current_get())->zones) == 1) && (e_config->desklock_login_box_zone == -2)) edd->move_handler = ecore_event_handler_del(edd->move_handler); l = _e_desklock_popup_find(ev->zone); if (l) { _e_desklock_popup_free(l->data); edd->elock_wnd_list = eina_list_remove_list(edd->elock_wnd_list, l); } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_desklock_cb_zone_move_resize(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Desklock_Popup_Data *edp; Eina_List *l; E_Event_Zone_Move_Resize *ev = event; if (!edd) return ECORE_CALLBACK_PASS_ON; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) if (edp->zone == ev->zone) { int w, h; evas_object_resize(edp->bg_object, ev->zone->w, ev->zone->h); evas_object_geometry_get(edp->login_box, NULL, NULL, &w, &h); evas_object_move(edp->login_box, edp->zone->x + ((edp->zone->w - w) / 2), edp->zone->y + ((edp->zone->h - h) / 2)); break; } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_desklock_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Event_Key *ev = event; if ((ev->window != edd->elock_wnd) || (edd->state == E_DESKLOCK_STATE_CHECKING)) return 1; if (!strcmp(ev->key, "Escape")) { if (edd->selected) { _e_desklock_unselect(); return ECORE_CALLBACK_RENEW; } } else if (!strcmp(ev->key, "KP_Enter")) _e_desklock_check_auth(); else if (!strcmp(ev->key, "Return")) _e_desklock_check_auth(); else if (!strcmp(ev->key, "BackSpace")) { if (edd->selected) { _e_desklock_null(); _e_desklock_unselect(); return ECORE_CALLBACK_RENEW; } _e_desklock_backspace(); } else if (!strcmp(ev->key, "Delete")) { if (edd->selected) { _e_desklock_null(); _e_desklock_unselect(); return ECORE_CALLBACK_RENEW; } _e_desklock_delete(); } else if ((!strcmp(ev->key, "u") && (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL))) _e_desklock_null(); else if ((!strcmp(ev->key, "a") && (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL))) _e_desklock_select(); else { /* here we have to grab a password */ if (ev->compose) { if (edd->selected) { _e_desklock_null(); _e_desklock_unselect(); } if ((strlen(edd->passwd) < (PASSWD_LEN - strlen(ev->compose)))) { strcat(edd->passwd, ev->compose); _e_desklock_passwd_update(); } } } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_desklock_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) { E_Desklock_Popup_Data *edp; E_Zone *current_zone; Eina_List *l; current_zone = e_util_zone_current_get(e_manager_current_get()); if (current_zone == last_active_zone) return ECORE_CALLBACK_PASS_ON; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) { if (!edp) continue; if (edp->zone != current_zone) { if (edp->login_box) evas_object_hide(edp->login_box); continue; } if (edp->login_box) evas_object_show(edp->login_box); else _e_desklock_login_box_add(edp); } _e_desklock_passwd_update(); last_active_zone = current_zone; return ECORE_CALLBACK_PASS_ON; } static void _e_desklock_passwd_update(void) { int len, i; char passwd_hidden[PASSWD_LEN] = "", *pp; E_Desklock_Popup_Data *edp; Eina_List *l; if (!edd) return; len = eina_unicode_utf8_get_len(edd->passwd); for (i = 0, pp = passwd_hidden; i < len; i++, pp++) *pp = '*'; *pp = 0; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) if (edp->login_box) edje_object_part_text_set(edp->login_box, "e.text.password", passwd_hidden); } static void _e_desklock_select(void) { E_Desklock_Popup_Data *edp; Eina_List *l; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) if (edp->login_box) edje_object_signal_emit(edp->login_box, "e,state,selected", "e"); edd->selected = EINA_TRUE; } static void _e_desklock_unselect(void) { E_Desklock_Popup_Data *edp; Eina_List *l; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) if (edp->login_box) edje_object_signal_emit(edp->login_box, "e,state,unselected", "e"); edd->selected = EINA_FALSE; } static void _e_desklock_null(void) { memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN); _e_desklock_passwd_update(); } static void _e_desklock_backspace(void) { int len, val, pos; if (!edd) return; len = strlen(edd->passwd); if (len > 0) { pos = evas_string_char_prev_get(edd->passwd, len, &val); if ((pos < len) && (pos >= 0)) { edd->passwd[pos] = 0; _e_desklock_passwd_update(); } } } static void _e_desklock_delete(void) { _e_desklock_backspace(); } static int _e_desklock_zone_num_get(void) { int num; Eina_List *l, *l2; E_Manager *man; num = 0; EINA_LIST_FOREACH(e_manager_list(), l, man) { E_Container *con; EINA_LIST_FOREACH(man->containers, l2, con) num += eina_list_count(con->zones); } return num; } static int _e_desklock_check_auth(void) { if (!edd) return 0; #ifdef HAVE_PAM if (e_config->desklock_auth_method == 0) { int ret; ret = _desklock_auth(edd->passwd); // passwd off in child proc now - null out from parent memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN); return ret; } else if (e_config->desklock_auth_method == 1) { #endif if ((e_config->desklock_personal_passwd) && (!strcmp(!edd->passwd ? "" : edd->passwd, !e_config->desklock_personal_passwd ? "" : e_config->desklock_personal_passwd))) { /* password ok */ /* security - null out passwd string once we are done with it */ memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN); e_desklock_hide(); return 1; } #ifdef HAVE_PAM } #endif /* password is definitely wrong */ _e_desklock_state_set(E_DESKLOCK_STATE_INVALID); _e_desklock_null(); return 0; } static void _e_desklock_state_set(int state) { Eina_List *l; E_Desklock_Popup_Data *edp; const char *signal_desklock, *text; if (!edd) return; edd->state = state; if (state == E_DESKLOCK_STATE_CHECKING) { signal_desklock = "e,state,checking"; text = _("Authenticating..."); } else if (state == E_DESKLOCK_STATE_INVALID) { signal_desklock = "e,state,invalid"; text = _("The password you entered is invalid. Try again."); } else return; EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp) { edje_object_signal_emit(edp->login_box, signal_desklock, "e.desklock"); // compat edje_object_signal_emit(edp->bg_object, signal_desklock, "e.desklock"); // compat edje_object_signal_emit(edp->login_box, signal_desklock, "e"); edje_object_signal_emit(edp->bg_object, signal_desklock, "e"); edje_object_part_text_set(edp->login_box, "e.text.title", text); } } #ifdef HAVE_PAM static Eina_Bool _e_desklock_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Exe_Event_Del *ev = event; if (ev->pid == _e_desklock_child_pid) { _e_desklock_child_pid = -1; /* ok */ if (ev->exit_code == 0) { /* security - null out passwd string once we are done with it */ memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN); e_desklock_hide(); } /* error */ else if (ev->exit_code < 128) { /* security - null out passwd string once we are done with it */ memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN); e_desklock_hide(); e_util_dialog_show(_("Authentication System Error"), _("Authentication via PAM had errors setting up the
" "authentication session. The error code was %i.
" "This is bad and should not be happening. Please report this bug.") , ev->exit_code); } /* failed auth */ else { _e_desklock_state_set(E_DESKLOCK_STATE_INVALID); /* security - null out passwd string once we are done with it */ _e_desklock_null(); } if (_e_desklock_exit_handler) ecore_event_handler_del(_e_desklock_exit_handler); _e_desklock_exit_handler = NULL; } return ECORE_CALLBACK_PASS_ON; } static int _desklock_auth(char *passwd) { _e_desklock_state_set(E_DESKLOCK_STATE_CHECKING); _e_desklock_child_pid = fork(); if (_e_desklock_child_pid > 0) { /* parent */ _e_desklock_exit_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _e_desklock_cb_exit, NULL); } else if (_e_desklock_child_pid == 0) { /* child */ int pamerr; E_Desklock_Auth da; char *current_user, *p; struct sigaction action; action.sa_handler = SIG_DFL; action.sa_flags = SA_ONSTACK | SA_NODEFER | SA_RESETHAND | SA_SIGINFO; sigemptyset(&action.sa_mask); sigaction(SIGSEGV, &action, NULL); sigaction(SIGILL, &action, NULL); sigaction(SIGFPE, &action, NULL); sigaction(SIGBUS, &action, NULL); sigaction(SIGABRT, &action, NULL); current_user = _desklock_auth_get_current_user(); eina_strlcpy(da.user, current_user, sizeof(da.user)); eina_strlcpy(da.passwd, passwd, sizeof(da.passwd)); /* security - null out passwd string once we are done with it */ for (p = passwd; *p; p++) *p = 0; da.pam.handle = NULL; da.pam.conv.conv = NULL; da.pam.conv.appdata_ptr = NULL; pamerr = _desklock_pam_init(&da); if (pamerr != PAM_SUCCESS) { free(current_user); exit(1); } pamerr = pam_authenticate(da.pam.handle, 0); pam_end(da.pam.handle, pamerr); /* security - null out passwd string once we are done with it */ memset(da.passwd, 0, sizeof(da.passwd)); if (pamerr == PAM_SUCCESS) { free(current_user); exit(0); } free(current_user); exit(-1); } else { _e_desklock_state_set(E_DESKLOCK_STATE_INVALID); return 0; } return 1; } static char * _desklock_auth_get_current_user(void) { char *user; struct passwd *pwent = NULL; pwent = getpwuid(getuid()); user = strdup(pwent->pw_name); return user; } static int _desklock_pam_init(E_Desklock_Auth *da) { int pamerr; const char *pam_prof; char *current_host; char *current_user; if (!da) return -1; da->pam.conv.conv = _desklock_auth_pam_conv; da->pam.conv.appdata_ptr = da; da->pam.handle = NULL; /* try other pam profiles - and system-auth (login for fbsd users) is a fallback */ pam_prof = "login"; if (ecore_file_exists("/etc/pam.d/enlightenment")) pam_prof = "enlightenment"; else if (ecore_file_exists("/etc/pam.d/xscreensaver")) pam_prof = "xscreensaver"; else if (ecore_file_exists("/etc/pam.d/kscreensaver")) pam_prof = "kscreensaver"; else if (ecore_file_exists("/etc/pam.d/system-auth")) pam_prof = "system-auth"; else if (ecore_file_exists("/etc/pam.d/system")) pam_prof = "system"; else if (ecore_file_exists("/etc/pam.d/xdm")) pam_prof = "xdm"; else if (ecore_file_exists("/etc/pam.d/gdm")) pam_prof = "gdm"; else if (ecore_file_exists("/etc/pam.d/kdm")) pam_prof = "kdm"; if ((pamerr = pam_start(pam_prof, da->user, &(da->pam.conv), &(da->pam.handle))) != PAM_SUCCESS) return pamerr; current_user = _desklock_auth_get_current_user(); if ((pamerr = pam_set_item(da->pam.handle, PAM_USER, current_user)) != PAM_SUCCESS) { free(current_user); return pamerr; } current_host = _desklock_auth_get_current_host(); if ((pamerr = pam_set_item(da->pam.handle, PAM_RHOST, current_host)) != PAM_SUCCESS) { free(current_user); free(current_host); return pamerr; } free(current_user); free(current_host); return 0; } static int _desklock_auth_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { int replies = 0; E_Desklock_Auth *da = (E_Desklock_Auth *)appdata_ptr; struct pam_response *reply = NULL; reply = (struct pam_response *)malloc(sizeof(struct pam_response) * num_msg); if (!reply) return PAM_CONV_ERR; for (replies = 0; replies < num_msg; replies++) { switch (msg[replies]->msg_style) { case PAM_PROMPT_ECHO_ON: reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = strdup(da->user); break; case PAM_PROMPT_ECHO_OFF: reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = strdup(da->passwd); break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = NULL; break; default: free(reply); return PAM_CONV_ERR; } } *resp = reply; return PAM_SUCCESS; } static char * _desklock_auth_get_current_host(void) { return strdup("localhost"); } #endif static Eina_Bool _e_desklock_cb_custom_desklock_exit(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Exe_Event_Del *ev = event; if (ev->exe != _e_custom_desklock_exe) return ECORE_CALLBACK_PASS_ON; if (ev->exit_code != 0) { /* do something profound here... like notify someone */ } e_desklock_hide(); return ECORE_CALLBACK_DONE; } static Eina_Bool _e_desklock_cb_idle_poller(void *data __UNUSED__) { if ((e_config->desklock_autolock_idle) && (!e_config->mode.presentation)) { double idle, max; /* If a desklock is already up, bail */ if ((_e_custom_desklock_exe) || (edd)) return ECORE_CALLBACK_RENEW; idle = ecore_x_screensaver_idle_time_get(); max = e_config->desklock_autolock_idle_timeout; if (_e_desklock_ask_presentation_count > 0) max *= (1 + _e_desklock_ask_presentation_count); /* If we have exceeded our idle time... */ if (idle >= max) { /* * Unfortunately, not all "desklocks" stay up for as long as * the user is idle or until it is unlocked. * * 'xscreensaver-command -lock' for example sends a command * to xscreensaver and then terminates. So, we have another * check (_e_desklock_user_idle) which lets us know that we * have locked the screen due to idleness. */ if (!_e_desklock_user_idle) { _e_desklock_user_idle = 1; e_desklock_show_autolocked(); } } else _e_desklock_user_idle = 0; } /* Make sure our poller persists. */ return ECORE_CALLBACK_RENEW; } static void _e_desklock_ask_presentation_del(void *data) { if (_e_desklock_ask_presentation_dia == data) _e_desklock_ask_presentation_dia = NULL; } static void _e_desklock_ask_presentation_yes(void *data __UNUSED__, E_Dialog *dia) { e_config->mode.presentation = 1; e_config_mode_changed(); e_config_save_queue(); e_object_del(E_OBJECT(dia)); _e_desklock_ask_presentation_count = 0; } static void _e_desklock_ask_presentation_no(void *data __UNUSED__, E_Dialog *dia) { e_object_del(E_OBJECT(dia)); _e_desklock_ask_presentation_count = 0; } static void _e_desklock_ask_presentation_no_increase(void *data __UNUSED__, E_Dialog *dia) { int timeout, interval, blanking, expose; _e_desklock_ask_presentation_count++; timeout = e_config->screensaver_timeout * _e_desklock_ask_presentation_count; interval = e_config->screensaver_interval; blanking = e_config->screensaver_blanking; expose = e_config->screensaver_expose; ecore_x_screensaver_set(timeout, interval, blanking, expose); e_object_del(E_OBJECT(dia)); } static void _e_desklock_ask_presentation_no_forever(void *data __UNUSED__, E_Dialog *dia) { e_config->desklock_ask_presentation = 0; e_config_save_queue(); e_object_del(E_OBJECT(dia)); _e_desklock_ask_presentation_count = 0; } static void _e_desklock_ask_presentation_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event) { Evas_Event_Key_Down *ev = event; E_Dialog *dia = data; if (strcmp(ev->keyname, "Return") == 0) _e_desklock_ask_presentation_yes(NULL, dia); else if (strcmp(ev->keyname, "Escape") == 0) _e_desklock_ask_presentation_no(NULL, dia); } static void _e_desklock_ask_presentation_mode(void) { E_Manager *man; E_Container *con; E_Dialog *dia; if (_e_desklock_ask_presentation_dia) return; if (!(man = e_manager_current_get())) return; if (!(con = e_container_current_get(man))) return; if (!(dia = e_dialog_new(con, "E", "_desklock_ask_presentation"))) return; e_dialog_title_set(dia, _("Activate Presentation Mode?")); e_dialog_icon_set(dia, "dialog-ask", 64); e_dialog_text_set(dia, _("You unlocked your desktop too fast.

" "Would you like to enable presentation mode and " "temporarily disable screen saver, lock and power saving?")); e_object_del_attach_func_set(E_OBJECT(dia), _e_desklock_ask_presentation_del); e_dialog_button_add(dia, _("Yes"), NULL, _e_desklock_ask_presentation_yes, NULL); e_dialog_button_add(dia, _("No"), NULL, _e_desklock_ask_presentation_no, NULL); e_dialog_button_add(dia, _("No, but increase timeout"), NULL, _e_desklock_ask_presentation_no_increase, NULL); e_dialog_button_add(dia, _("No, and stop asking"), NULL, _e_desklock_ask_presentation_no_forever, NULL); e_dialog_button_focus_num(dia, 0); e_widget_list_homogeneous_set(dia->box_object, 0); e_win_centered_set(dia->win, 1); e_dialog_show(dia); evas_object_event_callback_add(dia->bg_object, EVAS_CALLBACK_KEY_DOWN, _e_desklock_ask_presentation_key_down, dia); _e_desklock_ask_presentation_dia = dia; } static Eina_Bool _e_desklock_run(E_Desklock_Run *task) { Efreet_Desktop *desktop; desktop = eina_list_nth(task->desk_run->desktops, task->position++); if (!desktop) { e_object_del(E_OBJECT(task->desk_run)); free(task); return EINA_FALSE; } e_exec(NULL, desktop, NULL, NULL, NULL); return EINA_TRUE; } static void _e_desklock_job(void *data __UNUSED__) { E_Desklock_Run *task; job = NULL; if (!tasks) return; task = eina_list_data_get(tasks); if (!_e_desklock_run(task)) tasks = eina_list_remove_list(tasks, tasks); if (tasks) job = ecore_job_add(_e_desklock_job, NULL); } static Eina_Bool _e_desklock_cb_run(void *data __UNUSED__, int type __UNUSED__, void *event) { E_Desklock_Run *task; E_Event_Desklock *ev = event; E_Order *desk_run; char buf[PATH_MAX]; if (!ev->suspend) return ECORE_CALLBACK_PASS_ON; if (ev->on) { e_user_dir_concat_static(buf, "applications/desk-lock/.order"); if (!ecore_file_exists(buf)) e_prefix_data_concat_static(buf, "applications/desk-lock/.order"); } else { e_user_dir_concat_static(buf, "applications/desk-unlock/.order"); if (!ecore_file_exists(buf)) e_prefix_data_concat_static(buf, "applications/desk-unlock/.order"); } desk_run = e_order_new(buf); if (!desk_run) return ECORE_CALLBACK_PASS_ON; task = calloc(1, sizeof (E_Desklock_Run)); if (!task) { e_object_del(E_OBJECT(desk_run)); return ECORE_CALLBACK_PASS_ON; } task->desk_run = desk_run; tasks = eina_list_append(tasks, task); if (!job) ecore_job_add(_e_desklock_job, NULL); return ECORE_CALLBACK_PASS_ON; }