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