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