~lightdm-team/lightdm/1.2

« back to all changes in this revision

Viewing changes to tests/src/libsystem.c

  • Committer: Robert Ancell
  • Date: 2012-03-20 05:11:28 UTC
  • Revision ID: robert.ancell@canonical.com-20120320051128-3pz5ies6mxx2pdik
Call initgroups before pam_setcred - this allows pam_setcred to change group membership correctly

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#include <stdlib.h>
2
2
#include <string.h>
 
3
#include <errno.h>
3
4
#include <sys/types.h>
4
5
#include <pwd.h>
 
6
#include <grp.h>
5
7
#include <security/pam_appl.h>
6
8
#include <unistd.h>
7
9
#include <fcntl.h>
19
21
static GList *user_entries = NULL;
20
22
static GList *getpwent_link = NULL;
21
23
 
 
24
static GList *group_entries = NULL;
 
25
 
22
26
struct pam_handle
23
27
{
24
28
    char *service_name;
43
47
int
44
48
initgroups (const char *user, gid_t group)
45
49
{
 
50
    gid_t g[1];
 
51
 
 
52
    g[0] = group;
 
53
    setgroups (1, g);
 
54
 
 
55
    return 0;
 
56
}
 
57
 
 
58
int
 
59
getgroups (int size, gid_t list[])
 
60
{
 
61
    const gchar *group_list;
 
62
    gchar **groups;
 
63
    gint groups_length;
 
64
 
 
65
    /* Get groups we are a member of */
 
66
    group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
 
67
    if (!group_list)
 
68
        group_list = "";
 
69
    groups = g_strsplit (group_list, ",", -1);
 
70
    groups_length = g_strv_length (groups);
 
71
 
 
72
    if (size != 0)
 
73
    {
 
74
        int i;
 
75
 
 
76
        if (groups_length > size)
 
77
        {
 
78
            errno = EINVAL;
 
79
            return -1;
 
80
        }
 
81
        for (i = 0; groups[i]; i++)
 
82
            list[i] = atoi (groups[i]);
 
83
    }
 
84
    g_free (groups);
 
85
 
 
86
    return groups_length;
 
87
}
 
88
 
 
89
int
 
90
setgroups (size_t size, const gid_t *list)
 
91
{
 
92
    size_t i;
 
93
    GString *group_list;
 
94
 
 
95
    group_list = g_string_new ("");
 
96
    for (i = 0; i < size; i++)
 
97
    {
 
98
        if (i != 0)
 
99
            g_string_append (group_list, ",");
 
100
        g_string_append_printf (group_list, "%d", list[i]);
 
101
    }
 
102
    g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
 
103
    g_string_free (group_list, TRUE);
 
104
 
46
105
    return 0;
47
106
}
48
107
 
73
132
        va_end (ap);
74
133
    }
75
134
 
76
 
    _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open");      
 
135
    _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open");
77
136
    if (strcmp (pathname, "/dev/console") == 0)
78
137
    {
79
138
        if (console_fd < 0)
141
200
static void
142
201
load_passwd_file ()
143
202
{
144
 
    gchar *data = NULL, **lines;
 
203
    gchar *path, *data = NULL, **lines;
145
204
    gint i;
146
205
    GError *error = NULL;
147
206
 
149
208
    user_entries = NULL;
150
209
    getpwent_link = NULL;
151
210
 
152
 
    g_file_get_contents (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), &data, NULL, &error);
 
211
    path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
 
212
    g_file_get_contents (path, &data, NULL, &error);
 
213
    g_free (path);
153
214
    if (error)
154
215
        g_warning ("Error loading passwd file: %s", error->message);
155
216
    g_clear_error (&error);
257
318
    return link->data;
258
319
}
259
320
 
 
321
static void
 
322
free_group (gpointer data)
 
323
{
 
324
    struct group *entry = data;
 
325
  
 
326
    g_free (entry->gr_name);
 
327
    g_free (entry->gr_passwd);
 
328
    g_strfreev (entry->gr_mem);
 
329
    g_free (entry);
 
330
}
 
331
 
 
332
static void
 
333
load_group_file ()
 
334
{
 
335
    gchar *path, *data = NULL, **lines;
 
336
    gint i;
 
337
    GError *error = NULL;
 
338
 
 
339
    g_list_free_full (group_entries, free_group);
 
340
    group_entries = NULL;
 
341
 
 
342
    path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
 
343
    g_file_get_contents (path, &data, NULL, &error);
 
344
    g_free (path);
 
345
    if (error)
 
346
        g_warning ("Error loading group file: %s", error->message);
 
347
    g_clear_error (&error);
 
348
 
 
349
    if (!data)
 
350
        return;
 
351
 
 
352
    lines = g_strsplit (data, "\n", -1);
 
353
    g_free (data);
 
354
 
 
355
    for (i = 0; lines[i]; i++)
 
356
    {
 
357
        gchar *line, **fields;
 
358
 
 
359
        line = g_strstrip (lines[i]);
 
360
        fields = g_strsplit (line, ":", -1);
 
361
        if (g_strv_length (fields) == 4)
 
362
        {
 
363
            struct group *entry = malloc (sizeof (struct group));
 
364
 
 
365
            entry->gr_name = g_strdup (fields[0]);
 
366
            entry->gr_passwd = g_strdup (fields[1]);
 
367
            entry->gr_gid = atoi (fields[2]);
 
368
            entry->gr_mem = g_strsplit (fields[3], ",", -1);
 
369
            group_entries = g_list_append (group_entries, entry);
 
370
        }
 
371
        g_strfreev (fields);
 
372
    }
 
373
    g_strfreev (lines);
 
374
}
 
375
 
 
376
struct group *
 
377
getgrnam (const char *name)
 
378
{
 
379
    GList *link;
 
380
 
 
381
    load_group_file ();
 
382
 
 
383
    for (link = group_entries; link; link = link->next)
 
384
    {
 
385
        struct group *entry = link->data;
 
386
        if (strcmp (entry->gr_name, name) == 0)
 
387
            break;
 
388
    }
 
389
    if (!link)
 
390
        return NULL;
 
391
 
 
392
    return link->data;
 
393
}
 
394
 
 
395
struct group *
 
396
getgrgid (gid_t gid)
 
397
{
 
398
    GList *link;
 
399
 
 
400
    load_group_file ();
 
401
 
 
402
    for (link = group_entries; link; link = link->next)
 
403
    {
 
404
        struct group *entry = link->data;
 
405
        if (entry->gr_gid == gid)
 
406
            break;
 
407
    }
 
408
    if (!link)
 
409
        return NULL;
 
410
 
 
411
    return link->data;
 
412
}
 
413
 
260
414
int
261
415
pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
262
416
{
645
799
    pam_putenv (pamh, e);
646
800
    g_free (e);
647
801
 
 
802
    /* Join special groups if requested */
 
803
    if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
 
804
    {
 
805
        struct group *group;
 
806
        gid_t *groups;
 
807
        int groups_length;
 
808
 
 
809
        group = getgrnam ("test-group");
 
810
        if (group)
 
811
        {
 
812
            groups_length = getgroups (0, NULL);
 
813
            groups = malloc (sizeof (gid_t) * (groups_length + 1));
 
814
            groups_length = getgroups (groups_length, groups);
 
815
            groups[groups_length] = group->gr_gid;
 
816
            groups_length++;
 
817
            setgroups (groups_length, groups);
 
818
            free (groups);
 
819
        }
 
820
 
 
821
        /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
 
822
        pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
 
823
    }
 
824
 
648
825
    return PAM_SUCCESS;
649
826
}
650
827