]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/test-runner.c
Merge with trunk
[sojka/lightdm.git] / tests / src / test-runner.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <glib.h>
7 #include <glib/gstdio.h>
8 #include <glib-unix.h>
9 #include <gio/gio.h>
10 #include <gio/gunixsocketaddress.h>
11 #include <unistd.h>
12 #include <pwd.h>
13
14 /* Timeout in ms waiting for the status we expect */
15 static int status_timeout_ms = 4000;
16
17 /* Timeout in ms to wait for SIGTERM to be handled by a child process */
18 #define KILL_TIMEOUT 2000
19
20 static gchar *test_runner_command;
21 static gchar *config_path;
22 static GKeyFile *config;
23 static GSocket *status_socket = NULL;
24 static gchar *status_socket_name = NULL;
25 static GList *statuses = NULL;
26 typedef struct
27 {
28     gchar *text;
29     gboolean done;
30 } ScriptLine;
31 static GList *script = NULL;
32 static guint status_timeout = 0;
33 static gchar *temp_dir = NULL;
34 static int service_count;
35 typedef struct
36 {
37     pid_t pid;
38     guint kill_timeout;
39 } Process;
40 static Process *lightdm_process = NULL;
41 static GHashTable *children = NULL;
42 static gboolean stop = FALSE;
43 static gint exit_status = 0;
44 static GDBusConnection *accounts_connection = NULL;
45 static GDBusNodeInfo *accounts_info;
46 static GDBusNodeInfo *user_info;
47 typedef struct
48 {
49     guint uid;
50     gchar *user_name;
51     gchar *real_name;
52     gchar *home_directory;
53     gchar *path;
54     guint id;
55     gchar *language;
56     gchar *xsession;
57     gchar **layouts;
58     gboolean hidden;
59 } AccountsUser;
60 static GList *accounts_users = NULL;
61 static void handle_user_call (GDBusConnection       *connection,
62                               const gchar           *sender,
63                               const gchar           *object_path,
64                               const gchar           *interface_name,
65                               const gchar           *method_name,
66                               GVariant              *parameters,
67                               GDBusMethodInvocation *invocation,
68                               gpointer               user_data);
69 static GVariant *handle_user_get_property (GDBusConnection       *connection,
70                                            const gchar           *sender,
71                                            const gchar           *object_path,
72                                            const gchar           *interface_name,
73                                            const gchar           *property_name,
74                                            GError               **error,
75                                            gpointer               user_data);
76 static const GDBusInterfaceVTable user_vtable =
77 {
78     handle_user_call,
79     handle_user_get_property,
80 };
81 static GDBusConnection *ck_connection = NULL;
82 static GDBusNodeInfo *ck_session_info;
83 typedef struct
84 {
85     gchar *cookie;
86     gchar *path;
87     guint id;
88 } CKSession;
89 static GList *ck_sessions = NULL;
90 static gint ck_session_index = 0;
91 static void handle_session_call (GDBusConnection       *connection,
92                                     const gchar           *sender,
93                                     const gchar           *object_path,
94                                     const gchar           *interface_name,
95                                     const gchar           *method_name,
96                                     GVariant              *parameters,
97                                     GDBusMethodInvocation *invocation,
98                                     gpointer               user_data);
99 static const GDBusInterfaceVTable ck_session_vtable =
100 {
101     handle_session_call,
102 };
103
104 typedef struct
105 {
106     gchar *path;
107     guint pid;
108 } Login1Session;
109
110 static GList *login1_sessions = NULL;
111 static gint login1_session_index = 0;
112
113 typedef struct
114 {
115     GSocket *socket;
116     GSource *source;
117 } StatusClient;
118 static GList *status_clients = NULL;
119
120 static void run_lightdm (void);
121 static void quit (int status);
122 static void check_status (const gchar *status);
123 static AccountsUser *get_accounts_user_by_uid (guint uid);
124 static AccountsUser *get_accounts_user_by_name (const gchar *username);
125 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
126
127 static gboolean
128 kill_timeout_cb (gpointer data)
129 {
130     Process *process = data;
131
132     if (getenv ("DEBUG"))
133         g_print ("Sending SIGKILL to process %d\n", process->pid);
134     kill (process->pid, SIGKILL);
135     return FALSE;
136 }
137
138 static void
139 stop_process (Process *process)
140 {
141     if (process->kill_timeout != 0)
142         return;
143
144     if (getenv ("DEBUG"))
145         g_print ("Sending SIGTERM to process %d\n", process->pid);
146     kill (process->pid, SIGTERM);
147     process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
148 }
149
150 static void
151 process_exit_cb (GPid pid, gint status, gpointer data)
152 {
153     Process *process;
154     gchar *status_text;
155
156     if (getenv ("DEBUG"))
157     {
158         if (WIFEXITED (status))
159             g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
160         else
161             g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
162     }
163
164     if (lightdm_process && pid == lightdm_process->pid)
165     {
166         process = lightdm_process;
167         lightdm_process = NULL;
168         if (WIFEXITED (status))
169             status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
170         else
171             status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
172         check_status (status_text);
173     }
174     else
175     {
176         process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
177         if (!process)
178             return;
179         g_hash_table_remove (children, GINT_TO_POINTER (pid));
180     }
181
182     if (process->kill_timeout)
183         g_source_remove (process->kill_timeout);
184     process->kill_timeout = 0;
185
186     /* Quit once all children have stopped */
187     if (stop)
188         quit (exit_status);
189 }
190
191 static Process *
192 watch_process (pid_t pid)
193 {
194     Process *process;
195
196     process = g_malloc0 (sizeof (Process));
197     process->pid = pid;
198     process->kill_timeout = 0;
199
200     if (getenv ("DEBUG"))
201         g_print ("Watching process %d\n", process->pid);
202     g_child_watch_add (process->pid, process_exit_cb, NULL);
203
204     return process;
205 }
206
207 static void
208 quit (int status)
209 {
210     GHashTableIter iter;
211
212     if (!stop)
213         exit_status = status;
214     stop = TRUE;
215
216     /* Stop all the children */
217     g_hash_table_iter_init (&iter, children);
218     while (TRUE)
219     {
220         gpointer key, value;
221
222         if (!g_hash_table_iter_next (&iter, &key, &value))
223             break;
224
225         stop_process ((Process *)value);
226     }
227
228     /* Don't quit until all children are stopped */
229     if (g_hash_table_size (children) > 0)
230         return;
231
232     /* Stop the daemon */
233     if (lightdm_process)
234     {
235         stop_process (lightdm_process);
236         return;
237     }
238
239     if (status_socket_name)
240         unlink (status_socket_name);
241
242     if (temp_dir && getenv ("DEBUG") == NULL)
243     {
244         gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
245         if (system (command))
246             perror ("Failed to delete temp directory");
247     }
248
249     exit (status);
250 }
251
252 static void
253 fail (const gchar *event, const gchar *expected)
254 {
255     GList *link;
256
257     if (stop)
258         return;
259
260     g_printerr ("Command line: %s", test_runner_command);
261     g_printerr ("Events:\n");
262     for (link = statuses; link; link = link->next)
263         g_printerr ("    %s\n", (gchar *)link->data);
264     if (event)
265         g_printerr ("    %s\n", event);
266     if (expected)
267         g_printerr ("    ^^^ expected \"%s\"\n", expected);
268     else
269         g_printerr ("^^^ expected nothing\n");
270
271     quit (EXIT_FAILURE);
272 }
273
274 static gchar *
275 get_prefix (const gchar *text)
276 {
277     gchar *prefix;
278     gint i;
279
280     prefix = g_strdup (text);
281     for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
282     prefix[i] = '\0';
283
284     return prefix;
285 }
286
287 static ScriptLine *
288 get_script_line (const gchar *prefix)
289 {
290     GList *link;
291
292     for (link = script; link; link = link->next)
293     {
294         ScriptLine *line = link->data;
295
296         /* Ignore lines with other prefixes */
297         if (prefix)
298         {
299             gchar *p;
300             gboolean matches;
301
302             p = get_prefix (line->text);
303             matches = strcmp (prefix, p) == 0;
304             g_free (p);
305
306             if (!matches)
307                 continue;
308         }
309
310         if (!line->done)
311             return line;
312     }
313
314     return NULL;
315 }
316
317 static void
318 handle_command (const gchar *command)
319 {
320     const gchar *c;
321     gchar *name = NULL;
322     GHashTable *params;
323
324     c = command;
325     while (*c && !isspace (*c))
326         c++;
327     name = g_strdup_printf ("%.*s", (int) (c - command), command);
328
329     params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
330     while (TRUE)
331     {
332         const gchar *start;
333         gchar *param_name, *param_value;
334
335         while (isspace (*c))
336             c++;
337         start = c;
338         while (*c && !isspace (*c) && *c != '=')
339             c++;
340         if (*c == '\0')
341             break;
342
343         param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
344
345         if (*c == '=')
346         {
347             c++;
348             while (isspace (*c))
349                 c++;
350             if (*c == '\"')
351             {
352                 gboolean escaped = FALSE;
353                 GString *value;
354
355                 c++;
356                 value = g_string_new ("");
357                 while (*c)
358                 {
359                     if (*c == '\\')
360                     {
361                         if (escaped)
362                         {
363                             g_string_append_c (value, '\\');
364                             escaped = FALSE;
365                         }
366                         else
367                             escaped = TRUE;
368                     }
369                     else if (!escaped && *c == '\"')
370                         break;
371                     if (!escaped)
372                         g_string_append_c (value, *c);
373                     c++;
374                 }
375                 param_value = value->str;
376                 g_string_free (value, FALSE);
377                 if (*c == '\"')
378                     c++;
379             }
380             else
381             {
382                 start = c;
383                 while (*c && !isspace (*c))
384                     c++;
385                 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
386             }
387         }
388         else
389             param_value = g_strdup ("");
390
391         g_hash_table_insert (params, param_name, param_value);
392     }
393
394     if (strcmp (name, "WAIT") == 0)
395     {
396         sleep (1);
397     }
398     else if (strcmp (name, "LIST-SEATS") == 0)
399     {
400         GVariant *result, *value;
401         GString *status;
402         GVariantIter *iter;
403         const gchar *path;
404         int i = 0;
405
406         result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
407                                               "org.freedesktop.DisplayManager",
408                                               "/org/freedesktop/DisplayManager",
409                                               "org.freedesktop.DBus.Properties",
410                                               "Get",
411                                               g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
412                                               G_VARIANT_TYPE ("(v)"),
413                                               G_DBUS_CALL_FLAGS_NONE,
414                                               1000,
415                                               NULL,
416                                               NULL);
417
418         status = g_string_new ("RUNNER LIST-SEATS SEATS=");
419         g_variant_get (result, "(v)", &value);
420         g_variant_get (value, "ao", &iter);
421         while (g_variant_iter_loop (iter, "&o", &path))
422         {
423             if (i != 0)
424                 g_string_append (status, ",");
425             g_string_append (status, path);
426             i++;
427         }
428         g_variant_unref (value);
429         g_variant_unref (result);
430
431         check_status (status->str);
432         g_string_free (status, TRUE);
433     }
434     else if (strcmp (name, "LIST-SESSIONS") == 0)
435     {
436         GVariant *result, *value;
437         GString *status;
438         GVariantIter *iter;
439         const gchar *path;
440         int i = 0;
441
442         result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
443                                               "org.freedesktop.DisplayManager",
444                                               "/org/freedesktop/DisplayManager",
445                                               "org.freedesktop.DBus.Properties",
446                                               "Get",
447                                               g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
448                                               G_VARIANT_TYPE ("(v)"),
449                                               G_DBUS_CALL_FLAGS_NONE,
450                                               1000,
451                                               NULL,
452                                               NULL);
453
454         status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
455         g_variant_get (result, "(v)", &value);
456         g_variant_get (value, "ao", &iter);
457         while (g_variant_iter_loop (iter, "&o", &path))
458         {
459             if (i != 0)
460                 g_string_append (status, ",");
461             g_string_append (status, path);
462             i++;
463         }
464         g_variant_unref (value);
465         g_variant_unref (result);
466
467         check_status (status->str);
468         g_string_free (status, TRUE);
469     }
470     else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
471     {
472         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
473                                      "org.freedesktop.DisplayManager",
474                                      "/org/freedesktop/DisplayManager/Seat0",
475                                      "org.freedesktop.DisplayManager.Seat",
476                                      "SwitchToGreeter",
477                                      g_variant_new ("()"),
478                                      G_VARIANT_TYPE ("()"),
479                                      G_DBUS_CALL_FLAGS_NONE,
480                                      1000,
481                                      NULL,
482                                      NULL);
483         check_status ("RUNNER SWITCH-TO-GREETER");
484     }
485     else if (strcmp (name, "SWITCH-TO-USER") == 0)
486     {
487         gchar *status_text, *username;
488
489         username = g_hash_table_lookup (params, "USERNAME");
490         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
491                                      "org.freedesktop.DisplayManager",
492                                      "/org/freedesktop/DisplayManager/Seat0",
493                                      "org.freedesktop.DisplayManager.Seat",
494                                      "SwitchToUser",
495                                      g_variant_new ("(ss)", username, ""),
496                                      G_VARIANT_TYPE ("()"),
497                                      G_DBUS_CALL_FLAGS_NONE,
498                                      1000,
499                                      NULL,
500                                      NULL);
501         status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
502         check_status (status_text);
503         g_free (status_text);
504     }
505     else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
506     {
507         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
508                                      "org.freedesktop.DisplayManager",
509                                      "/org/freedesktop/DisplayManager/Seat0",
510                                      "org.freedesktop.DisplayManager.Seat",
511                                      "SwitchToGuest",
512                                      g_variant_new ("(s)", ""),
513                                      G_VARIANT_TYPE ("()"),
514                                      G_DBUS_CALL_FLAGS_NONE,
515                                      1000,
516                                      NULL,
517                                      NULL);
518         check_status ("RUNNER SWITCH-TO-GUEST");
519     }
520     else if (strcmp (name, "STOP-DAEMON") == 0)
521         stop_process (lightdm_process);
522     // FIXME: Make generic RUN-COMMAND
523     else if (strcmp (name, "START-XSERVER") == 0)
524     {
525         gchar *xserver_args, *command_line;
526         gchar **argv;
527         GPid pid;
528         Process *process;
529         GError *error = NULL;
530
531         xserver_args = g_hash_table_lookup (params, "ARGS");
532         if (!xserver_args)
533             xserver_args = "";
534         command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
535
536         if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
537             !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
538         {
539             g_printerr ("Error starting X server: %s", error->message);
540             quit (EXIT_FAILURE);
541         }
542         else
543         {
544             process = watch_process (pid);
545             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
546         }
547     }
548     else if (strcmp (name, "START-VNC-CLIENT") == 0)
549     {
550         gchar *vnc_client_args, *command_line;
551         gchar **argv;
552         GPid pid;
553         Process *process;
554         GError *error = NULL;
555
556         vnc_client_args = g_hash_table_lookup (params, "ARGS");
557         if (!vnc_client_args)
558             vnc_client_args = "";
559         command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
560
561         if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
562             !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
563         {
564             g_printerr ("Error starting VNC client: %s", error->message);
565             quit (EXIT_FAILURE);
566         }
567         else
568         {
569             process = watch_process (pid);
570             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
571         }
572     }
573     else if (strcmp (name, "ADD-USER") == 0)
574     {
575         gchar *status_text, *username;
576         AccountsUser *user;
577
578         username = g_hash_table_lookup (params, "USERNAME");
579         user = get_accounts_user_by_name (username);
580         if (user)
581             accounts_user_set_hidden (user, FALSE, TRUE);
582         else
583             g_warning ("Unknown user %s", username);
584
585         status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
586         check_status (status_text);
587         g_free (status_text);
588     }
589     else if (strcmp (name, "DELETE-USER") == 0)
590     {
591         gchar *status_text, *username;
592         AccountsUser *user;
593
594         username = g_hash_table_lookup (params, "USERNAME");
595         user = get_accounts_user_by_name (username);
596         if (user)
597             accounts_user_set_hidden (user, TRUE, TRUE);
598         else
599             g_warning ("Unknown user %s", username);
600
601         status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
602         check_status (status_text);
603         g_free (status_text);
604     }
605     /* Forward to external processes */
606     else if (g_str_has_prefix (name, "SESSION-") ||
607              g_str_has_prefix (name, "GREETER-") ||
608              g_str_has_prefix (name, "XSERVER-") ||
609              strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
610     {
611         GList *link;
612         for (link = status_clients; link; link = link->next)
613         {
614             StatusClient *client = link->data;
615             int length;
616             GError *error = NULL;
617
618             length = strlen (command);
619             if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
620                 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
621                 g_printerr ("Failed to write to client socket: %s\n", error->message);
622             g_clear_error (&error);
623         }
624     }
625     else
626     {
627         g_printerr ("Unknown command '%s'\n", name);
628         quit (EXIT_FAILURE);
629     }
630
631     g_free (name);
632     g_hash_table_unref (params);
633 }
634
635 static void
636 run_commands (void)
637 {
638     /* Stop daemon if requested */
639     while (TRUE)
640     {
641         ScriptLine *line;
642
643         /* Commands start with an asterisk */
644         line = get_script_line (NULL);
645         if (!line || line->text[0] != '*')
646             break;
647
648         statuses = g_list_append (statuses, g_strdup (line->text));
649         line->done = TRUE;
650
651         handle_command (line->text + 1);
652     }
653
654     /* Stop at the end of the script */
655     if (get_script_line (NULL) == NULL)
656         quit (EXIT_SUCCESS);
657 }
658
659 static gboolean
660 status_timeout_cb (gpointer data)
661 {
662     ScriptLine *line;
663
664     line = get_script_line (NULL);
665     fail ("(timeout)", line ? line->text : NULL);
666
667     return FALSE;
668 }
669
670 static void
671 check_status (const gchar *status)
672 {
673     ScriptLine *line;
674     gboolean result = FALSE;
675     gchar *prefix;
676
677     if (stop)
678         return;
679
680     statuses = g_list_append (statuses, g_strdup (status));
681
682     if (getenv ("DEBUG"))
683         g_print ("%s\n", status);
684
685     /* Try and match against expected */
686     prefix = get_prefix (status);
687     line = get_script_line (prefix);
688     g_free (prefix);
689     if (line)
690     {
691         gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
692         result = g_regex_match_simple (full_pattern, status, 0, 0);
693         g_free (full_pattern);
694     }
695
696     if (!result)
697     {
698         if (line == NULL)
699             line = get_script_line (NULL);
700         fail (NULL, line ? line->text : NULL);
701         return;
702     }
703
704     line->done = TRUE;
705
706     /* Restart timeout */
707     g_source_remove (status_timeout);
708     status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
709
710     run_commands ();
711 }
712
713 static gboolean
714 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
715 {
716     int length;
717     gchar buffer[1024];
718     ssize_t n_read;
719     GError *error = NULL;
720
721     n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
722     if (n_read > 0)
723         n_read = g_socket_receive (socket, buffer, length, NULL, &error);
724     if (error)
725         g_warning ("Error reading from socket: %s", error->message);
726     g_clear_error (&error);
727     if (n_read == 0)
728     {
729         status_clients = g_list_remove (status_clients, client);
730         g_object_unref (client->socket);
731         g_free (client);
732         return FALSE;
733     }
734     else if (n_read > 0)
735     {
736         buffer[n_read] = '\0';
737         check_status (buffer);
738     }
739
740     return TRUE;
741 }
742
743 static gboolean
744 status_connect_cb (gpointer data)
745 {
746     GSocket *socket;
747     GError *error = NULL;
748
749     socket = g_socket_accept (status_socket, NULL, &error);
750     if (error)
751         g_warning ("Failed to accept status connection: %s", error->message);
752     g_clear_error (&error);
753     if (socket)
754     {
755         StatusClient *client;
756
757         client = g_malloc0 (sizeof (StatusClient));
758         client->socket = socket;
759         client->source = g_socket_create_source (socket, G_IO_IN, NULL);
760         status_clients = g_list_append (status_clients, client);
761
762         g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
763         g_source_attach (client->source, NULL);
764     }
765
766     return TRUE;
767 }
768
769 static void
770 load_script (const gchar *filename)
771 {
772     int i;
773     gchar *data, **lines;
774
775     if (!g_file_get_contents (filename, &data, NULL, NULL))
776     {
777         g_printerr ("Unable to load script: %s\n", filename);
778         quit (EXIT_FAILURE);
779     }
780
781     lines = g_strsplit (data, "\n", -1);
782     g_free (data);
783
784     /* Load lines with #? prefix as expected behaviour */
785     for (i = 0; lines[i]; i++)
786     {
787         gchar *text = g_strstrip (lines[i]);
788         if (g_str_has_prefix (text, "#?"))
789         {
790             ScriptLine *line;
791             line = g_malloc0 (sizeof (ScriptLine));
792             line->text = g_strdup (text + 2);
793             line->done = FALSE;
794             script = g_list_append (script, line);
795         }
796     }
797     g_strfreev (lines);
798 }
799
800 static void
801 handle_upower_call (GDBusConnection       *connection,
802                     const gchar           *sender,
803                     const gchar           *object_path,
804                     const gchar           *interface_name,
805                     const gchar           *method_name,
806                     GVariant              *parameters,
807                     GDBusMethodInvocation *invocation,
808                     gpointer               user_data)
809 {
810     if (strcmp (method_name, "SuspendAllowed") == 0)
811     {
812         check_status ("UPOWER SUSPEND-ALLOWED");
813         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
814     }
815     else if (strcmp (method_name, "Suspend") == 0)
816     {
817         check_status ("UPOWER SUSPEND");
818         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
819     }
820     else if (strcmp (method_name, "HibernateAllowed") == 0)
821     {
822         check_status ("UPOWER HIBERNATE-ALLOWED");
823         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
824     }
825     else if (strcmp (method_name, "Hibernate") == 0)
826     {
827         check_status ("UPOWER HIBERNATE");
828         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
829     }
830     else
831         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
832 }
833
834 static void
835 upower_name_acquired_cb (GDBusConnection *connection,
836                          const gchar     *name,
837                          gpointer         user_data)
838 {
839     const gchar *upower_interface =
840         "<node>"
841         "  <interface name='org.freedesktop.UPower'>"
842         "    <method name='SuspendAllowed'>"
843         "      <arg name='allowed' direction='out' type='b'/>"
844         "    </method>"
845         "    <method name='Suspend'/>"
846         "    <method name='HibernateAllowed'>"
847         "      <arg name='allowed' direction='out' type='b'/>"
848         "    </method>"
849         "    <method name='Hibernate'/>"
850         "  </interface>"
851         "</node>";
852     static const GDBusInterfaceVTable upower_vtable =
853     {
854         handle_upower_call,
855     };
856     GDBusNodeInfo *upower_info;
857     GError *error = NULL;
858
859     upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
860     if (error)
861         g_warning ("Failed to parse D-Bus interface: %s", error->message);
862     g_clear_error (&error);
863     if (!upower_info)
864         return;
865     g_dbus_connection_register_object (connection,
866                                        "/org/freedesktop/UPower",
867                                        upower_info->interfaces[0],
868                                        &upower_vtable,
869                                        NULL, NULL,
870                                        &error);
871     if (error)
872         g_warning ("Failed to register UPower service: %s", error->message);
873     g_clear_error (&error);
874     g_dbus_node_info_unref (upower_info);
875
876     service_count--;
877     if (service_count == 0)
878         run_lightdm ();
879 }
880
881 static void
882 start_upower_daemon (void)
883 {
884     service_count++;
885     g_bus_own_name (G_BUS_TYPE_SYSTEM,
886                     "org.freedesktop.UPower",
887                     G_BUS_NAME_OWNER_FLAGS_NONE,
888                     upower_name_acquired_cb,
889                     NULL,
890                     NULL,
891                     NULL,
892                     NULL);
893 }
894
895 static CKSession *
896 open_ck_session (GVariant *params)
897 {
898     CKSession *session;
899     GString *cookie;
900     GVariantIter *iter;
901     const gchar *name;
902     GVariant *value;
903     GError *error = NULL;
904
905     session = g_malloc0 (sizeof (CKSession));
906     ck_sessions = g_list_append (ck_sessions, session);
907
908     cookie = g_string_new ("ck-cookie");
909     g_variant_get (params, "a(sv)", &iter);
910     while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
911     {
912         if (strcmp (name, "x11-display") == 0)
913         {
914             const gchar *display;
915             g_variant_get (value, "&s", &display);
916             g_string_append_printf (cookie, "-x%s", display);
917         }
918     }
919
920     session->cookie = cookie->str;
921     g_string_free (cookie, FALSE);
922     session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
923     session->id = g_dbus_connection_register_object (ck_connection,
924                                                      session->path,
925                                                      ck_session_info->interfaces[0],
926                                                      &ck_session_vtable,
927                                                      session,
928                                                      NULL,
929                                                      &error);
930     if (error)
931         g_warning ("Failed to register CK Session: %s", error->message);
932     g_clear_error (&error);
933
934     return session;
935 }
936
937 static void
938 handle_ck_call (GDBusConnection       *connection,
939                 const gchar           *sender,
940                 const gchar           *object_path,
941                 const gchar           *interface_name,
942                 const gchar           *method_name,
943                 GVariant              *parameters,
944                 GDBusMethodInvocation *invocation,
945                 gpointer               user_data)
946 {
947     if (strcmp (method_name, "CanRestart") == 0)
948     {
949         check_status ("CONSOLE-KIT CAN-RESTART");
950         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
951     }
952     else if (strcmp (method_name, "CanStop") == 0)
953     {
954         check_status ("CONSOLE-KIT CAN-STOP");
955         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
956     }
957     else if (strcmp (method_name, "CloseSession") == 0)
958         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
959     else if (strcmp (method_name, "OpenSession") == 0)
960     {
961         GVariantBuilder params;
962         g_variant_builder_init (&params, G_VARIANT_TYPE ("a(sv)"));
963         CKSession *session = open_ck_session (g_variant_builder_end (&params));
964         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
965     }
966     else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
967     {
968         CKSession *session = open_ck_session (g_variant_get_child_value (parameters, 0));
969         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
970     }
971     else if (strcmp (method_name, "GetSessionForCookie") == 0)
972     {
973         GList *link;
974         gchar *cookie;
975
976         g_variant_get (parameters, "(&s)", &cookie);
977
978         for (link = ck_sessions; link; link = link->next)
979         {
980             CKSession *session = link->data;
981             if (strcmp (session->cookie, cookie) != 0)
982             {
983                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
984                 return;
985             }
986         }
987
988         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
989     }
990     else if (strcmp (method_name, "Restart") == 0)
991     {
992         check_status ("CONSOLE-KIT RESTART");
993         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
994     }
995     else if (strcmp (method_name, "Stop") == 0)
996     {
997         check_status ("CONSOLE-KIT STOP");
998         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
999     }
1000     else
1001         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1002 }
1003
1004
1005 /* Shared between CK and Login1 - identical signatures */
1006 static void
1007 handle_session_call (GDBusConnection       *connection,
1008                      const gchar           *sender,
1009                      const gchar           *object_path,
1010                      const gchar           *interface_name,
1011                      const gchar           *method_name,
1012                      GVariant              *parameters,
1013                      GDBusMethodInvocation *invocation,
1014                      gpointer               user_data)
1015 {
1016     if (strcmp (method_name, "Lock") == 0)
1017         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1018     else if (strcmp (method_name, "Unlock") == 0)
1019         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1020     else
1021         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1022 }
1023
1024 static void
1025 ck_name_acquired_cb (GDBusConnection *connection,
1026                      const gchar     *name,
1027                      gpointer         user_data)
1028 {
1029     const gchar *ck_interface =
1030         "<node>"
1031         "  <interface name='org.freedesktop.ConsoleKit.Manager'>"
1032         "    <method name='CanRestart'>"
1033         "      <arg name='can_restart' direction='out' type='b'/>"
1034         "    </method>"
1035         "    <method name='CanStop'>"
1036         "      <arg name='can_stop' direction='out' type='b'/>"
1037         "    </method>"
1038         "    <method name='CloseSession'>"
1039         "      <arg name='cookie' direction='in' type='s'/>"
1040         "      <arg name='result' direction='out' type='b'/>"
1041         "    </method>"
1042         "    <method name='OpenSession'>"
1043         "      <arg name='cookie' direction='out' type='s'/>"
1044         "    </method>"
1045         "    <method name='OpenSessionWithParameters'>"
1046         "      <arg name='parameters' direction='in' type='a(sv)'/>"
1047         "      <arg name='cookie' direction='out' type='s'/>"
1048         "    </method>"
1049         "    <method name='GetSessionForCookie'>"
1050         "      <arg name='cookie' direction='in' type='s'/>"
1051         "      <arg name='ssid' direction='out' type='o'/>"
1052         "    </method>"
1053         "    <method name='Restart'/>"
1054         "    <method name='Stop'/>"
1055         "    <signal name='SeatAdded'>"
1056         "      <arg name='seat' type='o'/>"
1057         "    </signal>"
1058         "    <signal name='SeatRemoved'>"
1059         "      <arg name='seat' type='o'/>"
1060         "    </signal>"
1061         "  </interface>"
1062         "</node>";
1063     static const GDBusInterfaceVTable ck_vtable =
1064     {
1065         handle_ck_call,
1066     };
1067     const gchar *ck_session_interface =
1068         "<node>"
1069         "  <interface name='org.freedesktop.ConsoleKit.Session'>"
1070         "    <method name='Lock'/>"
1071         "    <method name='Unlock'/>"
1072         "  </interface>"
1073         "</node>";
1074     GDBusNodeInfo *ck_info;
1075     GError *error = NULL;
1076
1077     ck_connection = connection;
1078
1079     ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1080     if (error)
1081         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1082     g_clear_error (&error);
1083     if (!ck_info)
1084         return;
1085     ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1086     if (error)
1087         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1088     g_clear_error (&error);
1089     if (!ck_session_info)
1090         return;
1091     g_dbus_connection_register_object (connection,
1092                                        "/org/freedesktop/ConsoleKit/Manager",
1093                                        ck_info->interfaces[0],
1094                                        &ck_vtable,
1095                                        NULL, NULL,
1096                                        &error);
1097     if (error)
1098         g_warning ("Failed to register console kit service: %s", error->message);
1099     g_clear_error (&error);
1100     g_dbus_node_info_unref (ck_info);
1101
1102     service_count--;
1103     if (service_count == 0)
1104         run_lightdm ();
1105 }
1106
1107 static void
1108 start_console_kit_daemon (void)
1109 {
1110     service_count++;
1111     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1112                     "org.freedesktop.ConsoleKit",
1113                     G_BUS_NAME_OWNER_FLAGS_NONE,
1114                     ck_name_acquired_cb,
1115                     NULL,
1116                     NULL,
1117                     NULL,
1118                     NULL);
1119 }
1120
1121 static Login1Session *
1122 open_login1_session (GDBusConnection *connection,
1123                      GVariant *params)
1124 {
1125     Login1Session *session;
1126     GError *error = NULL;
1127     GDBusNodeInfo *login1_session_info;
1128
1129     const gchar *login1_session_interface =
1130         "<node>"
1131         "  <interface name='org.freedesktop.login1.Session'>"
1132         "    <method name='Lock'/>"
1133         "    <method name='Unlock'/>"
1134         "  </interface>"
1135         "</node>";
1136     static const GDBusInterfaceVTable login1_session_vtable =
1137     {
1138         handle_session_call,
1139     };
1140
1141     session = g_malloc0 (sizeof (Login1Session));
1142     login1_sessions = g_list_append (login1_sessions, session);
1143
1144     session->path = g_strdup_printf("/org/freedesktop/login1/Session/c%d",
1145                                     login1_session_index++);
1146
1147
1148
1149     login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface,
1150                                                         &error);
1151     if (error)
1152         g_warning ("Failed to parse login1 session D-Bus interface: %s",
1153                    error->message);
1154     g_clear_error (&error);
1155     if (!login1_session_info)
1156         return NULL;
1157
1158     g_dbus_connection_register_object (connection,
1159                                        session->path,
1160                                        login1_session_info->interfaces[0],
1161                                        &login1_session_vtable,
1162                                        session,
1163                                        NULL,
1164                                        &error);
1165     if (error)
1166         g_warning ("Failed to register login1 session: %s", error->message);
1167     g_clear_error (&error);
1168     g_dbus_node_info_unref (login1_session_info);
1169
1170     return session;
1171 }
1172
1173
1174 static void
1175 handle_login1_call (GDBusConnection       *connection,
1176                     const gchar           *sender,
1177                     const gchar           *object_path,
1178                     const gchar           *interface_name,
1179                     const gchar           *method_name,
1180                     GVariant              *parameters,
1181                     GDBusMethodInvocation *invocation,
1182                     gpointer               user_data)
1183 {
1184
1185     if (strcmp (method_name, "GetSessionByPID") == 0)
1186     {
1187         /* Look for a session with our PID, and create one if we don't have one
1188            already. */
1189         GList *link;
1190         guint pid;
1191         Login1Session *ret = NULL;
1192
1193         g_variant_get (parameters, "(u)", &pid);
1194
1195         for (link = login1_sessions; link; link = link->next)
1196         {
1197             Login1Session *session;
1198             session = link->data;
1199             if (session->pid == pid)
1200             {
1201                 ret = session;
1202                 break;
1203             }
1204         }
1205         /* Not found */
1206         if (!ret)
1207             ret = open_login1_session (connection, parameters);
1208
1209         g_dbus_method_invocation_return_value (invocation,
1210                                                g_variant_new("(o)", ret->path));
1211
1212     }
1213     else if (strcmp (method_name, "CanReboot") == 0)
1214     {
1215         check_status ("LOGIN1 CAN-REBOOT");
1216         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1217     }
1218     else if (strcmp (method_name, "Reboot") == 0)
1219     {
1220         gboolean interactive;
1221         g_variant_get (parameters, "(b)", &interactive);
1222         check_status ("LOGIN1 REBOOT");
1223         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1224     }
1225     else if (strcmp (method_name, "CanPowerOff") == 0)
1226     {
1227         check_status ("LOGIN1 CAN-POWER-OFF");
1228         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1229     }
1230     else if (strcmp (method_name, "Suspend") == 0)
1231     {
1232         gboolean interactive;
1233         g_variant_get (parameters, "(b)", &interactive);
1234         check_status ("LOGIN1 SUSPEND");
1235         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1236     }
1237     else if (strcmp (method_name, "CanSuspend") == 0)
1238     {
1239         check_status ("LOGIN1 CAN-SUSPEND");
1240         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1241     }
1242     else if (strcmp (method_name, "PowerOff") == 0)
1243     {
1244         gboolean interactive;
1245         g_variant_get (parameters, "(b)", &interactive);
1246         check_status ("LOGIN1 POWER-OFF");
1247         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1248     }
1249     else if (strcmp (method_name, "CanHibernate") == 0)
1250     {
1251         check_status ("LOGIN1 CAN-HIBERNATE");
1252         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1253     }
1254     else if (strcmp (method_name, "Hibernate") == 0)
1255     {
1256         gboolean interactive;
1257         g_variant_get (parameters, "(b)", &interactive);
1258         check_status ("LOGIN1 HIBERNATE");
1259         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1260     }
1261     else
1262         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1263 }
1264
1265 static void
1266 login1_name_acquired_cb (GDBusConnection *connection,
1267                          const gchar     *name,
1268                          gpointer         user_data)
1269 {
1270     const gchar *login1_interface =
1271         "<node>"
1272         "  <interface name='org.freedesktop.login1.Manager'>"
1273         "    <method name='GetSessionByPID'>"
1274         "      <arg name='pid' type='u' direction='in'/>"
1275         "      <arg name='session' type='o' direction='out'/>"
1276         "    </method>"
1277         "    <method name='CanReboot'>"
1278         "      <arg name='result' direction='out' type='s'/>"
1279         "    </method>"
1280         "    <method name='Reboot'>"
1281         "      <arg name='interactive' direction='in' type='b'/>"
1282         "    </method>"
1283         "    <method name='CanPowerOff'>"
1284         "      <arg name='result' direction='out' type='s'/>"
1285         "    </method>"
1286         "    <method name='PowerOff'>"
1287         "      <arg name='interactive' direction='in' type='b'/>"
1288         "    </method>"
1289         "    <method name='CanSuspend'>"
1290         "      <arg name='result' direction='out' type='s'/>"
1291         "    </method>"
1292         "    <method name='Suspend'>"
1293         "      <arg name='interactive' direction='in' type='b'/>"
1294         "    </method>"
1295         "    <method name='CanHibernate'>"
1296         "      <arg name='result' direction='out' type='s'/>"
1297         "    </method>"
1298         "    <method name='Hibernate'>"
1299         "      <arg name='interactive' direction='in' type='b'/>"
1300         "    </method>"
1301         "  </interface>"
1302         "</node>";
1303     static const GDBusInterfaceVTable login1_vtable =
1304     {
1305         handle_login1_call,
1306     };
1307     GDBusNodeInfo *login1_info;
1308     GError *error = NULL;
1309
1310     login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1311     if (error)
1312         g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1313     g_clear_error (&error);
1314     if (!login1_info)
1315         return;
1316     g_dbus_connection_register_object (connection,
1317                                        "/org/freedesktop/login1",
1318                                        login1_info->interfaces[0],
1319                                        &login1_vtable,
1320                                        NULL, NULL,
1321                                        &error);
1322     if (error)
1323         g_warning ("Failed to register login1 service: %s", error->message);
1324     g_clear_error (&error);
1325     g_dbus_node_info_unref (login1_info);
1326
1327     service_count--;
1328     if (service_count == 0)
1329         run_lightdm ();
1330 }
1331
1332 static void
1333 start_login1_daemon (void)
1334 {
1335     service_count++;
1336     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1337                     "org.freedesktop.login1",
1338                     G_BUS_NAME_OWNER_FLAGS_NONE,
1339                     login1_name_acquired_cb,
1340                     NULL,
1341                     NULL,
1342                     NULL,
1343                     NULL);
1344 }
1345
1346 static AccountsUser *
1347 get_accounts_user_by_uid (guint uid)
1348 {
1349     GList *link;
1350
1351     for (link = accounts_users; link; link = link->next)
1352     {
1353         AccountsUser *u = link->data;
1354         if (u->uid == uid)
1355             return u;
1356     }
1357   
1358     return NULL;
1359 }
1360
1361 static AccountsUser *
1362 get_accounts_user_by_name (const gchar *username)
1363 {
1364     GList *link;
1365
1366     for (link = accounts_users; link; link = link->next)
1367     {
1368         AccountsUser *u = link->data;
1369         if (strcmp (u->user_name, username) == 0)
1370             return u;
1371     }
1372
1373     return NULL;
1374 }
1375
1376 static void
1377 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1378 {
1379     GError *error = NULL;
1380
1381     user->hidden = hidden;
1382
1383     if (user->hidden && user->id != 0)
1384     {
1385         g_dbus_connection_unregister_object (accounts_connection, user->id);
1386         g_dbus_connection_emit_signal (accounts_connection,
1387                                        NULL,
1388                                        "/org/freedesktop/Accounts",
1389                                        "org.freedesktop.Accounts",
1390                                        "UserDeleted",
1391                                        g_variant_new ("(o)", user->path),
1392                                        &error);
1393         if (error)
1394             g_warning ("Failed to emit UserDeleted: %s", error->message);
1395         g_clear_error (&error);
1396
1397         user->id = 0;
1398     }
1399     if (!user->hidden && user->id == 0)
1400     {
1401         user->id = g_dbus_connection_register_object (accounts_connection,
1402                                                       user->path,
1403                                                       user_info->interfaces[0],
1404                                                       &user_vtable,
1405                                                       user,
1406                                                       NULL,
1407                                                       &error);
1408         if (error)
1409             g_warning ("Failed to register user: %s", error->message);
1410         g_clear_error (&error);
1411
1412         g_dbus_connection_emit_signal (accounts_connection,
1413                                        NULL,
1414                                        "/org/freedesktop/Accounts",
1415                                        "org.freedesktop.Accounts",
1416                                        "UserAdded",
1417                                        g_variant_new ("(o)", user->path),
1418                                        &error);
1419         if (error)
1420             g_warning ("Failed to emit UserAdded: %s", error->message);
1421         g_clear_error (&error);
1422     }
1423 }
1424
1425 static void
1426 load_passwd_file (void)
1427 {
1428     gchar *path, *data, **lines;
1429     gchar **user_filter = NULL;
1430     int i;
1431
1432     if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
1433     {
1434         gchar *filter;
1435
1436         filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
1437         user_filter = g_strsplit (filter, " ", -1);
1438         g_free (filter);
1439     }
1440
1441     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
1442     g_file_get_contents (path, &data, NULL, NULL);
1443     g_free (path);
1444     lines = g_strsplit (data, "\n", -1);
1445     g_free (data);
1446
1447     for (i = 0; lines[i]; i++)
1448     {
1449         gchar **fields;
1450         guint uid;
1451         gchar *user_name, *real_name;
1452         AccountsUser *user = NULL;
1453
1454         fields = g_strsplit (lines[i], ":", -1);
1455         if (fields == NULL || g_strv_length (fields) < 7)
1456         {
1457             g_strfreev (fields);
1458             continue;
1459         }
1460
1461         user_name = fields[0];
1462         uid = atoi (fields[2]);
1463         real_name = fields[4];
1464
1465         user = get_accounts_user_by_uid (uid);
1466         if (!user)
1467         {
1468             gchar *path;
1469             GKeyFile *dmrc_file;
1470
1471             user = g_malloc0 (sizeof (AccountsUser));
1472             accounts_users = g_list_append (accounts_users, user);
1473
1474             /* Only allow users in whitelist */
1475             user->hidden = FALSE;
1476             if (user_filter)
1477             {
1478                 int j;
1479
1480                 user->hidden = TRUE;
1481                 for (j = 0; user_filter[j] != NULL; j++)
1482                     if (strcmp (user_name, user_filter[j]) == 0)
1483                         user->hidden = FALSE;
1484             }
1485
1486             dmrc_file = g_key_file_new ();
1487             path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
1488             g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
1489             g_free (path);
1490
1491             user->uid = uid;
1492             user->user_name = g_strdup (user_name);
1493             user->real_name = g_strdup (real_name);
1494             user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
1495             user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
1496             /* DMRC contains a locale, strip the codeset off it to get the language */
1497             if (user->language)
1498             {
1499                 gchar *c = strchr (user->language, '.');
1500                 if (c)
1501                     *c = '\0';
1502             }
1503             user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
1504             user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
1505             user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
1506             accounts_user_set_hidden (user, user->hidden, FALSE);
1507
1508             g_key_file_free (dmrc_file);
1509         }
1510
1511         g_strfreev (fields);
1512     }
1513
1514     g_strfreev (lines);
1515 }
1516
1517 static void
1518 handle_accounts_call (GDBusConnection       *connection,
1519                       const gchar           *sender,
1520                       const gchar           *object_path,
1521                       const gchar           *interface_name,
1522                       const gchar           *method_name,
1523                       GVariant              *parameters,
1524                       GDBusMethodInvocation *invocation,
1525                       gpointer               user_data)
1526 {
1527     if (strcmp (method_name, "ListCachedUsers") == 0)
1528     {
1529         GVariantBuilder builder;
1530         GList *link;
1531
1532         g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
1533
1534         load_passwd_file ();
1535         for (link = accounts_users; link; link = link->next)
1536         {
1537             AccountsUser *user = link->data;
1538             if (!user->hidden)
1539                 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
1540         }
1541
1542         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
1543     }
1544     else if (strcmp (method_name, "FindUserByName") == 0)
1545     {
1546         AccountsUser *user = NULL;
1547         gchar *user_name;
1548
1549         g_variant_get (parameters, "(&s)", &user_name);
1550
1551         load_passwd_file ();
1552         user = get_accounts_user_by_name (user_name);
1553         if (user && !user->hidden)
1554             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
1555         else
1556             g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
1557     }
1558     else
1559         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1560 }
1561
1562 static void
1563 handle_user_call (GDBusConnection       *connection,
1564                   const gchar           *sender,
1565                   const gchar           *object_path,
1566                   const gchar           *interface_name,
1567                   const gchar           *method_name,
1568                   GVariant              *parameters,
1569                   GDBusMethodInvocation *invocation,
1570                   gpointer               user_data)
1571 {
1572     AccountsUser *user = user_data;
1573
1574     if (strcmp (method_name, "SetXSession") == 0)
1575     {
1576         gchar *xsession;
1577
1578         g_variant_get (parameters, "(&s)", &xsession);
1579
1580         g_free (user->xsession);
1581         user->xsession = g_strdup (xsession);
1582
1583         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1584     }
1585     else
1586         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1587 }
1588
1589 static GVariant *
1590 handle_user_get_property (GDBusConnection       *connection,
1591                           const gchar           *sender,
1592                           const gchar           *object_path,
1593                           const gchar           *interface_name,
1594                           const gchar           *property_name,
1595                           GError               **error,
1596                           gpointer               user_data)
1597 {
1598     AccountsUser *user = user_data;
1599
1600     if (strcmp (property_name, "UserName") == 0)
1601         return g_variant_new_string (user->user_name);
1602     else if (strcmp (property_name, "RealName") == 0)
1603         return g_variant_new_string (user->real_name);
1604     else if (strcmp (property_name, "HomeDirectory") == 0)
1605         return g_variant_new_string (user->home_directory);
1606     else if (strcmp (property_name, "BackgroundFile") == 0)
1607         return g_variant_new_string ("");
1608     else if (strcmp (property_name, "Language") == 0)
1609         return g_variant_new_string (user->language ? user->language : "");
1610     else if (strcmp (property_name, "XSession") == 0)
1611         return g_variant_new_string (user->xsession ? user->xsession : "");
1612     else if (strcmp (property_name, "XKeyboardLayouts") == 0)
1613     {
1614         if (user->layouts != NULL)
1615             return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
1616         else
1617             return g_variant_new_strv (NULL, 0);
1618     }
1619     else if (strcmp (property_name, "XHasMessages") == 0)
1620         return g_variant_new_boolean (FALSE);
1621
1622     return NULL;
1623 }
1624
1625 static void
1626 accounts_name_acquired_cb (GDBusConnection *connection,
1627                            const gchar     *name,
1628                            gpointer         user_data)
1629 {
1630     const gchar *accounts_interface =
1631         "<node>"
1632         "  <interface name='org.freedesktop.Accounts'>"
1633         "    <method name='ListCachedUsers'>"
1634         "      <arg name='user' direction='out' type='ao'/>"
1635         "    </method>"
1636         "    <method name='FindUserByName'>"
1637         "      <arg name='name' direction='in' type='s'/>"
1638         "      <arg name='user' direction='out' type='o'/>"
1639         "    </method>"
1640         "    <signal name='UserAdded'>"
1641         "      <arg name='user' type='o'/>"
1642         "    </signal>"
1643         "    <signal name='UserDeleted'>"
1644         "      <arg name='user' type='o'/>"
1645         "    </signal>"
1646         "  </interface>"
1647         "</node>";
1648     static const GDBusInterfaceVTable accounts_vtable =
1649     {
1650         handle_accounts_call,
1651     };
1652     const gchar *user_interface =
1653         "<node>"
1654         "  <interface name='org.freedesktop.Accounts.User'>"
1655         "    <method name='SetXSession'>"
1656         "      <arg name='x_session' direction='in' type='s'/>"
1657         "    </method>"
1658         "    <property name='UserName' type='s' access='read'/>"
1659         "    <property name='RealName' type='s' access='read'/>"
1660         "    <property name='HomeDirectory' type='s' access='read'/>"
1661         "    <property name='BackgroundFile' type='s' access='read'/>"
1662         "    <property name='Language' type='s' access='read'/>"
1663         "    <property name='XSession' type='s' access='read'/>"
1664         "    <property name='XKeyboardLayouts' type='as' access='read'/>"
1665         "    <property name='XHasMessages' type='b' access='read'/>"
1666         "  </interface>"
1667         "</node>";
1668     GError *error = NULL;
1669
1670     accounts_connection = connection;
1671
1672     accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
1673     if (error)
1674         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1675     g_clear_error (&error);
1676     if (!accounts_info)
1677         return;
1678     user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
1679     if (error)
1680         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1681     g_clear_error (&error);
1682     if (!user_info)
1683         return;
1684     g_dbus_connection_register_object (connection,
1685                                        "/org/freedesktop/Accounts",
1686                                        accounts_info->interfaces[0],
1687                                        &accounts_vtable,
1688                                        NULL,
1689                                        NULL,
1690                                        &error);
1691     if (error)
1692         g_warning ("Failed to register accounts service: %s", error->message);
1693     g_clear_error (&error);
1694     g_dbus_node_info_unref (accounts_info);
1695
1696     service_count--;
1697     if (service_count == 0)
1698         run_lightdm ();
1699 }
1700
1701 static void
1702 start_accounts_service_daemon (void)
1703 {
1704     service_count++;
1705     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1706                     "org.freedesktop.Accounts",
1707                     G_BUS_NAME_OWNER_FLAGS_NONE,
1708                     accounts_name_acquired_cb,
1709                     NULL,
1710                     NULL,
1711                     NULL,
1712                     NULL);
1713 }
1714
1715 static void
1716 run_lightdm (void)
1717 {
1718     GString *command_line;
1719     gchar **lightdm_argv;
1720     pid_t lightdm_pid;
1721     GError *error = NULL;
1722
1723     run_commands ();
1724
1725     status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
1726
1727     command_line = g_string_new ("lightdm");
1728     if (getenv ("DEBUG"))
1729         g_string_append (command_line, " --debug");
1730     g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
1731
1732     test_runner_command = g_strdup_printf ("PATH=%s LD_PRELOAD=%s LD_LIBRARY_PATH=%s LIGHTDM_TEST_ROOT=%s DBUS_SESSION_BUS_ADDRESS=%s %s\n",
1733                                            g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
1734                                            command_line->str);
1735
1736     if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
1737     {
1738         g_warning ("Error parsing command line: %s", error->message);
1739         quit (EXIT_FAILURE);
1740     }
1741     g_clear_error (&error);
1742
1743     if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
1744     {
1745         g_warning ("Error launching LightDM: %s", error->message);
1746         quit (EXIT_FAILURE);
1747     }
1748     g_clear_error (&error);
1749     lightdm_process = watch_process (lightdm_pid);
1750
1751     check_status ("RUNNER DAEMON-START");
1752 }
1753
1754 static gboolean
1755 signal_cb (gpointer user_data)
1756 {
1757     g_print ("Caught signal, quitting\n");
1758     quit (EXIT_FAILURE);
1759     return FALSE;
1760 }
1761
1762 int
1763 main (int argc, char **argv)
1764 {
1765     GMainLoop *loop;
1766     int i;
1767     gchar *greeter = NULL, *script_name, *config_file, *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
1768     GString *passwd_data, *group_data;
1769     GSource *status_source;
1770     gchar cwd[1024];
1771     GError *error = NULL;
1772
1773 #if !defined(GLIB_VERSION_2_36)
1774     g_type_init ();
1775 #endif
1776
1777     loop = g_main_loop_new (NULL, FALSE);
1778
1779     g_unix_signal_add (SIGINT, signal_cb, NULL);
1780     g_unix_signal_add (SIGTERM, signal_cb, NULL);
1781
1782     children = g_hash_table_new (g_direct_hash, g_direct_equal);
1783
1784     if (argc != 3)
1785     {
1786         g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
1787         quit (EXIT_FAILURE);
1788     }
1789     script_name = argv[1];
1790     config_file = g_strdup_printf ("%s.conf", script_name);
1791     config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
1792     g_free (config_file);
1793
1794     config = g_key_file_new ();
1795     g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
1796
1797     load_script (config_path);
1798
1799     if (!getcwd (cwd, 1024))
1800     {
1801         g_critical ("Error getting current directory: %s", strerror (errno));
1802         quit (EXIT_FAILURE);
1803     }
1804
1805     /* Don't contact our X server */
1806     g_unsetenv ("DISPLAY");
1807
1808     /* Override system calls */
1809     ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
1810     g_setenv ("LD_PRELOAD", ld_preload, TRUE);
1811     g_free (ld_preload);
1812
1813     /* Run test programs */
1814     path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
1815     g_setenv ("PATH", path, TRUE);
1816     g_free (path);
1817
1818     /* Use locally built libraries */
1819     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
1820     path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
1821     ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
1822     g_free (path1);
1823     g_free (path2);
1824     g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
1825     g_free (ld_library_path);
1826     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
1827     g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
1828     g_free (path1);
1829
1830     /* Run in a temporary directory inside the build directory */
1831     /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
1832     i = 0;
1833     while (TRUE) {
1834         gchar *name;
1835
1836         name = g_strdup_printf (".r%d", i);
1837         g_free (temp_dir);
1838         temp_dir = g_build_filename ("/tmp", name, NULL);
1839         g_free (name);
1840         if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
1841             break;
1842         i++;
1843     }  
1844     g_mkdir_with_parents (temp_dir, 0755);
1845     g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
1846
1847     /* Open socket for status */
1848     /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
1849     status_socket_name = g_build_filename (temp_dir, ".s", NULL);
1850     unlink (status_socket_name);
1851     status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1852     if (error)
1853         g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
1854     g_clear_error (&error);
1855     if (status_socket)
1856     {
1857         GSocketAddress *address;
1858         gboolean result;
1859
1860         address = g_unix_socket_address_new (status_socket_name);
1861         result = g_socket_bind (status_socket, address, FALSE, &error);
1862         g_object_unref (address);
1863         if (error)
1864             g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
1865         g_clear_error (&error);
1866         if (result)
1867         {
1868             result = g_socket_listen (status_socket, &error);
1869             if (error)
1870                 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
1871             g_clear_error (&error);
1872         }
1873         if (!result)
1874         {
1875             g_object_unref (status_socket);
1876             status_socket = NULL;
1877         }
1878     }
1879     if (!status_socket)
1880         quit (EXIT_FAILURE);
1881     status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
1882     g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
1883     g_source_attach (status_source, NULL);
1884
1885     /* Set up a skeleton file system */
1886     g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
1887     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
1888     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
1889     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
1890     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
1891     g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
1892     g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
1893     g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
1894
1895     /* Copy over the configuration */
1896     g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
1897     if (!g_key_file_has_key (config, "test-runner-config", "have-config", NULL) || g_key_file_get_boolean (config, "test-runner-config", "have-config", NULL))
1898         if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
1899             perror ("Failed to copy configuration");
1900
1901     additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
1902     if (additional_config)
1903     {
1904         gchar **files;
1905
1906         g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm/lightdm.conf.d", temp_dir), 0755);
1907
1908         files = g_strsplit (additional_config, " ", -1);
1909         for (i = 0; files[i]; i++)
1910             if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
1911                 perror ("Failed to copy configuration");
1912         g_strfreev (files);
1913     }
1914
1915     /* Always copy the script */
1916     if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
1917         perror ("Failed to copy configuration");
1918
1919     /* Copy over the greeter files */
1920     if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
1921         perror ("Failed to copy sessions");
1922     if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
1923         perror ("Failed to copy remote sessions");
1924     if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
1925         perror ("Failed to copy greeters");
1926
1927     /* Set up the default greeter */
1928     path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
1929     greeter = g_strdup_printf ("%s.desktop", argv[2]);
1930     if (symlink (greeter, path) < 0)
1931     {
1932         g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
1933         quit (EXIT_FAILURE);
1934     }
1935     g_free (path);
1936     g_free (greeter);
1937
1938     home_dir = g_build_filename (temp_dir, "home", NULL);
1939
1940     /* Make fake users */
1941     struct
1942     {
1943         gchar *user_name;
1944         gchar *password;
1945         gboolean have_home_dir;
1946         gchar *real_name;
1947         gchar *xsession;
1948         gchar *dmrc_layout;
1949         gchar *dbus_layouts;
1950         gchar *language;
1951         gint uid;
1952     } users[] =
1953     {
1954         /* Root account */
1955         {"root",             "",         TRUE,  "root",               NULL,  NULL, NULL,          NULL,             0},
1956         /* Unprivileged account for greeters */
1957         {"lightdm",          "",         TRUE,  "",                   NULL,  NULL, NULL,          NULL,           100},
1958         /* These accounts have a password */
1959         {"have-password1",   "password", TRUE,  "Password User 1",    NULL,  NULL, NULL,          NULL,          1000},
1960         {"have-password2",   "password", TRUE,  "Password User 2",    NULL,  NULL, NULL,          NULL,          1001},
1961         {"have-password3",   "password", TRUE,  "Password User 3",    NULL,  NULL, NULL,          NULL,          1002},
1962         {"have-password4",   "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1003},
1963         /* This account always prompts for a password, even if using the lightdm-autologin service */
1964         {"always-password",  "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1004},
1965         /* These accounts have no password */
1966         {"no-password1",     "",         TRUE,  "No Password User 1", NULL,  NULL, NULL,          NULL,          1005},
1967         {"no-password2",     "",         TRUE,  "No Password User 2", NULL,  NULL, NULL,          NULL,          1006},
1968         {"no-password3",     "",         TRUE,  "No Password User 3", NULL,  NULL, NULL,          NULL,          1007},
1969         {"no-password4",     "",         TRUE,  "No Password User 4", NULL,  NULL, NULL,          NULL,          1008},
1970         /* This account has a keyboard layout */
1971         {"have-layout",      "",         TRUE,  "Layout User",        NULL,  "us", NULL,          NULL,          1009},
1972         /* This account has a set of keyboard layouts */
1973         {"have-layouts",     "",         TRUE,  "Layouts User",       NULL,  "ru", "fr\toss;ru;", NULL,          1010},
1974         /* This account has a language set */
1975         {"have-language",    "",         TRUE,  "Language User",      NULL,  NULL, NULL,          "en_AU.utf8",  1011},
1976         /* This account has a preconfigured session */
1977         {"have-session",            "",  TRUE,  "Session User", "alternative", NULL, NULL,        NULL,          1012},
1978         /* This account has the home directory mounted on login */
1979         {"mount-home-dir",   "",         FALSE, "Mounted Home Dir User", NULL, NULL, NULL,        NULL,          1013},
1980         /* This account is denied access */
1981         {"denied",           "",         TRUE,  "Denied User",        NULL,  NULL, NULL,          NULL,          1014},
1982         /* This account has expired */
1983         {"expired",          "",         TRUE,  "Expired User",       NULL,  NULL, NULL,          NULL,          1015},
1984         /* This account needs a password change */
1985         {"new-authtok",      "",         TRUE,  "New Token User",     NULL,  NULL, NULL,          NULL,          1016},
1986         /* This account is switched to change-user2 when authentication succeeds */
1987         {"change-user1",     "",         TRUE,  "Change User 1",      NULL,  NULL, NULL,          NULL,          1017},
1988         {"change-user2",     "",         TRUE,  "Change User 2",      NULL,  NULL, NULL,          NULL,          1018},
1989         /* This account switches to invalid-user when authentication succeeds */
1990         {"change-user-invalid", "",      TRUE,  "Invalid Change User",NULL,  NULL, NULL,          NULL,          1019},
1991         /* This account crashes on authentication */
1992         {"crash-authenticate", "",       TRUE,  "Crash Auth User",    NULL,  NULL, NULL,          NULL,          1020},
1993         /* This account shows an informational prompt on login */
1994         {"info-prompt",      "password", TRUE,  "Info Prompt",        NULL,  NULL, NULL,          NULL,          1021},
1995         /* This account shows multiple informational prompts on login */
1996         {"multi-info-prompt","password", TRUE,  "Multi Info Prompt",  NULL,  NULL, NULL,          NULL,          1022},
1997         /* This account uses two factor authentication */
1998         {"two-factor",       "password", TRUE,  "Two Factor",         NULL,  NULL, NULL,          NULL,          1023},
1999         /* This account has a special group */
2000         {"group-member",     "password", TRUE,  "Group Member",       NULL,  NULL, NULL,          NULL,          1024},
2001         /* This account has the home directory created when the session starts */
2002         {"make-home-dir",    "",         FALSE, "Make Home Dir User", NULL,  NULL, NULL,          NULL,          1025},
2003         /* This account fails to open a session */
2004         {"session-error",    "password", TRUE,  "Session Error",      NULL,  NULL, NULL,          NULL,          1026},
2005         /* This account can't establish credentials */
2006         {"cred-error",       "password", TRUE,  "Cred Error",         NULL,  NULL, NULL,          NULL,          1027},
2007         /* This account has expired credentials */
2008         {"cred-expired",     "password", TRUE,  "Cred Expired",       NULL,  NULL, NULL,          NULL,          1028},
2009         /* This account has cannot access their credentials */
2010         {"cred-unavail",     "password", TRUE,  "Cred Unavail",       NULL,  NULL, NULL,          NULL,          1029},
2011         /* This account sends informational messages for each PAM function that is called */
2012         {"log-pam",          "password", TRUE,  "Log PAM",            NULL,  NULL, NULL,          NULL,          1030},
2013         /* This account shows multiple prompts on login */
2014         {"multi-prompt",     "password", TRUE,  "Multi Prompt",       NULL,  NULL, NULL,          NULL,          1031},
2015         {NULL,               NULL,       FALSE, NULL,                 NULL,  NULL, NULL,          NULL,             0}
2016     };
2017     passwd_data = g_string_new ("");
2018     group_data = g_string_new ("");
2019     for (i = 0; users[i].user_name; i++)
2020     {
2021         GKeyFile *dmrc_file;
2022         gboolean save_dmrc = FALSE;
2023
2024         if (users[i].have_home_dir)
2025         {
2026             path = g_build_filename (home_dir, users[i].user_name, NULL);
2027             g_mkdir_with_parents (path, 0755);
2028             if (chown (path, users[i].uid, users[i].uid) < 0)
2029               g_debug ("chown (%s) failed: %s", path, strerror (errno));
2030             g_free (path);
2031         }
2032
2033         dmrc_file = g_key_file_new ();
2034         if (users[i].xsession)
2035         {
2036             g_key_file_set_string (dmrc_file, "Desktop", "Session", users[i].xsession);
2037             save_dmrc = TRUE;
2038         }
2039         if (users[i].dmrc_layout)
2040         {
2041             g_key_file_set_string (dmrc_file, "Desktop", "Layout", users[i].dmrc_layout);
2042             save_dmrc = TRUE;
2043         }
2044         if (users[i].dbus_layouts)
2045         {
2046             g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", users[i].dbus_layouts);
2047             save_dmrc = TRUE;
2048
2049         }
2050         if (users[i].language)
2051         {
2052             g_key_file_set_string (dmrc_file, "Desktop", "Language", users[i].language);
2053             save_dmrc = TRUE;
2054         }
2055
2056         if (save_dmrc)
2057         {
2058             gchar *data;
2059
2060             path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2061             data = g_key_file_to_data (dmrc_file, NULL, NULL);
2062             g_file_set_contents (path, data, -1, NULL);
2063             g_free (data);
2064             g_free (path);
2065         }
2066
2067         g_key_file_free (dmrc_file);
2068
2069         /* Add passwd file entry */
2070         g_string_append_printf (passwd_data, "%s:%s:%d:%d:%s:%s/home/%s:/bin/sh\n", users[i].user_name, users[i].password, users[i].uid, users[i].uid, users[i].real_name, temp_dir, users[i].user_name);
2071
2072         /* Add group file entry */
2073         g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2074     }
2075     path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2076     g_file_set_contents (path, passwd_data->str, -1, NULL);
2077     g_free (path);
2078     g_string_free (passwd_data, TRUE);
2079
2080     /* Add an extra test group */
2081     g_string_append_printf (group_data, "test-group:x:111:\n");
2082
2083     path = g_build_filename (temp_dir, "etc", "group", NULL);
2084     g_file_set_contents (path, group_data->str, -1, NULL);
2085     g_free (path);
2086     g_string_free (group_data, TRUE);
2087
2088     if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2089         status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2090
2091     /* Start D-Bus services */
2092     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2093         start_upower_daemon ();
2094     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2095         start_console_kit_daemon ();
2096     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2097         start_login1_daemon ();
2098     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2099         start_accounts_service_daemon ();
2100
2101     g_main_loop_run (loop);
2102
2103     return EXIT_FAILURE;
2104 }