]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/libsystem.c
Just create proxy and ask for owner rather than manually calling StartServiceByName...
[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 (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 (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     if (pamh == NULL)
1210         return PAM_SYSTEM_ERR;
1211
1212     connect_status ();
1213     if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1214     {
1215         GString *status;
1216
1217         status = g_string_new ("");
1218         g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
1219         if (flags & PAM_SILENT)
1220             g_string_append (status, " SILENT");
1221
1222         status_notify (status->str);
1223         g_string_free (status, TRUE);
1224     }
1225
1226     if (strcmp (pamh->user, "session-error") == 0)
1227         return PAM_SESSION_ERR;
1228
1229     if (strcmp (pamh->user, "make-home-dir") == 0)
1230     {
1231         struct passwd *entry;
1232         entry = getpwnam (pamh->user);
1233         g_mkdir_with_parents (entry->pw_dir, 0755);
1234     }
1235
1236     return PAM_SUCCESS;
1237 }
1238
1239 int
1240 pam_close_session (pam_handle_t *pamh, int flags)
1241 {
1242     if (pamh == NULL)
1243         return PAM_SYSTEM_ERR;
1244
1245     connect_status ();
1246     if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1247     {
1248         GString *status;
1249
1250         status = g_string_new ("");
1251         g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
1252         if (flags & PAM_SILENT)
1253             g_string_append (status, " SILENT");
1254
1255         status_notify (status->str);
1256         g_string_free (status, TRUE);
1257     }
1258
1259     return PAM_SUCCESS;
1260 }
1261
1262 int
1263 pam_acct_mgmt (pam_handle_t *pamh, int flags)
1264 {
1265     if (pamh == NULL)
1266         return PAM_SYSTEM_ERR;
1267
1268     connect_status ();
1269     if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1270     {
1271         GString *status;
1272
1273         status = g_string_new ("");
1274         g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
1275         if (flags & PAM_SILENT)
1276             g_string_append (status, " SILENT");
1277         if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1278             g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1279
1280         status_notify (status->str);
1281         g_string_free (status, TRUE);
1282     }
1283   
1284     if (!pamh->user)
1285         return PAM_USER_UNKNOWN;
1286
1287     if (strcmp (pamh->user, "denied") == 0)
1288         return PAM_PERM_DENIED;
1289     if (strcmp (pamh->user, "expired") == 0)
1290         return PAM_ACCT_EXPIRED;
1291     if (strcmp (pamh->user, "new-authtok") == 0)
1292         return PAM_NEW_AUTHTOK_REQD;
1293
1294     return PAM_SUCCESS;
1295 }
1296
1297 int
1298 pam_chauthtok (pam_handle_t *pamh, int flags)
1299 {
1300     struct passwd *entry;
1301     int result;
1302     struct pam_message **msg;
1303     struct pam_response *resp = NULL;
1304
1305     if (pamh == NULL)
1306         return PAM_SYSTEM_ERR;
1307
1308     connect_status ();
1309     if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1310     {
1311         GString *status;
1312
1313         status = g_string_new ("");
1314         g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
1315         if (flags & PAM_SILENT)
1316             g_string_append (status, " SILENT");
1317         if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
1318             g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
1319
1320         status_notify (status->str);
1321         g_string_free (status, TRUE);
1322     }
1323
1324     msg = malloc (sizeof (struct pam_message *) * 1);
1325     msg[0] = malloc (sizeof (struct pam_message));
1326     msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1327     if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
1328         msg[0]->msg = "Enter new password (expired):";
1329     else
1330         msg[0]->msg = "Enter new password:";
1331     result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1332     free (msg[0]);
1333     free (msg);
1334     if (result != PAM_SUCCESS)
1335         return result;
1336
1337     if (resp == NULL)
1338         return PAM_CONV_ERR;
1339     if (resp[0].resp == NULL)
1340     {
1341         free (resp);
1342         return PAM_CONV_ERR;
1343     }
1344
1345     /* Update password database */
1346     entry = getpwnam (pamh->user);
1347     free (entry->pw_passwd);
1348     entry->pw_passwd = resp[0].resp;
1349     free (resp);
1350
1351     return PAM_SUCCESS;
1352 }
1353
1354 int
1355 pam_setcred (pam_handle_t *pamh, int flags)
1356 {
1357     gchar *e;
1358
1359     if (pamh == NULL)
1360         return PAM_SYSTEM_ERR;
1361
1362     connect_status ();
1363     if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1364     {
1365         GString *status;
1366
1367         status = g_string_new ("");
1368         g_string_append_printf (status, "%s SETCRED", pamh->id);
1369         if (flags & PAM_SILENT)
1370             g_string_append (status, " SILENT");
1371         if (flags & PAM_ESTABLISH_CRED)
1372             g_string_append (status, " ESTABLISH_CRED");
1373         if (flags & PAM_DELETE_CRED)
1374             g_string_append (status, " DELETE_CRED");
1375         if (flags & PAM_REINITIALIZE_CRED)
1376             g_string_append (status, " REINITIALIZE_CRED");
1377         if (flags & PAM_REFRESH_CRED)
1378             g_string_append (status, " REFRESH_CRED");
1379
1380         status_notify (status->str);
1381         g_string_free (status, TRUE);
1382     }
1383
1384     /* Put the test directories into the path */
1385     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"));
1386     pam_putenv (pamh, e);
1387     g_free (e);
1388
1389     if (strcmp (pamh->user, "cred-error") == 0)
1390         return PAM_CRED_ERR;
1391     if (strcmp (pamh->user, "cred-expired") == 0)
1392         return PAM_CRED_EXPIRED;
1393     if (strcmp (pamh->user, "cred-unavail") == 0)
1394         return PAM_CRED_UNAVAIL;
1395
1396     /* Join special groups if requested */
1397     if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
1398     {
1399         struct group *group;
1400         gid_t *groups;
1401         int groups_length;
1402
1403         group = getgrnam ("test-group");
1404         if (group)
1405         {
1406             groups_length = getgroups (0, NULL);
1407             if (groups_length < 0)
1408                 return PAM_SYSTEM_ERR;
1409             groups = malloc (sizeof (gid_t) * (groups_length + 1));
1410             groups_length = getgroups (groups_length, groups);
1411             if (groups_length < 0)
1412                 return PAM_SYSTEM_ERR;
1413             groups[groups_length] = group->gr_gid;
1414             groups_length++;
1415             setgroups (groups_length, groups);
1416             free (groups);
1417         }
1418
1419         /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1420         pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1421     }
1422
1423     return PAM_SUCCESS;
1424 }
1425
1426 int
1427 pam_end (pam_handle_t *pamh, int pam_status)
1428 {
1429     if (pamh == NULL)
1430         return PAM_SYSTEM_ERR;
1431
1432     connect_status ();
1433     if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1434     {
1435         GString *status;
1436
1437         status = g_string_new ("");
1438         g_string_append_printf (status, "%s END", pamh->id);
1439         status_notify (status->str);
1440         g_string_free (status, TRUE);
1441     }
1442
1443     free (pamh->id);
1444     free (pamh->service_name);
1445     if (pamh->user)
1446         free (pamh->user);
1447     if (pamh->authtok)
1448         free (pamh->authtok);
1449     if (pamh->ruser)
1450         free (pamh->ruser);
1451     if (pamh->tty)
1452         free (pamh->tty);
1453     free (pamh);
1454
1455     return PAM_SUCCESS;
1456 }
1457
1458 const char *
1459 pam_strerror (pam_handle_t *pamh, int errnum)
1460 {
1461     if (pamh == NULL)
1462         return NULL;
1463
1464     switch (errnum)
1465     {
1466     case PAM_SUCCESS:
1467         return "Success";
1468     case PAM_ABORT:
1469         return "Critical error - immediate abort";
1470     case PAM_OPEN_ERR:
1471         return "Failed to load module";
1472     case PAM_SYMBOL_ERR:
1473         return "Symbol not found";
1474     case PAM_SERVICE_ERR:
1475         return "Error in service module";
1476     case PAM_SYSTEM_ERR:
1477         return "System error";
1478     case PAM_BUF_ERR:
1479         return "Memory buffer error";
1480     case PAM_PERM_DENIED:
1481         return "Permission denied";
1482     case PAM_AUTH_ERR:
1483         return "Authentication failure";
1484     case PAM_CRED_INSUFFICIENT:
1485         return "Insufficient credentials to access authentication data";
1486     case PAM_AUTHINFO_UNAVAIL:
1487         return "Authentication service cannot retrieve authentication info";
1488     case PAM_USER_UNKNOWN:
1489         return "User not known to the underlying authentication module";
1490     case PAM_MAXTRIES:
1491         return "Have exhausted maximum number of retries for service";
1492     case PAM_NEW_AUTHTOK_REQD:
1493         return "Authentication token is no longer valid; new one required";
1494     case PAM_ACCT_EXPIRED:
1495         return "User account has expired";
1496     case PAM_SESSION_ERR:
1497         return "Cannot make/remove an entry for the specified session";
1498     case PAM_CRED_UNAVAIL:
1499         return "Authentication service cannot retrieve user credentials";
1500     case PAM_CRED_EXPIRED:
1501         return "User credentials expired";
1502     case PAM_CRED_ERR:
1503         return "Failure setting user credentials";
1504     case PAM_NO_MODULE_DATA:
1505         return "No module specific data is present";
1506     case PAM_BAD_ITEM:
1507         return "Bad item passed to pam_*_item()";
1508     case PAM_CONV_ERR:
1509         return "Conversation error";
1510     case PAM_AUTHTOK_ERR:
1511         return "Authentication token manipulation error";
1512     case PAM_AUTHTOK_RECOVERY_ERR:
1513         return "Authentication information cannot be recovered";
1514     case PAM_AUTHTOK_LOCK_BUSY:
1515         return "Authentication token lock busy";
1516     case PAM_AUTHTOK_DISABLE_AGING:
1517         return "Authentication token aging disabled";
1518     case PAM_TRY_AGAIN:
1519         return "Failed preliminary check by password service";
1520     case PAM_IGNORE:
1521         return "The return value should be ignored by PAM dispatch";
1522     case PAM_MODULE_UNKNOWN:
1523         return "Module is unknown";
1524     case PAM_AUTHTOK_EXPIRED:
1525         return "Authentication token expired";
1526     case PAM_CONV_AGAIN:
1527         return "Conversation is waiting for event";
1528     case PAM_INCOMPLETE:
1529         return "Application needs to call libpam again";
1530     default:
1531         return "Unknown PAM error";
1532     }
1533 }
1534
1535 void
1536 setutxent (void)
1537 {
1538 }
1539
1540 struct utmpx *
1541 pututxline (const struct utmpx *ut)
1542 {
1543     connect_status ();
1544     if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1545     {
1546         GString *status;
1547
1548         status = g_string_new ("UTMP");
1549         switch (ut->ut_type)
1550         {
1551         case INIT_PROCESS:
1552             g_string_append_printf (status, " TYPE=INIT_PROCESS");
1553             break;
1554         case LOGIN_PROCESS:
1555             g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1556             break;
1557         case USER_PROCESS:
1558             g_string_append_printf (status, " TYPE=USER_PROCESS");
1559             break;
1560         case DEAD_PROCESS:
1561             g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1562             break;
1563         default:
1564             g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1565         }
1566         if (ut->ut_line)
1567             g_string_append_printf (status, " LINE=%s", ut->ut_line);
1568         if (ut->ut_id)
1569             g_string_append_printf (status, " ID=%s", ut->ut_id);
1570         if (ut->ut_user)
1571             g_string_append_printf (status, " USER=%s", ut->ut_user);
1572         if (ut->ut_host)
1573             g_string_append_printf (status, " HOST=%s", ut->ut_host);
1574         status_notify ("%s", status->str);
1575         g_string_free (status, TRUE);
1576     }
1577
1578     return (struct utmpx *)ut;
1579 }
1580
1581 void
1582 endutxent (void)
1583 {
1584 }
1585
1586 void
1587 updwtmp (const char *wtmp_file, const struct utmp *ut)
1588 {
1589     connect_status ();
1590     if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1591     {
1592         GString *status;
1593
1594         status = g_string_new ("WTMP");
1595         g_string_append_printf (status, " FILE=%s", wtmp_file);
1596         switch (ut->ut_type)
1597         {
1598         case INIT_PROCESS:
1599             g_string_append_printf (status, " TYPE=INIT_PROCESS");
1600             break;
1601         case LOGIN_PROCESS:
1602             g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1603             break;
1604         case USER_PROCESS:
1605             g_string_append_printf (status, " TYPE=USER_PROCESS");
1606             break;
1607         case DEAD_PROCESS:
1608             g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1609             break;
1610         default:
1611             g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1612         }
1613         if (ut->ut_line)
1614             g_string_append_printf (status, " LINE=%s", ut->ut_line);
1615         if (ut->ut_id)
1616             g_string_append_printf (status, " ID=%s", ut->ut_id);
1617         if (ut->ut_user)
1618             g_string_append_printf (status, " USER=%s", ut->ut_user);
1619         if (ut->ut_host)
1620             g_string_append_printf (status, " HOST=%s", ut->ut_host);
1621         status_notify ("%s", status->str);
1622         g_string_free (status, TRUE);
1623     }
1624 }
1625
1626 struct xcb_connection_t
1627 {
1628     gchar *display;
1629     int error;
1630     GSocket *socket;
1631 };
1632
1633 xcb_connection_t *
1634 xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
1635 {
1636     xcb_connection_t *c;
1637     gchar *socket_path;
1638     GError *error = NULL;
1639   
1640     c = malloc (sizeof (xcb_connection_t));
1641     c->display = g_strdup (display);
1642     c->error = 0;
1643
1644     if (display == NULL)
1645         display = getenv ("DISPLAY");
1646     if (display == NULL)
1647         c->error = XCB_CONN_CLOSED_PARSE_ERR;
1648
1649     if (c->error == 0)
1650     {
1651         c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1652         if (error)
1653             g_printerr ("%s\n", error->message);
1654         g_clear_error (&error);
1655         if (c->socket == NULL)
1656             c->error = XCB_CONN_ERROR;
1657     }
1658
1659     if (c->error == 0)
1660     {
1661         gchar *d;
1662         GSocketAddress *address;
1663
1664         /* Skip the hostname, we'll assume it's localhost */
1665         d = g_strdup_printf (".x%s", strchr (display, ':'));
1666
1667         socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
1668         g_free (d);
1669         address = g_unix_socket_address_new (socket_path);
1670         if (!g_socket_connect (c->socket, address, NULL, &error))
1671             c->error = XCB_CONN_ERROR;
1672         g_object_unref (address);
1673         if (error)
1674             g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
1675         g_free (socket_path);
1676         g_clear_error (&error);
1677     }
1678
1679     // FIXME: Send auth info
1680     if (c->error == 0)
1681     {
1682     }
1683
1684     return c;
1685 }
1686
1687 xcb_connection_t *
1688 xcb_connect (const char *displayname, int *screenp)
1689 {
1690     return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
1691 }
1692
1693 int
1694 xcb_connection_has_error (xcb_connection_t *c)
1695 {
1696     return c->error;
1697 }
1698
1699 void
1700 xcb_disconnect (xcb_connection_t *c)
1701 {
1702     free (c->display);
1703     if (c->socket)
1704         g_object_unref (c->socket);
1705     free (c);
1706 }