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