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