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