]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/libsystem.c
Add greeter-show-remote-login hint
[sojka/lightdm.git] / tests / src / libsystem.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <sys/types.h>
5 #include <pwd.h>
6 #include <grp.h>
7 #include <security/pam_appl.h>
8 #include <fcntl.h>
9 #define __USE_GNU
10 #include <dlfcn.h>
11 #ifdef __linux__
12 #include <linux/vt.h>
13 #endif
14 #include <glib.h>
15
16 #define LOGIN_PROMPT "login:"
17
18 static int console_fd = -1;
19
20 static GList *user_entries = NULL;
21 static GList *getpwent_link = NULL;
22
23 static GList *group_entries = NULL;
24
25 struct pam_handle
26 {
27     char *service_name;
28     char *user;
29     char *authtok;
30     char *ruser;
31     char *tty;
32     char **envlist;
33     struct pam_conv conversation;
34 };
35
36 uid_t
37 getuid (void)
38 {
39     return 0;
40 }
41
42 /*uid_t
43 geteuid (void)
44 {
45     return 0;
46 }*/
47
48 int
49 initgroups (const char *user, gid_t group)
50 {
51     gid_t g[1];
52
53     g[0] = group;
54     setgroups (1, g);
55
56     return 0;
57 }
58
59 int
60 getgroups (int size, gid_t list[])
61 {
62     const gchar *group_list;
63     gchar **groups;
64     gint groups_length;
65
66     /* Get groups we are a member of */
67     group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
68     if (!group_list)
69         group_list = "";
70     groups = g_strsplit (group_list, ",", -1);
71     groups_length = g_strv_length (groups);
72
73     if (size != 0)
74     {
75         int i;
76
77         if (groups_length > size)
78         {
79             errno = EINVAL;
80             return -1;
81         }
82         for (i = 0; groups[i]; i++)
83             list[i] = atoi (groups[i]);
84     }
85     g_free (groups);
86
87     return groups_length;
88 }
89
90 int
91 setgroups (size_t size, const gid_t *list)
92 {
93     size_t i;
94     GString *group_list;
95
96     group_list = g_string_new ("");
97     for (i = 0; i < size; i++)
98     {
99         if (i != 0)
100             g_string_append (group_list, ",");
101         g_string_append_printf (group_list, "%d", list[i]);
102     }
103     g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
104     g_string_free (group_list, TRUE);
105
106     return 0;
107 }
108
109 int
110 setgid (gid_t gid)
111 {
112     return 0;
113 }
114
115 int
116 setegid (gid_t gid)
117 {
118     return 0;
119 }
120
121 int
122 setresgid (gid_t rgid, gid_t ugid, gid_t sgid)
123 {
124     return 0;
125 }
126
127 int
128 setuid (uid_t uid)
129 {
130     return 0;
131 }
132
133 int
134 seteuid (uid_t uid)
135 {
136     return 0;
137 }
138
139 int
140 setresuid (uid_t ruid, uid_t uuid, uid_t suid)
141 {
142     return 0;
143 }
144
145 #ifdef __linux__
146 static int
147 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
148 {
149     int (*_open) (const char * pathname, int flags, mode_t mode);
150
151     _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
152     if (strcmp (pathname, "/dev/console") == 0)
153     {
154         if (console_fd < 0)
155         {
156             console_fd = _open ("/dev/null", flags, mode);
157             fcntl (console_fd, F_SETFD, FD_CLOEXEC);
158         }
159         return console_fd;
160     }
161     else if (strcmp (pathname, CONFIG_DIR "/lightdm.conf") == 0)
162     {
163         gchar *path;
164         int fd;
165
166         path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "lightdm", "lightdm.conf", NULL);
167         fd = _open (path, flags, mode);
168         g_free (path);
169
170         return fd;
171     }
172     else
173         return _open (pathname, flags, mode);
174 }
175
176 int
177 open (const char *pathname, int flags, ...)
178 {
179     int mode = 0;
180     if (flags & O_CREAT)
181     {
182         va_list ap;
183         va_start (ap, flags);
184         mode = va_arg (ap, int);
185         va_end (ap);
186     }
187     return open_wrapper ("open", pathname, flags, mode);
188 }
189
190 int
191 open64 (const char *pathname, int flags, ...)
192 {
193     int mode = 0;
194     if (flags & O_CREAT)
195     {
196         va_list ap;
197         va_start (ap, flags);
198         mode = va_arg (ap, int);
199         va_end (ap);
200     }
201     return open_wrapper ("open64", pathname, flags, mode);
202 }
203
204 int
205 ioctl (int d, int request, void *data)
206 {
207     int (*_ioctl) (int d, int request, void *data);
208
209     _ioctl = (int (*)(int d, int request, void *data)) dlsym (RTLD_NEXT, "ioctl");
210     if (d > 0 && d == console_fd)
211     {
212         struct vt_stat *console_state;
213
214         switch (request)
215         {
216         case VT_GETSTATE:
217             console_state = data;
218             console_state->v_active = 7;
219             break;          
220         case VT_ACTIVATE:
221             break;
222         }
223         return 0;
224     }
225     else
226         return _ioctl (d, request, data);
227 }
228
229 int
230 close (int fd)
231 {
232     int (*_close) (int fd);
233
234     if (fd > 0 && fd == console_fd)
235         return 0;
236
237     _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
238     return _close (fd);
239 }
240 #endif
241
242 static void
243 free_user (gpointer data)
244 {
245     struct passwd *entry = data;
246   
247     g_free (entry->pw_name);
248     g_free (entry->pw_passwd);
249     g_free (entry->pw_gecos);
250     g_free (entry->pw_dir);
251     g_free (entry->pw_shell);
252     g_free (entry);
253 }
254
255 static void
256 load_passwd_file ()
257 {
258     gchar *path, *data = NULL, **lines;
259     gint i;
260     GError *error = NULL;
261
262     g_list_free_full (user_entries, free_user);
263     user_entries = NULL;
264     getpwent_link = NULL;
265
266     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
267     g_file_get_contents (path, &data, NULL, &error);
268     g_free (path);
269     if (error)
270         g_warning ("Error loading passwd file: %s", error->message);
271     g_clear_error (&error);
272
273     if (!data)
274         return;
275
276     lines = g_strsplit (data, "\n", -1);
277     g_free (data);
278
279     for (i = 0; lines[i]; i++)
280     {
281         gchar *line, **fields;
282
283         line = g_strstrip (lines[i]);
284         fields = g_strsplit (line, ":", -1);
285         if (g_strv_length (fields) == 7)
286         {
287             struct passwd *entry = malloc (sizeof (struct passwd));
288
289             entry->pw_name = g_strdup (fields[0]);
290             entry->pw_passwd = g_strdup (fields[1]);
291             entry->pw_uid = atoi (fields[2]);
292             entry->pw_gid = atoi (fields[3]);
293             entry->pw_gecos = g_strdup (fields[4]);
294             entry->pw_dir = g_strdup (fields[5]);
295             entry->pw_shell = g_strdup (fields[6]);
296             user_entries = g_list_append (user_entries, entry);
297         }
298         g_strfreev (fields);
299     }
300     g_strfreev (lines);
301 }
302
303 struct passwd *
304 getpwent (void)
305 {
306     if (getpwent_link == NULL)
307     {
308         load_passwd_file ();
309         if (user_entries == NULL)
310             return NULL;
311         getpwent_link = user_entries;
312     }
313     else
314     {
315         if (getpwent_link->next == NULL)
316             return NULL;
317         getpwent_link = getpwent_link->next;
318     }
319
320     return getpwent_link->data;
321 }
322
323 void
324 setpwent (void)
325 {
326     getpwent_link = NULL;
327 }
328
329 void
330 endpwent (void)
331 {
332     getpwent_link = NULL;
333 }
334
335 struct passwd *
336 getpwnam (const char *name)
337 {
338     GList *link;
339   
340     if (name == NULL)
341         return NULL;
342   
343     load_passwd_file ();
344
345     for (link = user_entries; link; link = link->next)
346     {
347         struct passwd *entry = link->data;
348         if (strcmp (entry->pw_name, name) == 0)
349             break;
350     }
351     if (!link)
352         return NULL;
353
354     return link->data;
355 }
356
357 struct passwd *
358 getpwuid (uid_t uid)
359 {
360     GList *link;
361
362     load_passwd_file ();
363
364     for (link = user_entries; link; link = link->next)
365     {
366         struct passwd *entry = link->data;
367         if (entry->pw_uid == uid)
368             break;
369     }
370     if (!link)
371         return NULL;
372
373     return link->data;
374 }
375
376 static void
377 free_group (gpointer data)
378 {
379     struct group *entry = data;
380   
381     g_free (entry->gr_name);
382     g_free (entry->gr_passwd);
383     g_strfreev (entry->gr_mem);
384     g_free (entry);
385 }
386
387 static void
388 load_group_file ()
389 {
390     gchar *path, *data = NULL, **lines;
391     gint i;
392     GError *error = NULL;
393
394     g_list_free_full (group_entries, free_group);
395     group_entries = NULL;
396
397     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
398     g_file_get_contents (path, &data, NULL, &error);
399     g_free (path);
400     if (error)
401         g_warning ("Error loading group file: %s", error->message);
402     g_clear_error (&error);
403
404     if (!data)
405         return;
406
407     lines = g_strsplit (data, "\n", -1);
408     g_free (data);
409
410     for (i = 0; lines[i]; i++)
411     {
412         gchar *line, **fields;
413
414         line = g_strstrip (lines[i]);
415         fields = g_strsplit (line, ":", -1);
416         if (g_strv_length (fields) == 4)
417         {
418             struct group *entry = malloc (sizeof (struct group));
419
420             entry->gr_name = g_strdup (fields[0]);
421             entry->gr_passwd = g_strdup (fields[1]);
422             entry->gr_gid = atoi (fields[2]);
423             entry->gr_mem = g_strsplit (fields[3], ",", -1);
424             group_entries = g_list_append (group_entries, entry);
425         }
426         g_strfreev (fields);
427     }
428     g_strfreev (lines);
429 }
430
431 struct group *
432 getgrnam (const char *name)
433 {
434     GList *link;
435
436     load_group_file ();
437
438     for (link = group_entries; link; link = link->next)
439     {
440         struct group *entry = link->data;
441         if (strcmp (entry->gr_name, name) == 0)
442             break;
443     }
444     if (!link)
445         return NULL;
446
447     return link->data;
448 }
449
450 struct group *
451 getgrgid (gid_t gid)
452 {
453     GList *link;
454
455     load_group_file ();
456
457     for (link = group_entries; link; link = link->next)
458     {
459         struct group *entry = link->data;
460         if (entry->gr_gid == gid)
461             break;
462     }
463     if (!link)
464         return NULL;
465
466     return link->data;
467 }
468
469 int
470 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
471 {
472     pam_handle_t *handle;
473
474     if (service_name == NULL || conversation == NULL || pamh == NULL)
475         return PAM_SYSTEM_ERR;
476
477     handle = *pamh = malloc (sizeof (pam_handle_t));
478     if (handle == NULL)
479         return PAM_BUF_ERR;
480
481     handle->service_name = strdup (service_name);
482     handle->user = user ? strdup (user) : NULL;
483     handle->authtok = NULL;
484     handle->ruser = NULL;
485     handle->tty = NULL;
486     handle->conversation.conv = conversation->conv;
487     handle->conversation.appdata_ptr = conversation->appdata_ptr;
488     handle->envlist = malloc (sizeof (char *) * 1);
489     handle->envlist[0] = NULL;
490
491     return PAM_SUCCESS;
492 }
493
494 static void
495 send_info (pam_handle_t *pamh, const char *message)
496 {
497     struct pam_message **msg;
498     struct pam_response *resp = NULL;
499
500     msg = calloc (1, sizeof (struct pam_message *));
501     msg[0] = malloc (sizeof (struct pam_message));
502     msg[0]->msg_style = PAM_TEXT_INFO;
503     msg[0]->msg = message;
504     pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
505     free (msg[0]);
506     free (msg);
507     if (resp)
508     {
509         if (resp[0].resp)
510             free (resp[0].resp);
511         free (resp);
512     }
513 }
514
515 int
516 pam_authenticate (pam_handle_t *pamh, int flags)
517 {
518     struct passwd *entry;
519     gboolean password_matches = FALSE;
520
521     if (pamh == NULL)
522         return PAM_SYSTEM_ERR;
523   
524     if (strcmp (pamh->service_name, "test-remote") == 0)
525     {
526         int result;
527         struct pam_message **msg;
528         struct pam_response *resp = NULL;
529
530         msg = malloc (sizeof (struct pam_message *) * 1);
531         msg[0] = malloc (sizeof (struct pam_message));
532         msg[0]->msg_style = PAM_PROMPT_ECHO_ON; 
533         msg[0]->msg = "remote-login:";
534         result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
535         free (msg[0]);
536         free (msg);
537         if (result != PAM_SUCCESS)
538             return result;
539
540         if (resp == NULL)
541             return PAM_CONV_ERR;
542         if (resp[0].resp == NULL)
543         {
544             free (resp);
545             return PAM_CONV_ERR;
546         }
547
548         if (pamh->ruser)
549             free (pamh->ruser);
550         pamh->ruser = strdup (resp[0].resp);
551         free (resp[0].resp);
552         free (resp);
553
554         msg = malloc (sizeof (struct pam_message *) * 1);
555         msg[0] = malloc (sizeof (struct pam_message));
556         msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
557         msg[0]->msg = "remote-password:";
558         result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
559         free (msg[0]);
560         free (msg);
561         if (result != PAM_SUCCESS)
562             return result;
563
564         if (resp == NULL)
565             return PAM_CONV_ERR;
566         if (resp[0].resp == NULL)
567         {
568             free (resp);
569             return PAM_CONV_ERR;
570         }
571
572         if (pamh->authtok)
573             free (pamh->authtok);
574         pamh->authtok = strdup (resp[0].resp);
575         free (resp[0].resp);
576         free (resp);
577
578         password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0;
579
580         if (password_matches)
581             return PAM_SUCCESS;
582         else
583             return PAM_AUTH_ERR;
584     }
585
586     /* Prompt for username */
587     if (pamh->user == NULL)
588     {
589         int result;
590         struct pam_message **msg;
591         struct pam_response *resp = NULL;
592
593         msg = malloc (sizeof (struct pam_message *) * 1);
594         msg[0] = malloc (sizeof (struct pam_message));
595         msg[0]->msg_style = PAM_PROMPT_ECHO_ON; 
596         msg[0]->msg = LOGIN_PROMPT;
597         result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
598         free (msg[0]);
599         free (msg);
600         if (result != PAM_SUCCESS)
601             return result;
602
603         if (resp == NULL)
604             return PAM_CONV_ERR;
605         if (resp[0].resp == NULL)
606         {
607             free (resp);
608             return PAM_CONV_ERR;
609         }
610       
611         pamh->user = strdup (resp[0].resp);
612         free (resp[0].resp);
613         free (resp);
614     }
615
616     if (strcmp (pamh->user, "log-pam") == 0)
617         send_info (pamh, "pam_authenticate");
618
619     /* Crash on authenticate */
620     if (strcmp (pamh->user, "crash-authenticate") == 0)
621         kill (getpid (), SIGSEGV);
622
623     /* Look up password database */
624     entry = getpwnam (pamh->user);
625
626     /* Prompt for password if required */
627     if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
628         password_matches = TRUE;
629     else
630     {
631         int i, n_messages = 0, password_index, result;
632         struct pam_message **msg;
633         struct pam_response *resp = NULL;
634
635         msg = malloc (sizeof (struct pam_message *) * 5);
636         if (strcmp (pamh->user, "info-prompt") == 0)
637         {
638             msg[n_messages] = malloc (sizeof (struct pam_message));
639             msg[n_messages]->msg_style = PAM_TEXT_INFO;
640             msg[n_messages]->msg = "Welcome to LightDM";
641             n_messages++;
642         }
643         if (strcmp (pamh->user, "multi-info-prompt") == 0)
644         {
645             msg[n_messages] = malloc (sizeof (struct pam_message));
646             msg[n_messages]->msg_style = PAM_TEXT_INFO;
647             msg[n_messages]->msg = "Welcome to LightDM";
648             n_messages++;
649             msg[n_messages] = malloc (sizeof (struct pam_message));
650             msg[n_messages]->msg_style = PAM_ERROR_MSG;
651             msg[n_messages]->msg = "This is an error";
652             n_messages++;
653             msg[n_messages] = malloc (sizeof (struct pam_message));
654             msg[n_messages]->msg_style = PAM_TEXT_INFO;
655             msg[n_messages]->msg = "You should have seen three messages";
656             n_messages++;
657         }
658         if (strcmp (pamh->user, "multi-prompt") == 0)
659         {
660             msg[n_messages] = malloc (sizeof (struct pam_message));
661             msg[n_messages]->msg_style = PAM_PROMPT_ECHO_ON;
662             msg[n_messages]->msg = "Favorite Color:";
663             n_messages++;
664         }
665         msg[n_messages] = malloc (sizeof (struct pam_message));
666         msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
667         msg[n_messages]->msg = "Password:";
668         password_index = n_messages;
669         n_messages++;
670         result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
671         for (i = 0; i < n_messages; i++)
672             free (msg[i]);
673         free (msg);
674         if (result != PAM_SUCCESS)
675             return result;
676
677         if (resp == NULL)
678             return PAM_CONV_ERR;
679         if (resp[password_index].resp == NULL)
680         {
681             free (resp);
682             return PAM_CONV_ERR;
683         }
684
685         if (entry)
686             password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
687
688         if (password_matches && strcmp (pamh->user, "multi-prompt") == 0)
689             password_matches = strcmp ("blue", resp[0].resp) == 0;
690
691         for (i = 0; i < n_messages; i++)
692         {
693             if (resp[i].resp)
694                 free (resp[i].resp);
695         }
696         free (resp);
697
698         /* Do two factor authentication */
699         if (password_matches && strcmp (pamh->user, "two-factor") == 0)
700         {
701             msg = malloc (sizeof (struct pam_message *) * 1);
702             msg[0] = malloc (sizeof (struct pam_message));
703             msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
704             msg[0]->msg = "OTP:";
705             resp = NULL;
706             result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
707             free (msg[0]);
708             free (msg);
709
710             if (resp == NULL)
711                 return PAM_CONV_ERR;
712             if (resp[0].resp == NULL)
713             {
714                 free (resp);
715                 return PAM_CONV_ERR;
716             }
717             password_matches = strcmp (resp[0].resp, "otp") == 0;
718             free (resp[0].resp);
719             free (resp);
720         }
721     }
722
723     /* Special user has home directory created on login */
724     if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
725         g_mkdir_with_parents (entry->pw_dir, 0755);
726
727     /* Special user 'change-user1' changes user on authentication */
728     if (password_matches && strcmp (pamh->user, "change-user1") == 0)
729     {
730         g_free (pamh->user);
731         pamh->user = g_strdup ("change-user2");
732     }
733
734     /* Special user 'change-user-invalid' changes to an invalid user on authentication */
735     if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
736     {
737         g_free (pamh->user);
738         pamh->user = g_strdup ("invalid-user");
739     }
740
741     if (password_matches)
742         return PAM_SUCCESS;
743     else
744         return PAM_AUTH_ERR;
745 }
746
747 static const char *
748 get_env_value (const char *name_value, const char *name)
749 {
750     int j;
751
752     for (j = 0; name[j] && name[j] != '=' && name[j] == name_value[j]; j++);
753     if (name_value[j] == '=')
754         return &name_value[j + 1];
755
756     return NULL;
757 }
758
759 int
760 pam_putenv (pam_handle_t *pamh, const char *name_value)
761 {
762     int i;
763
764     if (pamh == NULL || name_value == NULL)
765         return PAM_SYSTEM_ERR;
766
767     for (i = 0; pamh->envlist[i]; i++)
768     {
769         if (get_env_value (pamh->envlist[i], name_value))
770             break;
771     }
772
773     if (pamh->envlist[i])
774     {
775         free (pamh->envlist[i]);
776         pamh->envlist[i] = strdup (name_value);
777     }
778     else
779     {
780         pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
781         pamh->envlist[i] = strdup (name_value);
782         pamh->envlist[i + 1] = NULL;
783     }
784
785     return PAM_SUCCESS;
786 }
787
788 const char *
789 pam_getenv (pam_handle_t *pamh, const char *name)
790 {
791     int i;
792
793     if (pamh == NULL || name == NULL)
794         return NULL;
795
796     for (i = 0; pamh->envlist[i]; i++)
797     {
798         const char *value;
799         value = get_env_value (pamh->envlist[i], name);
800         if (value)
801             return value;
802     }
803
804     return NULL;
805 }
806
807 char **
808 pam_getenvlist (pam_handle_t *pamh)
809 {
810     if (pamh == NULL)
811         return NULL;
812
813     return pamh->envlist;
814 }
815
816 int
817 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
818 {
819     if (pamh == NULL || item == NULL)
820         return PAM_SYSTEM_ERR;
821
822     switch (item_type)
823     {
824     case PAM_TTY:
825         if (pamh->tty)
826             free (pamh->tty);
827         pamh->tty = strdup ((const char *) item);
828         return PAM_SUCCESS;
829
830     default:
831         return PAM_BAD_ITEM;
832     }
833 }
834
835 int
836 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
837 {
838     if (pamh == NULL || item == NULL)
839         return PAM_SYSTEM_ERR;
840   
841     switch (item_type)
842     {
843     case PAM_SERVICE:
844         *item = pamh->service_name;
845         return PAM_SUCCESS;
846       
847     case PAM_USER:
848         *item = pamh->user;
849         return PAM_SUCCESS;
850
851     case PAM_AUTHTOK:
852         *item = pamh->authtok;
853         return PAM_SUCCESS;
854
855     case PAM_RUSER:
856         *item = pamh->ruser;
857         return PAM_SUCCESS;
858      
859     case PAM_USER_PROMPT:
860         *item = LOGIN_PROMPT;
861         return PAM_SUCCESS;
862       
863     case PAM_TTY:
864         *item = pamh->tty;
865         return PAM_SUCCESS;
866
867     case PAM_CONV:
868         *item = &pamh->conversation;
869         return PAM_SUCCESS;
870
871     default:
872         return PAM_BAD_ITEM;
873     }
874 }
875
876 int
877 pam_open_session (pam_handle_t *pamh, int flags)
878 {
879     if (pamh == NULL)
880         return PAM_SYSTEM_ERR;
881
882     if (strcmp (pamh->user, "session-error") == 0)
883         return PAM_SESSION_ERR;
884
885     if (strcmp (pamh->user, "log-pam") == 0)
886         send_info (pamh, "pam_open_session");
887
888     if (strcmp (pamh->user, "make-home-dir") == 0)
889     {
890         struct passwd *entry;
891         entry = getpwnam (pamh->user);
892         g_mkdir_with_parents (entry->pw_dir, 0755);
893     }
894
895     return PAM_SUCCESS;
896 }
897
898 int
899 pam_close_session (pam_handle_t *pamh, int flags)
900 {
901     if (pamh == NULL)
902         return PAM_SYSTEM_ERR;
903
904     if (strcmp (pamh->user, "log-pam") == 0)
905         send_info (pamh, "pam_close_session");
906
907     return PAM_SUCCESS;
908 }
909
910 int
911 pam_acct_mgmt (pam_handle_t *pamh, int flags)
912 {
913     if (pamh == NULL)
914         return PAM_SYSTEM_ERR;
915   
916     if (!pamh->user)
917         return PAM_USER_UNKNOWN;
918
919     if (strcmp (pamh->user, "log-pam") == 0)
920         send_info (pamh, "pam_acct_mgmt");
921
922     if (strcmp (pamh->user, "denied") == 0)
923         return PAM_PERM_DENIED;
924     if (strcmp (pamh->user, "expired") == 0)
925         return PAM_ACCT_EXPIRED;
926     if (strcmp (pamh->user, "new-authtok") == 0)
927         return PAM_NEW_AUTHTOK_REQD;
928
929     return PAM_SUCCESS;
930 }
931
932 int
933 pam_chauthtok (pam_handle_t *pamh, int flags)
934 {
935     struct passwd *entry;
936     int result;
937     struct pam_message **msg;
938     struct pam_response *resp = NULL;
939
940     if (pamh == NULL)
941         return PAM_SYSTEM_ERR;
942
943     if (strcmp (pamh->user, "log-pam") == 0)
944         send_info (pamh, "pam_chauthtok");
945
946     msg = malloc (sizeof (struct pam_message *) * 1);
947     msg[0] = malloc (sizeof (struct pam_message));
948     msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
949     msg[0]->msg = "Enter new password:";
950     result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
951     free (msg[0]);
952     free (msg);
953     if (result != PAM_SUCCESS)
954         return result;
955
956     if (resp == NULL)
957         return PAM_CONV_ERR;
958     if (resp[0].resp == NULL)
959     {
960         free (resp);
961         return PAM_CONV_ERR;
962     }
963
964     /* Update password database */
965     entry = getpwnam (pamh->user);
966     free (entry->pw_passwd);
967     entry->pw_passwd = resp[0].resp;
968     free (resp);
969
970     return PAM_SUCCESS;
971 }
972
973 int
974 pam_setcred (pam_handle_t *pamh, int flags)
975 {
976     gchar *e;
977
978     if (pamh == NULL)
979         return PAM_SYSTEM_ERR;
980
981     if (strcmp (pamh->user, "log-pam") == 0)
982         send_info (pamh, "pam_setcred");
983
984     /* Put the test directories into the path */
985     e = g_strdup_printf ("PATH=%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, pam_getenv (pamh, "PATH"));
986     pam_putenv (pamh, e);
987     g_free (e);
988
989     if (strcmp (pamh->user, "cred-error") == 0)
990         return PAM_CRED_ERR;
991     if (strcmp (pamh->user, "cred-expired") == 0)
992         return PAM_CRED_EXPIRED;
993     if (strcmp (pamh->user, "cred-unavail") == 0)
994         return PAM_CRED_UNAVAIL;
995
996     /* Join special groups if requested */
997     if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
998     {
999         struct group *group;
1000         gid_t *groups;
1001         int groups_length;
1002
1003         group = getgrnam ("test-group");
1004         if (group)
1005         {
1006             groups_length = getgroups (0, NULL);
1007             groups = malloc (sizeof (gid_t) * (groups_length + 1));
1008             groups_length = getgroups (groups_length, groups);
1009             groups[groups_length] = group->gr_gid;
1010             groups_length++;
1011             setgroups (groups_length, groups);
1012             free (groups);
1013         }
1014
1015         /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1016         pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1017     }
1018
1019     return PAM_SUCCESS;
1020 }
1021
1022 int
1023 pam_end (pam_handle_t *pamh, int pam_status)
1024 {
1025     if (pamh == NULL)
1026         return PAM_SYSTEM_ERR;
1027   
1028     free (pamh->service_name);
1029     if (pamh->user)
1030         free (pamh->user);
1031     if (pamh->authtok)
1032         free (pamh->authtok);
1033     if (pamh->ruser)
1034         free (pamh->ruser);
1035     if (pamh->tty)
1036         free (pamh->tty);
1037     free (pamh);
1038
1039     return PAM_SUCCESS;
1040 }
1041
1042 const char *
1043 pam_strerror (pam_handle_t *pamh, int errnum)
1044 {
1045     if (pamh == NULL)
1046         return NULL;
1047
1048     switch (errnum)
1049     {
1050     case PAM_SUCCESS:
1051         return "Success";
1052     case PAM_ABORT:
1053         return "Critical error - immediate abort";
1054     case PAM_OPEN_ERR:
1055         return "Failed to load module";
1056     case PAM_SYMBOL_ERR:
1057         return "Symbol not found";
1058     case PAM_SERVICE_ERR:
1059         return "Error in service module";
1060     case PAM_SYSTEM_ERR:
1061         return "System error";
1062     case PAM_BUF_ERR:
1063         return "Memory buffer error";
1064     case PAM_PERM_DENIED:
1065         return "Permission denied";
1066     case PAM_AUTH_ERR:
1067         return "Authentication failure";
1068     case PAM_CRED_INSUFFICIENT:
1069         return "Insufficient credentials to access authentication data";
1070     case PAM_AUTHINFO_UNAVAIL:
1071         return "Authentication service cannot retrieve authentication info";
1072     case PAM_USER_UNKNOWN:
1073         return "User not known to the underlying authentication module";
1074     case PAM_MAXTRIES:
1075         return "Have exhausted maximum number of retries for service";
1076     case PAM_NEW_AUTHTOK_REQD:
1077         return "Authentication token is no longer valid; new one required";
1078     case PAM_ACCT_EXPIRED:
1079         return "User account has expired";
1080     case PAM_SESSION_ERR:
1081         return "Cannot make/remove an entry for the specified session";
1082     case PAM_CRED_UNAVAIL:
1083         return "Authentication service cannot retrieve user credentials";
1084     case PAM_CRED_EXPIRED:
1085         return "User credentials expired";
1086     case PAM_CRED_ERR:
1087         return "Failure setting user credentials";
1088     case PAM_NO_MODULE_DATA:
1089         return "No module specific data is present";
1090     case PAM_BAD_ITEM:
1091         return "Bad item passed to pam_*_item()";
1092     case PAM_CONV_ERR:
1093         return "Conversation error";
1094     case PAM_AUTHTOK_ERR:
1095         return "Authentication token manipulation error";
1096     case PAM_AUTHTOK_RECOVERY_ERR:
1097         return "Authentication information cannot be recovered";
1098     case PAM_AUTHTOK_LOCK_BUSY:
1099         return "Authentication token lock busy";
1100     case PAM_AUTHTOK_DISABLE_AGING:
1101         return "Authentication token aging disabled";
1102     case PAM_TRY_AGAIN:
1103         return "Failed preliminary check by password service";
1104     case PAM_IGNORE:
1105         return "The return value should be ignored by PAM dispatch";
1106     case PAM_MODULE_UNKNOWN:
1107         return "Module is unknown";
1108     case PAM_AUTHTOK_EXPIRED:
1109         return "Authentication token expired";
1110     case PAM_CONV_AGAIN:
1111         return "Conversation is waiting for event";
1112     case PAM_INCOMPLETE:
1113         return "Application needs to call libpam again";
1114     default:
1115         return "Unknown PAM error";
1116     }
1117 }
1118
1119 void
1120 setutxent (void)
1121 {
1122 }
1123   
1124 struct utmp *
1125 pututxline (struct utmp *ut)
1126 {
1127     return ut;
1128 }
1129
1130 void
1131 endutxent (void)
1132 {
1133 }