diff options
author | Robert Ancell <robert.ancell@canonical.com> | 2012-03-20 16:11:28 +1100 |
---|---|---|
committer | Robert Ancell <robert.ancell@canonical.com> | 2012-03-20 16:11:28 +1100 |
commit | 89a42458fad356f36742b09e04be686092e698dd (patch) | |
tree | 5d05625c6ae79784ce51bab9b2d553ef599e0c60 /tests | |
parent | f8841d64f28da418060092a8e181e0693906b23e (diff) | |
download | lightdm-89a42458fad356f36742b09e04be686092e698dd.tar.gz |
Call initgroups before pam_setcred - this allows pam_setcred to change group membership correctly
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/scripts/group-membership.conf | 34 | ||||
-rw-r--r-- | tests/src/X.c | 11 | ||||
-rw-r--r-- | tests/src/guest-account.c | 18 | ||||
-rw-r--r-- | tests/src/libsystem.c | 183 | ||||
-rw-r--r-- | tests/src/test-runner.c | 28 | ||||
-rw-r--r-- | tests/src/test-session.c | 29 | ||||
-rwxr-xr-x | tests/test-group-membership | 2 |
8 files changed, 281 insertions, 26 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index 1912ff68..a26996e8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,6 +22,7 @@ TESTS = \ test-autologin-guest \ test-autologin-guest-fail-setup-script \ test-autologin-guest-logout \ + test-group-membership \ test-session-stdout \ test-session-stderr \ test-xauthority \ @@ -158,6 +159,7 @@ EXTRA_DIST = \ scripts/greeter-fail-start.conf \ scripts/greeter-not-installed.conf \ scripts/greeter-xserver-crash.conf \ + scripts/group-membership.conf \ scripts/headless.conf \ scripts/home-dir-on-authenticate.conf \ scripts/keyboard-layout.conf \ diff --git a/tests/scripts/group-membership.conf b/tests/scripts/group-membership.conf new file mode 100644 index 00000000..70f5afd3 --- /dev/null +++ b/tests/scripts/group-membership.conf @@ -0,0 +1,34 @@ +# +# Check group membership is correctly set up +# + +[LightDM] +minimum-display-number=50 + +[SeatDefaults] +autologin-user=group-member + +#?RUNNER DAEMON-START + +# X server starts +#?XSERVER :50 START +#?XSERVER :50 INDICATE-READY + +# LightDM connects to X server +#?XSERVER :50 ACCEPT-CONNECT + +# Session starts +#?SESSION :50 START USER=group-member +#?XSERVER :50 ACCEPT-CONNECT +#?SESSION :50 CONNECT-XSERVER + +# Check we belong to the group for our user and the special group set by PAM +#?*SESSION :50 LIST-GROUPS +#?SESSION :50 LIST-GROUPS GROUPS=group-member,test-group + +# Cleanup +#?*STOP-DAEMON +# Don't know what order they will terminate +#?(SESSION :50 TERMINATE SIGNAL=15|XSERVER :50 TERMINATE SIGNAL=15) +#?(SESSION :50 TERMINATE SIGNAL=15|XSERVER :50 TERMINATE SIGNAL=15) +#?RUNNER DAEMON-EXIT STATUS=0 diff --git a/tests/src/X.c b/tests/src/X.c index b11ea977..a6d846d6 100644 --- a/tests/src/X.c +++ b/tests/src/X.c @@ -348,21 +348,12 @@ main (int argc, char **argv) if (g_getenv ("LIGHTDM_TEST_CONFIG")) g_key_file_load_from_file (config, g_getenv ("LIGHTDM_TEST_CONFIG"), G_KEY_FILE_NONE, NULL); - return_lock = g_build_filename (g_getenv ("LIGHTDM_TEST_HOME_DIR"), ".xserver-returned", NULL); - f = fopen (return_lock, "r"); - if (f == NULL && g_key_file_has_key (config, "test-xserver-config", "return-value", NULL)) + if (g_key_file_has_key (config, "test-xserver-config", "return-value", NULL)) { int return_value = g_key_file_get_integer (config, "test-xserver-config", "return-value", NULL); status_notify ("XSERVER :%d EXIT CODE=%d", display_number, return_value); - - /* Write lock to stop repeatedly exiting */ - f = fopen (return_lock, "w"); - fclose (f); - return return_value; } - if (f != NULL) - fclose (f); lock_path = g_strdup_printf ("/tmp/.X%d-lock", display_number); lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444); diff --git a/tests/src/guest-account.c b/tests/src/guest-account.c index b736943c..9b851c31 100644 --- a/tests/src/guest-account.c +++ b/tests/src/guest-account.c @@ -17,6 +17,8 @@ request_cb (const gchar *message) int main (int argc, char **argv) { + gchar *passwd_path; + g_type_init (); status_connect (request_cb); @@ -25,6 +27,8 @@ main (int argc, char **argv) if (g_getenv ("LIGHTDM_TEST_CONFIG")) g_key_file_load_from_file (config, g_getenv ("LIGHTDM_TEST_CONFIG"), G_KEY_FILE_NONE, NULL); + passwd_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL); + if (argc == 2 && strcmp (argv[1], "add") == 0) { gchar *home_dir, *username, line[1024]; @@ -32,7 +36,7 @@ main (int argc, char **argv) FILE *passwd; /* Create a unique name */ - home_dir = g_strdup_printf ("%s/guest-XXXXXX", g_getenv ("LIGHTDM_TEST_HOME_DIR")); + home_dir = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "home", "guest-XXXXXX", NULL); if (!mkdtemp (home_dir)) { g_printerr ("Failed to create home directory %s: %s\n", home_dir, strerror (errno)); @@ -41,7 +45,7 @@ main (int argc, char **argv) username = strrchr (home_dir, '/') + 1; /* Get the largest UID */ - passwd = fopen (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), "r"); + passwd = fopen (passwd_path, "r"); if (passwd) { while (fgets (line, 1024, passwd)) @@ -59,7 +63,7 @@ main (int argc, char **argv) } /* Add a new account to the passwd file */ - passwd = fopen (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), "a"); + passwd = fopen (passwd_path, "a"); fprintf (passwd, "%s::%d:%d:Guest Account:%s:/bin/sh\n", username, max_uid+1, max_uid+1, home_dir); fclose (passwd); @@ -80,8 +84,8 @@ main (int argc, char **argv) status_notify ("GUEST-ACCOUNT REMOVE USERNAME=%s", username); /* Open a new file for writing */ - passwd = fopen (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), "r"); - path = g_strdup_printf ("%s~", g_getenv ("LIGHTDM_TEST_PASSWD_FILE")); + passwd = fopen (passwd_path, "r"); + path = g_strdup_printf ("%s~", passwd_path); new_passwd = fopen (path, "w"); /* Copy the old file, omitting our entry */ @@ -95,10 +99,10 @@ main (int argc, char **argv) fclose (new_passwd); /* Move the new file on the old one */ - rename (path, g_getenv ("LIGHTDM_TEST_PASSWD_FILE")); + rename (path, passwd_path); /* Delete home directory */ - gchar *command = g_strdup_printf ("rm -r %s/%s", g_getenv ("LIGHTDM_TEST_HOME_DIR"), username); + gchar *command = g_strdup_printf ("rm -r %s/home/%s", g_getenv ("LIGHTDM_TEST_ROOT"), username); if (system (command)) perror ("Failed to delete temp directory"); diff --git a/tests/src/libsystem.c b/tests/src/libsystem.c index ca3cd66d..184f8a66 100644 --- a/tests/src/libsystem.c +++ b/tests/src/libsystem.c @@ -1,7 +1,9 @@ #include <stdlib.h> #include <string.h> +#include <errno.h> #include <sys/types.h> #include <pwd.h> +#include <grp.h> #include <security/pam_appl.h> #include <unistd.h> #include <fcntl.h> @@ -19,6 +21,8 @@ static int console_fd = -1; static GList *user_entries = NULL; static GList *getpwent_link = NULL; +static GList *group_entries = NULL; + struct pam_handle { char *service_name; @@ -43,6 +47,61 @@ geteuid (void) int initgroups (const char *user, gid_t group) { + gid_t g[1]; + + g[0] = group; + setgroups (1, g); + + return 0; +} + +int +getgroups (int size, gid_t list[]) +{ + const gchar *group_list; + gchar **groups; + gint groups_length; + + /* Get groups we are a member of */ + group_list = g_getenv ("LIGHTDM_TEST_GROUPS"); + if (!group_list) + group_list = ""; + groups = g_strsplit (group_list, ",", -1); + groups_length = g_strv_length (groups); + + if (size != 0) + { + int i; + + if (groups_length > size) + { + errno = EINVAL; + return -1; + } + for (i = 0; groups[i]; i++) + list[i] = atoi (groups[i]); + } + g_free (groups); + + return groups_length; +} + +int +setgroups (size_t size, const gid_t *list) +{ + size_t i; + GString *group_list; + + group_list = g_string_new (""); + for (i = 0; i < size; i++) + { + if (i != 0) + g_string_append (group_list, ","); + g_string_append_printf (group_list, "%d", list[i]); + } + g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE); + g_string_free (group_list, TRUE); + return 0; } @@ -73,7 +132,7 @@ open (const char *pathname, int flags, ...) va_end (ap); } - _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open"); + _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open"); if (strcmp (pathname, "/dev/console") == 0) { if (console_fd < 0) @@ -141,7 +200,7 @@ free_user (gpointer data) static void load_passwd_file () { - gchar *data = NULL, **lines; + gchar *path, *data = NULL, **lines; gint i; GError *error = NULL; @@ -149,7 +208,9 @@ load_passwd_file () user_entries = NULL; getpwent_link = NULL; - g_file_get_contents (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), &data, NULL, &error); + path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL); + g_file_get_contents (path, &data, NULL, &error); + g_free (path); if (error) g_warning ("Error loading passwd file: %s", error->message); g_clear_error (&error); @@ -257,6 +318,99 @@ getpwuid (uid_t uid) return link->data; } +static void +free_group (gpointer data) +{ + struct group *entry = data; + + g_free (entry->gr_name); + g_free (entry->gr_passwd); + g_strfreev (entry->gr_mem); + g_free (entry); +} + +static void +load_group_file () +{ + gchar *path, *data = NULL, **lines; + gint i; + GError *error = NULL; + + g_list_free_full (group_entries, free_group); + group_entries = NULL; + + path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL); + g_file_get_contents (path, &data, NULL, &error); + g_free (path); + if (error) + g_warning ("Error loading group file: %s", error->message); + g_clear_error (&error); + + if (!data) + return; + + lines = g_strsplit (data, "\n", -1); + g_free (data); + + for (i = 0; lines[i]; i++) + { + gchar *line, **fields; + + line = g_strstrip (lines[i]); + fields = g_strsplit (line, ":", -1); + if (g_strv_length (fields) == 4) + { + struct group *entry = malloc (sizeof (struct group)); + + entry->gr_name = g_strdup (fields[0]); + entry->gr_passwd = g_strdup (fields[1]); + entry->gr_gid = atoi (fields[2]); + entry->gr_mem = g_strsplit (fields[3], ",", -1); + group_entries = g_list_append (group_entries, entry); + } + g_strfreev (fields); + } + g_strfreev (lines); +} + +struct group * +getgrnam (const char *name) +{ + GList *link; + + load_group_file (); + + for (link = group_entries; link; link = link->next) + { + struct group *entry = link->data; + if (strcmp (entry->gr_name, name) == 0) + break; + } + if (!link) + return NULL; + + return link->data; +} + +struct group * +getgrgid (gid_t gid) +{ + GList *link; + + load_group_file (); + + for (link = group_entries; link; link = link->next) + { + struct group *entry = link->data; + if (entry->gr_gid == gid) + break; + } + if (!link) + return NULL; + + return link->data; +} + int pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh) { @@ -645,6 +799,29 @@ pam_setcred (pam_handle_t *pamh, int flags) pam_putenv (pamh, e); g_free (e); + /* Join special groups if requested */ + if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED) + { + struct group *group; + gid_t *groups; + int groups_length; + + group = getgrnam ("test-group"); + if (group) + { + groups_length = getgroups (0, NULL); + groups = malloc (sizeof (gid_t) * (groups_length + 1)); + groups_length = getgroups (groups_length, groups); + groups[groups_length] = group->gr_gid; + groups_length++; + setgroups (groups_length, groups); + free (groups); + } + + /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */ + pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS"))); + } + return PAM_SUCCESS; } diff --git a/tests/src/test-runner.c b/tests/src/test-runner.c index 36473349..ee2495bd 100644 --- a/tests/src/test-runner.c +++ b/tests/src/test-runner.c @@ -838,10 +838,12 @@ start_console_kit_daemon () static void load_passwd_file () { - gchar *data, **lines; + gchar *path, *data, **lines; int i; - g_file_get_contents (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), &data, NULL, NULL); + path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL); + g_file_get_contents (path, &data, NULL, NULL); + g_free (path); lines = g_strsplit (data, "\n", -1); g_free (data); @@ -1179,7 +1181,7 @@ main (int argc, char **argv) { GMainLoop *loop; gchar *greeter = NULL, *script_name, *config_file, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir; - GString *passwd_data; + GString *passwd_data, *group_data; GSource *status_source; gchar cwd[1024]; GError *error = NULL; @@ -1288,6 +1290,7 @@ main (int argc, char **argv) quit (EXIT_FAILURE); } g_chmod (temp_dir, 0755); + g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE); /* Set up a skeleton file system */ g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755); @@ -1311,7 +1314,6 @@ main (int argc, char **argv) g_free (greeter); home_dir = g_build_filename (temp_dir, "home", NULL); - g_setenv ("LIGHTDM_TEST_HOME_DIR", home_dir, TRUE); /* Make fake users */ struct @@ -1372,9 +1374,12 @@ main (int argc, char **argv) {"multi-info-prompt","password", TRUE, "Multi Info Prompt", NULL, NULL, NULL, NULL, 1022}, /* This account uses two factor authentication */ {"two-factor", "password", TRUE, "Two Factor", NULL, NULL, NULL, NULL, 1023}, + /* This account has a special group */ + {"group-member", "password", TRUE, "Group Member", NULL, NULL, NULL, NULL, 1024}, {NULL, NULL, FALSE, NULL, NULL, NULL, NULL, NULL, 0} }; passwd_data = g_string_new (""); + group_data = g_string_new (""); int i; for (i = 0; users[i].user_name; i++) { @@ -1425,14 +1430,25 @@ main (int argc, char **argv) g_key_file_free (dmrc_file); + /* Add passwd file entry */ 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); + + /* Add group file entry */ + g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name); } - path = g_build_filename (temp_dir, "passwd", NULL); - g_setenv ("LIGHTDM_TEST_PASSWD_FILE", path, TRUE); + path = g_build_filename (temp_dir, "etc", "passwd", NULL); g_file_set_contents (path, passwd_data->str, -1, NULL); g_free (path); g_string_free (passwd_data, TRUE); + /* Add an extra test group */ + g_string_append_printf (group_data, "test-group:x:111:\n"); + + path = g_build_filename (temp_dir, "etc", "group", NULL); + g_file_set_contents (path, group_data->str, -1, NULL); + g_free (path); + g_string_free (group_data, TRUE); + /* Start D-Bus services */ if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL)) start_console_kit_daemon (); diff --git a/tests/src/test-session.c b/tests/src/test-session.c index 8df53d45..fb42b1e4 100644 --- a/tests/src/test-session.c +++ b/tests/src/test-session.c @@ -5,6 +5,7 @@ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> +#include <grp.h> #include <xcb/xcb.h> #include <glib.h> #include <glib-object.h> @@ -76,6 +77,34 @@ request_cb (const gchar *request) } g_free (r); + r = g_strdup_printf ("SESSION %s LIST-GROUPS", getenv ("DISPLAY")); + if (strcmp (request, r) == 0) + { + int n_groups, i; + gid_t *groups; + GString *group_list; + + n_groups = getgroups (0, NULL); + groups = malloc (sizeof (gid_t) * n_groups); + n_groups = getgroups (n_groups, groups); + group_list = g_string_new (""); + for (i = 0; i < n_groups; i++) + { + struct group *group; + + if (i != 0) + g_string_append (group_list, ","); + group = getgrgid (groups[i]); + if (group) + g_string_append (group_list, group->gr_name); + else + g_string_append_printf (group_list, "%d", groups[i]); + } + status_notify ("SESSION %s LIST-GROUPS GROUPS=%s", getenv ("DISPLAY"), group_list->str); + g_string_free (group_list, TRUE); + free (groups); + } + r = g_strdup_printf ("SESSION %s READ-ENV NAME=", getenv ("DISPLAY")); if (g_str_has_prefix (request, r)) { diff --git a/tests/test-group-membership b/tests/test-group-membership new file mode 100755 index 00000000..a18c48ec --- /dev/null +++ b/tests/test-group-membership @@ -0,0 +1,2 @@ +#!/bin/sh +./src/dbus-env ./src/test-runner group-membership test-gobject-greeter |