update for beta release
[framework/uifw/e17.git] / src / bin / e_desklock.c
1 #include "e.h"
2 #ifdef HAVE_PAM
3 # include <security/pam_appl.h>
4 # include <pwd.h>
5 #endif
6
7 #define E_DESKLOCK_STATE_DEFAULT 0
8 #define E_DESKLOCK_STATE_CHECKING 1
9 #define E_DESKLOCK_STATE_INVALID 2
10
11 #define ELOCK_POPUP_LAYER 10000
12 #define PASSWD_LEN 256
13
14 /**************************** private data ******************************/
15 typedef struct _E_Desklock_Data       E_Desklock_Data;
16 typedef struct _E_Desklock_Popup_Data E_Desklock_Popup_Data;
17 #ifdef HAVE_PAM
18 typedef struct _E_Desklock_Auth       E_Desklock_Auth;
19 #endif
20
21 struct _E_Desklock_Popup_Data
22 {
23    E_Popup     *popup_wnd;
24    Evas_Object *bg_object;
25    Evas_Object *login_box;
26 };
27
28 struct _E_Desklock_Data
29 {
30    Eina_List      *elock_wnd_list;
31    Ecore_X_Window  elock_wnd;
32    Eina_List      *handlers;
33    Ecore_X_Window  elock_grab_break_wnd;
34    char            passwd[PASSWD_LEN];
35    int             state;
36 };
37
38 #ifdef HAVE_PAM
39 struct _E_Desklock_Auth
40 {
41    struct 
42      {
43         struct pam_conv conv;
44         pam_handle_t    *handle;
45      } pam;
46
47    char user[PATH_MAX];
48    char passwd[PATH_MAX];
49 };
50 #endif
51
52 static E_Desklock_Data *edd = NULL;
53 static E_Zone *last_active_zone = NULL;
54 #ifdef HAVE_PAM
55 static Ecore_Event_Handler *_e_desklock_exit_handler = NULL;
56 static pid_t _e_desklock_child_pid = -1;
57 #endif
58 static Ecore_Exe *_e_custom_desklock_exe = NULL;
59 static Ecore_Event_Handler *_e_custom_desklock_exe_handler = NULL;
60 static Ecore_Poller *_e_desklock_idle_poller = NULL;
61 static int _e_desklock_user_idle = 0;
62 static double _e_desklock_autolock_time = 0.0;
63 static E_Dialog *_e_desklock_ask_presentation_dia = NULL;
64 static int _e_desklock_ask_presentation_count = 0;
65
66 /***********************************************************************/
67
68 static Eina_Bool _e_desklock_cb_key_down(void *data, int type, void *event);
69 static Eina_Bool _e_desklock_cb_mouse_move(void *data, int type, void *event);
70 static Eina_Bool _e_desklock_cb_custom_desklock_exit(void *data, int type, void *event);
71 static Eina_Bool _e_desklock_cb_idle_poller(void *data);
72 static Eina_Bool _e_desklock_cb_window_stack(void *data, int type, void *event);
73
74 static void _e_desklock_null(void);
75 static void _e_desklock_passwd_update(void);
76 static void _e_desklock_backspace(void);
77 static void _e_desklock_delete(void);
78 static int _e_desklock_zone_num_get(void);
79 static int _e_desklock_check_auth(void);
80 static void _e_desklock_state_set(int state);
81
82 #ifdef HAVE_PAM
83 static Eina_Bool _e_desklock_cb_exit(void *data, int type, void *event);
84 static int _desklock_auth(char *passwd);
85 static int _desklock_pam_init(E_Desklock_Auth *da);
86 static int _desklock_auth_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr);
87 static char *_desklock_auth_get_current_user(void);
88 static char *_desklock_auth_get_current_host(void);
89 #endif
90
91 static void _e_desklock_ask_presentation_mode(void);
92
93 EAPI int E_EVENT_DESKLOCK = 0;
94
95 EINTERN int
96 e_desklock_init(void)
97 {
98    /* A poller to tick every 256 ticks, watching for an idle user */
99    _e_desklock_idle_poller = ecore_poller_add(ECORE_POLLER_CORE, 256,
100                                               _e_desklock_cb_idle_poller, NULL);
101
102    if (e_config->desklock_background)
103      e_filereg_register(e_config->desklock_background);
104
105    E_EVENT_DESKLOCK = ecore_event_type_new();
106
107    return 1;
108 }
109
110 EINTERN int
111 e_desklock_shutdown(void)
112 {
113    if (!x_fatal)
114       e_desklock_hide();
115    if (e_config->desklock_background)
116      e_filereg_deregister(e_config->desklock_background);
117
118    return 1;
119 }
120
121 static const char *
122 _user_wallpaper_get(void)
123 {
124    const E_Config_Desktop_Background *cdbg;
125    const Eina_List *l;
126
127    if (e_config->desktop_default_background)
128      return e_config->desktop_default_background;
129
130    EINA_LIST_FOREACH(e_config->desktop_backgrounds, l, cdbg)
131      if (cdbg->file) return cdbg->file;
132
133    return e_theme_edje_file_get("base/theme/desklock", "e/desklock/background");
134 }
135
136 EAPI int
137 e_desklock_show_autolocked(void)
138 {
139    if (e_util_fullscreen_curreny_any()) return 0;
140    if (_e_desklock_autolock_time < 1.0)
141      _e_desklock_autolock_time = ecore_loop_time_get();
142    return e_desklock_show();
143 }
144
145 EAPI int
146 e_desklock_show(void)
147 {
148    Eina_List *managers, *l, *l2, *l3;
149    E_Manager *man;
150    E_Desklock_Popup_Data *edp;
151    Evas_Coord mw, mh;
152    E_Zone *current_zone;
153    int zone_counter, total_zone_num;
154    E_Event_Desklock *ev;
155
156    if (_e_custom_desklock_exe) return 0;
157
158    if (e_config->desklock_use_custom_desklock)
159      {
160         _e_custom_desklock_exe_handler = 
161           ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
162                                   _e_desklock_cb_custom_desklock_exit, NULL);
163         e_util_library_path_strip();
164         _e_custom_desklock_exe = 
165           ecore_exe_run(e_config->desklock_custom_desklock_cmd, NULL);
166         e_util_library_path_restore();
167         return 1;
168      }
169
170 #ifndef HAVE_PAM
171    e_util_dialog_show(_("Error - no PAM support"),
172                       _("No PAM support was built into Enlightenment, so<br>"
173                         "desk locking is disabled."));
174    return 0;
175 #endif
176
177    if (edd) return 0;
178
179 #ifdef HAVE_PAM
180    if (e_config->desklock_auth_method == 1)
181      {
182 #endif
183        if (!e_config->desklock_personal_passwd)
184          {
185             E_Zone  *zone;
186
187             zone = e_util_zone_current_get(e_manager_current_get());
188             if (zone)
189               e_configure_registry_call("screen/screen_lock", zone->container, NULL);
190             return 0;
191          }
192 #ifdef HAVE_PAM
193      }
194 #endif
195
196    edd = E_NEW(E_Desklock_Data, 1);
197    if (!edd) return 0;
198    edd->elock_wnd = 
199      ecore_x_window_input_new(e_manager_current_get()->root, 0, 0, 1, 1);
200    ecore_x_window_show(edd->elock_wnd);
201    managers = e_manager_list();
202    if (!e_grabinput_get(edd->elock_wnd, 0, edd->elock_wnd))
203      {
204         EINA_LIST_FOREACH(managers, l, man)
205           {
206              Ecore_X_Window *windows;
207              int wnum;
208
209              windows = ecore_x_window_children_get(man->root, &wnum);
210              if (windows)
211                {
212                   int i;
213
214                   for (i = 0; i < wnum; i++)
215                     {
216                        Ecore_X_Window_Attributes att;
217
218                        memset(&att, 0, sizeof(Ecore_X_Window_Attributes));
219                        ecore_x_window_attributes_get(windows[i], &att);
220                        if (att.visible)
221                          {
222                             ecore_x_window_hide(windows[i]);
223                             if (e_grabinput_get(edd->elock_wnd, 0, edd->elock_wnd))
224                               {
225                                  edd->elock_grab_break_wnd = windows[i];
226                                  free(windows);
227                                  goto works;
228                               }
229                             ecore_x_window_show(windows[i]);
230                          }
231                     }
232                   free(windows);
233                }
234           }
235         /* everything failed - can't lock */
236         e_util_dialog_show(_("Lock Failed"),
237                            _("Locking the desktop failed because some application<br>"
238                              "has grabbed either the keyboard or the mouse or both<br>"
239                              "and their grab is unable to be broken."));
240         ecore_x_window_free(edd->elock_wnd);
241         E_FREE(edd);
242         return 0;
243      }
244    works:
245
246    last_active_zone = current_zone =
247      e_zone_current_get(e_container_current_get(e_manager_current_get()));
248
249    zone_counter = 0;
250    total_zone_num = _e_desklock_zone_num_get();
251    EINA_LIST_FOREACH(managers, l, man)
252      {
253         E_Container *con;
254
255         EINA_LIST_FOREACH(man->containers, l2, con)
256           {
257              E_Zone *zone;
258
259              EINA_LIST_FOREACH(con->zones, l3, zone)
260                {
261                   edp = E_NEW(E_Desklock_Popup_Data, 1);
262                   if (edp)
263                     {
264                        edp->popup_wnd = e_popup_new(zone, 0, 0, zone->w, zone->h);
265                        evas_event_feed_mouse_move(edp->popup_wnd->evas, -1000000, -1000000,
266                                                   ecore_x_current_time_get(), NULL);
267
268                        e_popup_layer_set(edp->popup_wnd, ELOCK_POPUP_LAYER);
269                        ecore_evas_raise(edp->popup_wnd->ecore_evas);
270
271                        evas_event_freeze(edp->popup_wnd->evas);
272                        edp->bg_object = edje_object_add(edp->popup_wnd->evas);
273
274                        if ((!e_config->desklock_background) ||
275                            (!strcmp(e_config->desklock_background, "theme_desklock_background")))
276                          {
277                             e_theme_edje_object_set(edp->bg_object,
278                                                     "base/theme/desklock",
279                                                     "e/desklock/background");
280                          }
281                        else if (!strcmp(e_config->desklock_background, "theme_background"))
282                          {
283                             e_theme_edje_object_set(edp->bg_object,
284                                                     "base/theme/backgrounds",
285                                                     "e/desktop/background");
286                          }
287                        else
288                          {
289                            const char *f;
290
291                            if (!strcmp(e_config->desklock_background, "user_background"))
292                              f = _user_wallpaper_get();
293                            else
294                              f = e_config->desklock_background;
295
296                            if (e_util_edje_collection_exists(f, "e/desklock/background"))
297                              {
298                                 edje_object_file_set(edp->bg_object, f,
299                                                      "e/desklock/background");
300                              }
301                            else
302                              {
303                                if (!edje_object_file_set(edp->bg_object,
304                                                          f, "e/desktop/background"))
305                                  {
306                                     edje_object_file_set(edp->bg_object,
307                                                          e_theme_edje_file_get("base/theme/desklock",
308                                                                                "e/desklock/background"),
309                                                          "e/desklock/background");
310                                  }
311                              }
312                          }
313
314                        evas_object_move(edp->bg_object, 0, 0);
315                        evas_object_resize(edp->bg_object, zone->w, zone->h);
316                        evas_object_show(edp->bg_object);
317                        edp->login_box = edje_object_add(edp->popup_wnd->evas);
318                        e_theme_edje_object_set(edp->login_box,
319                                                "base/theme/desklock",
320                                                "e/desklock/login_box");
321                        edje_object_part_text_set(edp->login_box, "e.text.title",
322                                                  _("Please enter your unlock password"));
323                        edje_object_size_min_calc(edp->login_box, &mw, &mh);
324                        if (edje_object_part_exists(edp->bg_object, "e.swallow.login_box"))
325                          {
326                             edje_extern_object_min_size_set(edp->login_box, mw, mh);
327                             edje_object_part_swallow(edp->bg_object, "e.swallow.login_box", edp->login_box);
328                          }
329                        else
330                          {
331                             evas_object_resize(edp->login_box, mw, mh);
332                             evas_object_move(edp->login_box,
333                                              ((zone->w - mw) / 2),
334                                              ((zone->h - mh) / 2));
335                          }
336                        if (total_zone_num > 1)
337                          {
338                             if (e_config->desklock_login_box_zone == -1)
339                               evas_object_show(edp->login_box);
340                             else if ((e_config->desklock_login_box_zone == -2) &&
341                                      (zone == current_zone))
342                               evas_object_show(edp->login_box);
343                             else if (e_config->desklock_login_box_zone == zone_counter)
344                               evas_object_show(edp->login_box);
345                          }
346                        else
347                          evas_object_show(edp->login_box);
348
349                        e_popup_edje_bg_object_set(edp->popup_wnd, edp->bg_object);
350                        evas_event_thaw(edp->popup_wnd->evas);
351
352                        e_popup_show(edp->popup_wnd);
353
354                        edd->elock_wnd_list = eina_list_append(edd->elock_wnd_list, edp);
355                     }
356                   zone_counter++;
357                }
358           }
359      }
360
361    /* handlers */
362    edd->handlers = 
363      eina_list_append(edd->handlers,
364                       ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
365                                               _e_desklock_cb_key_down, NULL));
366    edd->handlers =
367      eina_list_append(edd->handlers,
368                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_STACK,
369                                               _e_desklock_cb_window_stack, NULL));
370    edd->handlers =
371      eina_list_append(edd->handlers,
372                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE,
373                                               _e_desklock_cb_window_stack, NULL));
374    edd->handlers =
375      eina_list_append(edd->handlers,
376                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE,
377                                               _e_desklock_cb_window_stack, NULL));
378
379    if ((total_zone_num > 1) && (e_config->desklock_login_box_zone == -2)) 
380      {
381         edd->handlers = 
382           eina_list_append(edd->handlers,
383                            ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
384                                                    _e_desklock_cb_mouse_move,
385                                                    NULL));
386      }
387
388    _e_desklock_passwd_update();
389
390    ev = E_NEW(E_Event_Desklock, 1);
391    ev->on = 1;
392    ecore_event_add(E_EVENT_DESKLOCK, ev, NULL, NULL);
393    return 1;
394 }
395
396 EAPI void
397 e_desklock_hide(void)
398 {
399    E_Desklock_Popup_Data *edp;
400    E_Event_Desklock *ev;
401
402    if ((!edd) && (!_e_custom_desklock_exe)) return;
403
404    if (e_config->desklock_use_custom_desklock)
405      {
406         _e_custom_desklock_exe = NULL;
407         return;
408      }
409
410    if (edd->elock_grab_break_wnd)
411      ecore_x_window_show(edd->elock_grab_break_wnd);
412
413    EINA_LIST_FREE(edd->elock_wnd_list, edp)
414      {
415         if (edp)
416           {
417              e_popup_hide(edp->popup_wnd);
418
419              evas_event_freeze(edp->popup_wnd->evas);
420              evas_object_del(edp->bg_object);
421              evas_object_del(edp->login_box);
422              evas_event_thaw(edp->popup_wnd->evas);
423
424              e_util_defer_object_del(E_OBJECT(edp->popup_wnd));
425              E_FREE(edp);
426           }
427      }
428
429    E_FREE_LIST(edd->handlers, ecore_event_handler_del);
430
431    e_grabinput_release(edd->elock_wnd, edd->elock_wnd);
432    ecore_x_window_free(edd->elock_wnd);
433
434    E_FREE(edd);
435    edd = NULL;
436
437    ev = E_NEW(E_Event_Desklock, 1);
438    ev->on = 0;
439    ecore_event_add(E_EVENT_DESKLOCK, ev, NULL, NULL);
440
441    if (_e_desklock_autolock_time > 0.0)
442      {
443         if ((e_config->desklock_ask_presentation) &&
444             (e_config->desklock_ask_presentation_timeout > 0.0))
445           {
446              double max, now;
447
448              now = ecore_loop_time_get();
449              max = _e_desklock_autolock_time + e_config->desklock_ask_presentation_timeout;
450              if (now <= max)
451                _e_desklock_ask_presentation_mode();
452           }
453         else
454           _e_desklock_ask_presentation_count = 0;
455
456         _e_desklock_autolock_time = 0.0;
457      }
458 }
459
460 static Eina_Bool
461 _e_desklock_cb_window_stack(void *data __UNUSED__,
462                             int   type,
463                             void *event)
464 {
465    Ecore_X_Window win;
466    E_Desklock_Popup_Data *edp;
467    Eina_List *l;
468    Eina_Bool raise = EINA_TRUE;
469
470    if (type == ECORE_X_EVENT_WINDOW_STACK)
471      win = ((Ecore_X_Event_Window_Stack*) event)->event_win;
472    else if (type == ECORE_X_EVENT_WINDOW_STACK)
473      win = ((Ecore_X_Event_Window_Configure*) event)->event_win;
474    else if (type == ECORE_X_EVENT_WINDOW_CREATE)
475      win = ((Ecore_X_Event_Window_Create*) event)->win;
476    else 
477      return ECORE_CALLBACK_PASS_ON;
478    
479    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
480      {
481         if (win == edp->popup_wnd->evas_win)
482           {
483              raise = EINA_FALSE;             
484              break;
485           }
486      }
487
488    if (raise)
489      {
490         EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
491           ecore_evas_raise(edp->popup_wnd->ecore_evas);
492      }
493
494    return ECORE_CALLBACK_PASS_ON;
495 }
496
497 static Eina_Bool
498 _e_desklock_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
499 {
500    Ecore_Event_Key *ev = event;
501
502    if ((ev->window != edd->elock_wnd) || 
503        (edd->state == E_DESKLOCK_STATE_CHECKING)) return 1;
504
505    if (!strcmp(ev->key, "Escape"))
506      ;
507    else if (!strcmp(ev->key, "KP_Enter"))
508      _e_desklock_check_auth();
509    else if (!strcmp(ev->key, "Return"))
510      _e_desklock_check_auth();
511    else if (!strcmp(ev->key, "BackSpace"))
512      _e_desklock_backspace();
513    else if (!strcmp(ev->key, "Delete"))
514      _e_desklock_delete();
515    else if ((!strcmp(ev->key, "u") && 
516              (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)))
517      _e_desklock_null();
518    else
519      {
520         /* here we have to grab a password */
521         if (ev->compose)
522           {
523              if ((strlen(edd->passwd) < (PASSWD_LEN - strlen(ev->compose))))
524                {
525                   strcat(edd->passwd, ev->compose);
526                   _e_desklock_passwd_update();
527                }
528           }
529      }
530
531    return ECORE_CALLBACK_PASS_ON;
532 }
533
534 static Eina_Bool
535 _e_desklock_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
536 {
537    E_Desklock_Popup_Data *edp;
538    E_Zone *current_zone;
539    Eina_List *l;
540
541    current_zone = e_zone_current_get(e_container_current_get(e_manager_current_get()));
542
543    if (current_zone == last_active_zone)
544      return ECORE_CALLBACK_PASS_ON;
545
546    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
547      {
548         if (!edp) continue;
549
550         if (edp->popup_wnd->zone == last_active_zone)
551           evas_object_hide(edp->login_box);
552         else if (edp->popup_wnd->zone == current_zone)
553           evas_object_show(edp->login_box);
554      }
555    last_active_zone = current_zone;
556    return ECORE_CALLBACK_PASS_ON;
557 }
558
559 static void
560 _e_desklock_passwd_update(void)
561 {
562    int len, i;
563    char passwd_hidden[PASSWD_LEN] = "", *pp;
564    E_Desklock_Popup_Data *edp;
565    Eina_List *l;
566
567    if (!edd) return;
568
569    len = eina_unicode_utf8_get_len(edd->passwd);
570    for (i = 0, pp = passwd_hidden ; i < len ; i++, pp++)
571      *pp = '*';
572    *pp = 0;
573
574    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
575      edje_object_part_text_set(edp->login_box, "e.text.password",
576                                passwd_hidden);
577 }
578
579 static void
580 _e_desklock_null(void)
581 {
582    memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
583    _e_desklock_passwd_update();
584 }
585
586 static void
587 _e_desklock_backspace(void)
588 {
589    int len, val, pos;
590
591    if (!edd) return;
592
593    len = strlen(edd->passwd);
594    if (len > 0)
595      {
596         pos = evas_string_char_prev_get(edd->passwd, len, &val);
597         if ((pos < len) && (pos >= 0))
598           {
599              edd->passwd[pos] = 0;
600              _e_desklock_passwd_update();
601           }
602      }
603 }
604
605 static void
606 _e_desklock_delete(void)
607 {
608    _e_desklock_backspace();
609 }
610
611 static int
612 _e_desklock_zone_num_get(void)
613 {
614    int num;
615    Eina_List *l, *l2;
616    E_Manager *man;
617
618    num = 0;
619    EINA_LIST_FOREACH(e_manager_list(), l, man)
620      {
621         E_Container *con;
622         EINA_LIST_FOREACH(man->containers, l2, con)
623           num += eina_list_count(con->zones);
624      }
625
626    return num;
627 }
628
629 static int
630 _e_desklock_check_auth(void)
631 {
632    if (!edd) return 0;
633 #ifdef HAVE_PAM
634    if (e_config->desklock_auth_method == 0)
635      return _desklock_auth(edd->passwd);
636    else if (e_config->desklock_auth_method == 1)
637      {
638 #endif
639         if ((e_config->desklock_personal_passwd) &&
640             (!strcmp(!edd->passwd ? "" : edd->passwd,
641                      !e_config->desklock_personal_passwd ? "" :
642                      e_config->desklock_personal_passwd)))
643           {
644              /* password ok */
645              /* security - null out passwd string once we are done with it */
646              memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
647              e_desklock_hide();
648              return 1;
649           }
650 #ifdef HAVE_PAM
651      }
652 #endif
653    /* password is definitely wrong */
654    _e_desklock_state_set(E_DESKLOCK_STATE_INVALID);
655    _e_desklock_null();
656    return 0;
657 }
658
659 static void
660 _e_desklock_state_set(int state)
661 {
662    Eina_List *l;
663    E_Desklock_Popup_Data *edp;
664    const char *signal, *text;
665    if (!edd) return;
666
667    edd->state = state;
668    if (state == E_DESKLOCK_STATE_CHECKING)
669      {
670         signal = "e,state,checking";
671         text = "Authenticating...";
672      }
673    else if (state == E_DESKLOCK_STATE_INVALID)
674      {
675         signal = "e,state,invalid";
676         text = "The password you entered is invalid. Try again.";
677      }
678    else
679      return;
680
681    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
682      {
683         edje_object_signal_emit(edp->login_box, signal, "e.desklock");
684         edje_object_signal_emit(edp->bg_object, signal, "e.desklock");
685         edje_object_part_text_set(edp->login_box, "e.text.title", text);
686      }
687 }
688
689
690 #ifdef HAVE_PAM
691 static Eina_Bool
692 _e_desklock_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
693 {
694    Ecore_Exe_Event_Del *ev = event;
695
696    if (ev->pid == _e_desklock_child_pid)
697      {
698         _e_desklock_child_pid = -1;
699         /* ok */
700         if (ev->exit_code == 0)
701           {
702              /* security - null out passwd string once we are done with it */
703              memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
704              e_desklock_hide();
705           }
706         /* error */
707         else if (ev->exit_code < 128)
708           {
709              /* security - null out passwd string once we are done with it */
710              memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
711              e_desklock_hide();
712              e_util_dialog_show(_("Authentication System Error"),
713                                 _("Authentication via PAM had errors setting up the<br>"
714                                   "authentication session. The error code was <hilight>%i</hilight>.<br>"
715                                   "This is bad and should not be happening. Please report this bug.")
716                                 , ev->exit_code);
717           }
718         /* failed auth */
719         else
720           {
721              _e_desklock_state_set(E_DESKLOCK_STATE_INVALID);
722              /* security - null out passwd string once we are done with it */
723              _e_desklock_null();
724           }
725         if (_e_desklock_exit_handler) 
726           ecore_event_handler_del(_e_desklock_exit_handler);
727         _e_desklock_exit_handler = NULL;
728      }
729    return ECORE_CALLBACK_PASS_ON;
730 }
731
732 static int
733 _desklock_auth(char *passwd)
734 {
735    _e_desklock_state_set(E_DESKLOCK_STATE_CHECKING);
736    _e_desklock_child_pid = fork();
737    if (_e_desklock_child_pid > 0)
738      {
739         /* parent */
740         _e_desklock_exit_handler =
741           ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _e_desklock_cb_exit,
742                                   NULL);
743      }
744    else if (_e_desklock_child_pid == 0)
745      {
746         /* child */
747         int pamerr;
748         E_Desklock_Auth da;
749         char *current_user, *p;
750         struct sigaction action;
751
752         action.sa_handler = SIG_DFL;
753         action.sa_flags = SA_ONSTACK | SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
754         sigemptyset(&action.sa_mask);
755         sigaction(SIGSEGV, &action, NULL);
756         sigaction(SIGILL, &action, NULL);
757         sigaction(SIGFPE, &action, NULL);
758         sigaction(SIGBUS, &action, NULL);
759         sigaction(SIGABRT, &action, NULL);
760
761         current_user = _desklock_auth_get_current_user();
762         eina_strlcpy(da.user, current_user, sizeof(da.user));
763         eina_strlcpy(da.passwd, passwd, sizeof(da.passwd));
764         /* security - null out passwd string once we are done with it */
765         for (p = passwd; *p; p++) *p = 0;
766         da.pam.handle = NULL;
767         da.pam.conv.conv = NULL;
768         da.pam.conv.appdata_ptr = NULL;
769
770         pamerr = _desklock_pam_init(&da);
771         if (pamerr != PAM_SUCCESS)
772           {
773              free(current_user);
774              exit(1);
775           }
776         pamerr = pam_authenticate(da.pam.handle, 0);
777         pam_end(da.pam.handle, pamerr);
778         /* security - null out passwd string once we are done with it */
779         memset(da.passwd, 0, sizeof(da.passwd));
780         if (pamerr == PAM_SUCCESS)
781           {
782              free(current_user);
783              exit(0);
784           }
785         free(current_user);
786         exit(-1);
787      }
788    else
789      {
790         _e_desklock_state_set(E_DESKLOCK_STATE_INVALID);
791         return 0;
792      }
793    return 1;
794 }
795
796 static char *
797 _desklock_auth_get_current_user(void)
798 {
799    char *user;
800    struct passwd *pwent = NULL;
801
802    pwent = getpwuid(getuid());
803    user = strdup(pwent->pw_name);
804    return user;
805 }
806
807 static int
808 _desklock_pam_init(E_Desklock_Auth *da)
809 {
810    int pamerr;
811    const char *pam_prof;
812    char *current_host;
813    char *current_user;
814
815    if (!da) return -1;
816
817    da->pam.conv.conv = _desklock_auth_pam_conv;
818    da->pam.conv.appdata_ptr = da;
819    da->pam.handle = NULL;
820
821    /* try other pam profiles - and system-auth (login for fbsd users) is a fallback */
822    pam_prof = "login";
823    if (ecore_file_exists("/etc/pam.d/enlightenment"))
824      pam_prof = "enlightenment";
825    else if (ecore_file_exists("/etc/pam.d/xscreensaver"))
826      pam_prof = "xscreensaver";
827    else if (ecore_file_exists("/etc/pam.d/kscreensaver"))
828      pam_prof = "kscreensaver";
829    else if (ecore_file_exists("/etc/pam.d/system-auth"))
830      pam_prof = "system-auth";
831    else if (ecore_file_exists("/etc/pam.d/system"))
832      pam_prof = "system";
833    else if (ecore_file_exists("/etc/pam.d/xdm"))
834      pam_prof = "xdm";
835    else if (ecore_file_exists("/etc/pam.d/gdm"))
836      pam_prof = "gdm";
837    else if (ecore_file_exists("/etc/pam.d/kdm"))
838      pam_prof = "kdm";
839
840    if ((pamerr = pam_start(pam_prof, da->user, &(da->pam.conv),
841                            &(da->pam.handle))) != PAM_SUCCESS)
842      return pamerr;
843
844    current_user = _desklock_auth_get_current_user();
845
846    if ((pamerr = pam_set_item(da->pam.handle, PAM_USER, current_user)) != PAM_SUCCESS)
847      {
848         free(current_user);
849         return pamerr;
850      }
851
852    current_host = _desklock_auth_get_current_host();
853    if ((pamerr = pam_set_item(da->pam.handle, PAM_RHOST, current_host)) != PAM_SUCCESS)
854      {
855         free(current_user);
856         free(current_host);
857         return pamerr;
858      }
859
860    free(current_user);
861    free(current_host);
862    return 0;
863 }
864
865 static int
866 _desklock_auth_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
867 {
868    int replies = 0;
869    E_Desklock_Auth *da = (E_Desklock_Auth *)appdata_ptr;
870    struct pam_response *reply = NULL;
871
872    reply = (struct pam_response *)malloc(sizeof(struct pam_response) *num_msg);
873
874    if (!reply) return PAM_CONV_ERR;
875
876    for (replies = 0; replies < num_msg; replies++)
877      {
878         switch (msg[replies]->msg_style)
879           {
880            case PAM_PROMPT_ECHO_ON:
881              reply[replies].resp_retcode = PAM_SUCCESS;
882              reply[replies].resp = strdup(da->user);
883              break;
884            case PAM_PROMPT_ECHO_OFF:
885              reply[replies].resp_retcode = PAM_SUCCESS;
886              reply[replies].resp = strdup(da->passwd);
887              break;
888            case PAM_ERROR_MSG:
889            case PAM_TEXT_INFO:
890              reply[replies].resp_retcode = PAM_SUCCESS;
891              reply[replies].resp = NULL;
892              break;
893            default:
894              free(reply);
895              return PAM_CONV_ERR;
896           }
897      }
898    *resp = reply;
899    return PAM_SUCCESS;
900 }
901
902 static char *
903 _desklock_auth_get_current_host(void)
904 {
905    return strdup("localhost");
906 }
907 #endif
908
909 static Eina_Bool
910 _e_desklock_cb_custom_desklock_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
911 {
912    Ecore_Exe_Event_Del *ev = event;
913
914    if (ev->exe != _e_custom_desklock_exe) return ECORE_CALLBACK_PASS_ON;
915
916    if (ev->exit_code != 0)
917      {
918         /* do something profound here... like notify someone */
919      }
920
921    e_desklock_hide();
922
923    return ECORE_CALLBACK_DONE;
924 }
925
926 static Eina_Bool
927 _e_desklock_cb_idle_poller(void *data __UNUSED__)
928 {
929    if ((e_config->desklock_autolock_idle) && (!e_config->mode.presentation) &&
930        (!e_util_fullscreen_curreny_any()))
931      {
932         double idle, max;
933
934         /* If a desklock is already up, bail */
935         if ((_e_custom_desklock_exe) || (edd)) return ECORE_CALLBACK_RENEW;
936
937         idle = ecore_x_screensaver_idle_time_get();
938         max = e_config->desklock_autolock_idle_timeout;
939         if (_e_desklock_ask_presentation_count > 0)
940           max *= (1 + _e_desklock_ask_presentation_count);
941
942         /* If we have exceeded our idle time... */
943         if (idle >= max)
944           {
945              /*
946               * Unfortunately, not all "desklocks" stay up for as long as
947               * the user is idle or until it is unlocked.
948               *
949               * 'xscreensaver-command -lock' for example sends a command
950               * to xscreensaver and then terminates.  So, we have another
951               * check (_e_desklock_user_idle) which lets us know that we
952               * have locked the screen due to idleness.
953               */
954              if (!_e_desklock_user_idle)
955                {
956                   _e_desklock_user_idle = 1;
957                   e_desklock_show_autolocked();
958                }
959           }
960         else
961           _e_desklock_user_idle = 0;
962      }
963
964    /* Make sure our poller persists. */
965    return ECORE_CALLBACK_RENEW;
966 }
967
968 static void
969 _e_desklock_ask_presentation_del(void *data)
970 {
971    if (_e_desklock_ask_presentation_dia == data)
972      _e_desklock_ask_presentation_dia = NULL;
973 }
974
975 static void
976 _e_desklock_ask_presentation_yes(void *data __UNUSED__, E_Dialog *dia)
977 {
978    e_config->mode.presentation = 1;
979    e_config_mode_changed();
980    e_config_save_queue();
981    e_object_del(E_OBJECT(dia));
982    _e_desklock_ask_presentation_count = 0;
983 }
984
985 static void
986 _e_desklock_ask_presentation_no(void *data __UNUSED__, E_Dialog *dia)
987 {
988    e_object_del(E_OBJECT(dia));
989    _e_desklock_ask_presentation_count = 0;
990 }
991
992 static void
993 _e_desklock_ask_presentation_no_increase(void *data __UNUSED__, E_Dialog *dia)
994 {
995    int timeout, interval, blanking, expose;
996
997    _e_desklock_ask_presentation_count++;
998    timeout = e_config->screensaver_timeout * _e_desklock_ask_presentation_count;
999    interval = e_config->screensaver_interval;
1000    blanking = e_config->screensaver_blanking;
1001    expose = e_config->screensaver_expose;
1002
1003    ecore_x_screensaver_set(timeout, interval, blanking, expose);
1004    e_object_del(E_OBJECT(dia));
1005 }
1006
1007 static void
1008 _e_desklock_ask_presentation_no_forever(void *data __UNUSED__, E_Dialog *dia)
1009 {
1010    e_config->desklock_ask_presentation = 0;
1011    e_config_save_queue();
1012    e_object_del(E_OBJECT(dia));
1013    _e_desklock_ask_presentation_count = 0;
1014 }
1015
1016 static void
1017 _e_desklock_ask_presentation_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event)
1018 {
1019    Evas_Event_Key_Down *ev = event;
1020    E_Dialog *dia = data;
1021
1022    if (strcmp(ev->keyname, "Return") == 0)
1023      _e_desklock_ask_presentation_yes(NULL, dia);
1024    else if (strcmp(ev->keyname, "Escape") == 0)
1025      _e_desklock_ask_presentation_no(NULL, dia);
1026 }
1027
1028 static void
1029 _e_desklock_ask_presentation_mode(void)
1030 {
1031    E_Manager *man;
1032    E_Container *con;
1033    E_Dialog *dia;
1034
1035    if (_e_desklock_ask_presentation_dia) return;
1036
1037    if (!(man = e_manager_current_get())) return;
1038    if (!(con = e_container_current_get(man))) return;
1039    if (!(dia = e_dialog_new(con, "E", "_desklock_ask_presentation"))) return;
1040
1041    e_dialog_title_set(dia, _("Activate Presentation Mode?"));
1042    e_dialog_icon_set(dia, "dialog-ask", 64);
1043    e_dialog_text_set(dia,
1044                      _("You unlocked desktop too fast.<br><br>"
1045                        "Would you like to enable <b>presentation</b> mode and "
1046                        "temporarily disable screen saver, lock and power saving?"));
1047
1048    e_object_del_attach_func_set(E_OBJECT(dia), 
1049                                 _e_desklock_ask_presentation_del);
1050    e_dialog_button_add(dia, _("Yes"), NULL, 
1051                        _e_desklock_ask_presentation_yes, NULL);
1052    e_dialog_button_add(dia, _("No"), NULL, 
1053                        _e_desklock_ask_presentation_no, NULL);
1054    e_dialog_button_add(dia, _("No, but increase timeout"), NULL,
1055                        _e_desklock_ask_presentation_no_increase, NULL);
1056    e_dialog_button_add(dia, _("No, and stop asking"), NULL,
1057                        _e_desklock_ask_presentation_no_forever, NULL);
1058
1059    e_dialog_button_focus_num(dia, 0);
1060    e_widget_list_homogeneous_set(dia->box_object, 0);
1061    e_win_centered_set(dia->win, 1);
1062    e_dialog_show(dia);
1063
1064    evas_object_event_callback_add(dia->bg_object, EVAS_CALLBACK_KEY_DOWN,
1065                                   _e_desklock_ask_presentation_key_down, dia);
1066
1067    _e_desklock_ask_presentation_dia = dia;
1068 }