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