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