~ubuntu-branches/ubuntu/utopic/libuser/utopic-proposed

« back to all changes in this revision

Viewing changes to lib/user.c

  • Committer: Bazaar Package Importer
  • Author(s): Ghe Rivero
  • Date: 2005-09-30 16:22:04 UTC
  • Revision ID: james.westby@ubuntu.com-20050930162204-qubxaa7e2lbovdgh
Tags: upstream-0.54.dfsg.1
ImportĀ upstreamĀ versionĀ 0.54.dfsg.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2002, 2004 Red Hat, Inc.
 
2
 *
 
3
 * This is free software; you can redistribute it and/or modify it under
 
4
 * the terms of the GNU Library General Public License as published by
 
5
 * the Free Software Foundation; either version 2 of the License, or
 
6
 * (at your option) any later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
 * General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Library General Public
 
14
 * License along with this program; if not, write to the Free Software
 
15
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
16
 */
 
17
 
 
18
#ident "$Id: user.c,v 1.78 2005/09/12 23:24:37 mitr Exp $"
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "../config.h"
 
22
#endif
 
23
#include <sys/types.h>
 
24
#include <errno.h>
 
25
#include <grp.h>
 
26
#include <inttypes.h>
 
27
#include <pwd.h>
 
28
#include <stddef.h>
 
29
#include <stdio.h>
 
30
#include <stdlib.h>
 
31
#include <string.h>
 
32
#include <utmp.h>
 
33
#include "user_private.h"
 
34
#include "internal.h"
 
35
 
 
36
#define DEFAULT_ID 500
 
37
 
 
38
enum lu_dispatch_id {
 
39
        uses_elevated_privileges = 0x0003,
 
40
        user_lookup_name,
 
41
        user_lookup_id,
 
42
        user_default,
 
43
        user_add_prep,
 
44
        user_add,
 
45
        user_mod,
 
46
        user_del,
 
47
        user_lock,
 
48
        user_unlock,
 
49
        user_unlock_nonempty,
 
50
        user_is_locked,
 
51
        user_setpass,
 
52
        user_removepass,
 
53
        users_enumerate,
 
54
        users_enumerate_by_group,
 
55
        users_enumerate_full,
 
56
        users_enumerate_by_group_full,
 
57
        group_lookup_name,
 
58
        group_lookup_id,
 
59
        group_default,
 
60
        group_add_prep,
 
61
        group_add,
 
62
        group_mod,
 
63
        group_del,
 
64
        group_lock,
 
65
        group_unlock,
 
66
        group_unlock_nonempty,
 
67
        group_is_locked,
 
68
        group_setpass,
 
69
        group_removepass,
 
70
        groups_enumerate,
 
71
        groups_enumerate_full,
 
72
        groups_enumerate_by_user,
 
73
        groups_enumerate_by_user_full,
 
74
};
 
75
 
 
76
struct lu_context *
 
77
lu_start(const char *auth_name, enum lu_entity_type auth_type,
 
78
         const char *modules, const char *create_modules,
 
79
         lu_prompt_fn *prompter, gpointer prompter_data,
 
80
         struct lu_error **error)
 
81
{
 
82
        struct lu_context *ctx = NULL;
 
83
 
 
84
        LU_ERROR_CHECK(error);
 
85
 
 
86
        /* Register our message domain with gettext. */
 
87
        bindtextdomain(PACKAGE, LOCALEDIR);
 
88
 
 
89
        /* Initialize the gtype system if it's not already initialized. */
 
90
        g_type_init();
 
91
 
 
92
        /* Allocate space for the context. */
 
93
        ctx = g_malloc0(sizeof(struct lu_context));
 
94
 
 
95
        /* Create a configuration structure. */
 
96
        if (lu_cfg_init(ctx, error) == FALSE) {
 
97
                /* If there's an error, lu_cfg_init() sets it. */
 
98
                g_free(ctx);
 
99
                return NULL;
 
100
        }
 
101
 
 
102
        /* Initialize the rest of the fields. */
 
103
        ctx->scache = lu_string_cache_new(TRUE);
 
104
 
 
105
        ctx->auth_name = ctx->scache->cache(ctx->scache, auth_name);
 
106
        ctx->auth_type = auth_type;
 
107
 
 
108
        ctx->prompter = prompter;
 
109
        ctx->prompter_data = prompter_data;
 
110
 
 
111
        ctx->modules = g_tree_new(lu_strcasecmp);
 
112
 
 
113
        /* Read the list of default modules, if the application didn't specify
 
114
         * any that we should be using. */
 
115
        if (modules == NULL) {
 
116
                modules = lu_cfg_read_single(ctx,
 
117
                                             "defaults/modules",
 
118
                                             "files shadow");
 
119
        }
 
120
        if (create_modules == NULL) {
 
121
                create_modules = lu_cfg_read_single(ctx,
 
122
                                                    "defaults/create_modules",
 
123
                                                    "files shadow");
 
124
        }
 
125
 
 
126
        /* Load the modules. */
 
127
        if (!lu_modules_load(ctx, modules, &ctx->module_names, error)) {
 
128
                /* lu_module_load sets errors */
 
129
                g_free(ctx);
 
130
                return NULL;
 
131
        }
 
132
        if (!lu_modules_load(ctx, create_modules, &ctx->create_module_names,
 
133
                             error)) {
 
134
                /* lu_module_load sets errors */
 
135
                g_free(ctx);
 
136
                return NULL;
 
137
        }
 
138
 
 
139
        return ctx;
 
140
}
 
141
 
 
142
void
 
143
lu_end(struct lu_context *context)
 
144
{
 
145
        g_assert(context != NULL);
 
146
 
 
147
        if (context->modules != NULL) {
 
148
                g_tree_foreach(context->modules, lu_module_unload, NULL);
 
149
                g_tree_destroy(context->modules);
 
150
        }
 
151
 
 
152
        g_value_array_free(context->create_module_names);
 
153
        g_value_array_free(context->module_names);
 
154
 
 
155
        lu_cfg_done(context);
 
156
 
 
157
        if (context->scache != NULL) {
 
158
                context->scache->free(context->scache);
 
159
        }
 
160
 
 
161
        memset(context, 0, sizeof(struct lu_context));
 
162
 
 
163
        g_free(context);
 
164
}
 
165
 
 
166
static const char *
 
167
extract_name(struct lu_ent *ent)
 
168
{
 
169
        GValueArray *array;
 
170
        GValue *value;
 
171
        g_return_val_if_fail(ent != NULL, NULL);
 
172
        g_return_val_if_fail((ent->type == lu_user) || (ent->type == lu_group), NULL);
 
173
        array = lu_ent_get(ent,
 
174
                           ent->type == lu_user ? LU_USERNAME : LU_GROUPNAME);
 
175
        if (array == NULL) {
 
176
                array = lu_ent_get_current(ent,
 
177
                                           ent->type == lu_user ? LU_USERNAME : LU_GROUPNAME);
 
178
        }
 
179
        g_return_val_if_fail(array != NULL, NULL);
 
180
        value = g_value_array_get_nth(array, 0);
 
181
        g_return_val_if_fail(value != NULL, NULL);
 
182
        return ent->cache->cache(ent->cache, g_value_get_string(value));
 
183
}
 
184
 
 
185
static gboolean
 
186
lu_name_allowed(struct lu_ent *ent, struct lu_error **error)
 
187
{
 
188
        const char *sdata;
 
189
        size_t len, i;
 
190
 
 
191
        g_return_val_if_fail(ent != NULL, FALSE);
 
192
        g_return_val_if_fail((ent->type == lu_user) || (ent->type == lu_group),
 
193
                             FALSE);
 
194
        sdata = extract_name(ent);
 
195
        if (sdata == NULL) {
 
196
                lu_error_new(error, lu_error_name_bad, _("name is not set"));
 
197
                return FALSE;
 
198
        }
 
199
        len = strlen(sdata);
 
200
        if (len == 0) {
 
201
                lu_error_new(error, lu_error_name_bad, _("name is too short"));
 
202
                return FALSE;
 
203
        }
 
204
        if (len > UT_NAMESIZE - 1) {
 
205
                lu_error_new(error, lu_error_name_bad,
 
206
                             _("name is too long (%zu > %d)"), len,
 
207
                             UT_NAMESIZE - 1);
 
208
                return FALSE;
 
209
        }
 
210
        for (i = 0; sdata[i] != '\0'; i++) {
 
211
                if ((sdata[i] & 0x80) != 0) {
 
212
                        lu_error_new(error, lu_error_name_bad,
 
213
                                     _("name contains non-ASCII characters"));
 
214
                        return FALSE;
 
215
                }
 
216
        }
 
217
        for (i = 0; sdata[i] != '\0'; i++) {
 
218
                if ((sdata[i] == 0x7f) || (sdata[i] < 0x20)) {
 
219
                        lu_error_new(error, lu_error_name_bad,
 
220
                                     _("name contains control characters"));
 
221
                        return FALSE;
 
222
                }
 
223
        }
 
224
        for (i = 0; sdata[i] != '\0'; i++) {
 
225
                if (g_ascii_isspace(sdata[i])) {
 
226
                        lu_error_new(error, lu_error_name_bad,
 
227
                                     _("name contains whitespace"));
 
228
                        return FALSE;
 
229
                }
 
230
        }
 
231
        /* SUSv3 (3.426) says "To be portable across ..., the value is composed
 
232
           of characters from the portable filename character set. The hyphen
 
233
           should not be used as the first character of a portable user name.
 
234
 
 
235
           Note: "the value _is_ composed", not "should be" composed.  We don't
 
236
           have to allow more. */
 
237
        if (sdata[0] == '-') {
 
238
                lu_error_new(error, lu_error_name_bad,
 
239
                             _("name starts with a hyphen"));
 
240
                return FALSE;
 
241
        }
 
242
        for (i = 0; sdata[i] != '\0'; i++) {
 
243
                if (!((sdata[i] >= 'a' && sdata[i] <= 'z')
 
244
                      || (sdata[i] >= 'A' && sdata[i] <= 'Z')
 
245
                      || (sdata[i] >= '0' && sdata[i] <= '9')
 
246
                      || sdata[i] == '.' || sdata[i] ==  '-' || sdata[i] == '_'
 
247
                      /* Allow trailing $ for samba machine accounts. */
 
248
                      || (sdata[i] == '$' && sdata[i + 1] == '\0'))) {
 
249
                        lu_error_new(error, lu_error_name_bad,
 
250
                                     _("name contains invalid char `%c'"),
 
251
                                     sdata[i]);
 
252
                        return FALSE;
 
253
                }
 
254
        }
 
255
        return TRUE;
 
256
}
 
257
 
 
258
static id_t
 
259
extract_id(struct lu_ent *ent)
 
260
{
 
261
        GValueArray *array;
 
262
        GValue *value;
 
263
 
 
264
        g_return_val_if_fail(ent != NULL, LU_VALUE_INVALID_ID);
 
265
        g_return_val_if_fail((ent->type == lu_user) || (ent->type == lu_group),
 
266
                             LU_VALUE_INVALID_ID);
 
267
        array = lu_ent_get(ent,
 
268
                           ent->type == lu_user ? LU_UIDNUMBER : LU_GIDNUMBER);
 
269
        if (array == NULL) {
 
270
                array = lu_ent_get_current(ent,
 
271
                                           ent->type == lu_user ? LU_UIDNUMBER : LU_GIDNUMBER);
 
272
        }
 
273
        g_return_val_if_fail(array != NULL, LU_VALUE_INVALID_ID);
 
274
        value = g_value_array_get_nth(array, 0);
 
275
        g_return_val_if_fail(value != NULL, LU_VALUE_INVALID_ID);
 
276
        return lu_value_get_id(value);
 
277
}
 
278
 
 
279
static uid_t
 
280
convert_user_name_to_id(struct lu_context *context, const char *sdata)
 
281
{
 
282
        struct lu_ent *ent;
 
283
        uid_t ret = LU_VALUE_INVALID_ID;
 
284
        char buf[LINE_MAX * 4];
 
285
        struct passwd *err, passwd;
 
286
        struct lu_error *error = NULL;
 
287
        if ((getpwnam_r(sdata, &passwd, buf, sizeof(buf), &err) == 0) &&
 
288
            (err == &passwd))
 
289
                return passwd.pw_uid;
 
290
        ent = lu_ent_new();
 
291
        if (lu_user_lookup_name(context, sdata, ent, &error) == TRUE) {
 
292
                ret = extract_id(ent);
 
293
        }
 
294
        lu_ent_free(ent);
 
295
        return ret;
 
296
}
 
297
 
 
298
static gid_t
 
299
convert_group_name_to_id(struct lu_context *context, const char *sdata)
 
300
{
 
301
        struct lu_ent *ent;
 
302
        gid_t ret = LU_VALUE_INVALID_ID;
 
303
        char buf[LINE_MAX * 4];
 
304
        struct group *err, group;
 
305
        struct lu_error *error = NULL;
 
306
        if ((getgrnam_r(sdata, &group, buf, sizeof(buf), &err) == 0) &&
 
307
            (err == &group))
 
308
                return group.gr_gid;
 
309
        ent = lu_ent_new();
 
310
        if (lu_group_lookup_name(context, sdata, ent, &error) == TRUE) {
 
311
                ret = extract_id(ent);
 
312
        }
 
313
        lu_ent_free(ent);
 
314
        return ret;
 
315
}
 
316
 
 
317
static gboolean lu_refresh_int(struct lu_context *context,
 
318
                               struct lu_ent *entity,
 
319
                               struct lu_error **error);
 
320
 
 
321
static gboolean
 
322
lu_refresh_user(struct lu_context *context, struct lu_ent *entity,
 
323
                struct lu_error **error)
 
324
{
 
325
        g_return_val_if_fail(entity->type == lu_user, FALSE);
 
326
        return lu_refresh_int(context, entity, error);
 
327
}
 
328
 
 
329
static gboolean
 
330
lu_refresh_group(struct lu_context *context, struct lu_ent *entity,
 
331
                 struct lu_error **error)
 
332
{
 
333
        g_return_val_if_fail(entity->type == lu_group, FALSE);
 
334
        return lu_refresh_int(context, entity, error);
 
335
}
 
336
 
 
337
static gboolean
 
338
run_single(struct lu_context *context,
 
339
           struct lu_module *module,
 
340
           enum lu_dispatch_id id,
 
341
           const char *sdata, id_t ldata,
 
342
           struct lu_ent *entity,
 
343
           gpointer *ret,
 
344
           struct lu_error **error)
 
345
{
 
346
        GPtrArray *ptrs;
 
347
        size_t i;
 
348
 
 
349
        g_assert(context != NULL);
 
350
        g_assert(module != NULL);
 
351
 
 
352
        LU_ERROR_CHECK(error);
 
353
 
 
354
        switch (id) {
 
355
        case user_lookup_name:
 
356
                g_return_val_if_fail(sdata != NULL, FALSE);
 
357
                g_return_val_if_fail(strlen(sdata) > 0, FALSE);
 
358
                g_return_val_if_fail(entity != NULL, FALSE);
 
359
                if (module->user_lookup_name(module, sdata, entity, error)) {
 
360
                        lu_ent_add_module(entity, module->name);
 
361
                        return TRUE;
 
362
                }
 
363
                return FALSE;
 
364
        case user_lookup_id:
 
365
                g_return_val_if_fail(entity != NULL, FALSE);
 
366
                if (module->user_lookup_id(module, ldata, entity, error)) {
 
367
                        lu_ent_add_module(entity, module->name);
 
368
                        return TRUE;
 
369
                }
 
370
                return FALSE;
 
371
        case user_default:
 
372
                g_return_val_if_fail(entity != NULL, FALSE);
 
373
                if (module->user_default(module, sdata, ldata, entity, error)) {
 
374
                        lu_ent_add_module(entity, module->name);
 
375
                        return TRUE;
 
376
                }
 
377
                return FALSE;
 
378
        case user_add:
 
379
                g_return_val_if_fail(entity != NULL, FALSE);
 
380
                if (module->user_add(module, entity, error)) {
 
381
                        lu_ent_add_module(entity, module->name);
 
382
                        return TRUE;
 
383
                }
 
384
                return FALSE;
 
385
        case user_add_prep:
 
386
                g_return_val_if_fail(entity != NULL, FALSE);
 
387
                if (lu_name_allowed(entity, error) == FALSE) {
 
388
                        return FALSE;
 
389
                } else if (module->user_add_prep(module, entity, error)) {
 
390
                        lu_ent_add_module(entity, module->name);
 
391
                        return TRUE;
 
392
                }
 
393
                return FALSE;
 
394
        case user_mod:
 
395
                g_return_val_if_fail(entity != NULL, FALSE);
 
396
                return module->user_mod(module, entity, error);
 
397
        case user_del:
 
398
                g_return_val_if_fail(entity != NULL, FALSE);
 
399
                return module->user_del(module, entity, error);
 
400
        case user_lock:
 
401
                g_return_val_if_fail(entity != NULL, FALSE);
 
402
                return module->user_lock(module, entity, error);
 
403
        case user_unlock:
 
404
                g_return_val_if_fail(entity != NULL, FALSE);
 
405
                return module->user_unlock(module, entity, error);
 
406
        case user_unlock_nonempty:
 
407
                g_return_val_if_fail(entity != NULL, FALSE);
 
408
                return module->user_unlock_nonempty(module, entity, error);
 
409
        case user_is_locked:
 
410
                g_return_val_if_fail(entity != NULL, FALSE);
 
411
                return module->user_is_locked(module, entity, error);
 
412
        case user_setpass:
 
413
                g_return_val_if_fail(entity != NULL, FALSE);
 
414
                g_return_val_if_fail(sdata != NULL, FALSE);
 
415
                return module->user_setpass(module, entity, sdata, error);
 
416
        case user_removepass:
 
417
                g_return_val_if_fail(entity != NULL, FALSE);
 
418
                return module->user_removepass(module, entity, error);
 
419
        case users_enumerate:
 
420
                g_return_val_if_fail(ret != NULL, FALSE);
 
421
                *ret = module->users_enumerate(module, sdata, error);
 
422
                return TRUE;
 
423
        case users_enumerate_by_group:
 
424
                g_return_val_if_fail(sdata != NULL, FALSE);
 
425
                g_return_val_if_fail(strlen(sdata) > 0, FALSE);
 
426
                g_return_val_if_fail(ret != NULL, FALSE);
 
427
                *ret = module->users_enumerate_by_group(module,
 
428
                                                        sdata,
 
429
                                                        ldata,
 
430
                                                        error);
 
431
                return TRUE;
 
432
        case users_enumerate_full:
 
433
                g_return_val_if_fail(ret != NULL, FALSE);
 
434
                *ret = module->users_enumerate_full(module, sdata, error);
 
435
                if (*ret) {
 
436
                        ptrs = *ret;
 
437
                        for (i = 0; i < ptrs->len; i++) {
 
438
                                lu_ent_add_module(g_ptr_array_index(ptrs, i),
 
439
                                                  module->name);
 
440
                        }
 
441
                }
 
442
                return TRUE;
 
443
        case users_enumerate_by_group_full:
 
444
                g_return_val_if_fail(sdata != NULL, FALSE);
 
445
                g_return_val_if_fail(strlen(sdata) > 0, FALSE);
 
446
                g_return_val_if_fail(ret != NULL, FALSE);
 
447
                *ret = module->users_enumerate_by_group_full(module,
 
448
                                                             sdata,
 
449
                                                             ldata,
 
450
                                                             error);
 
451
                if (*ret) {
 
452
                        ptrs = *ret;
 
453
                        for (i = 0; i < ptrs->len; i++) {
 
454
                                lu_ent_add_module(g_ptr_array_index(ptrs, i),
 
455
                                                  module->name);
 
456
                        }
 
457
                }
 
458
                return TRUE;
 
459
        case group_lookup_name:
 
460
                g_return_val_if_fail(sdata != NULL, FALSE);
 
461
                g_return_val_if_fail(strlen(sdata) > 0, FALSE);
 
462
                g_return_val_if_fail(entity != NULL, FALSE);
 
463
                if (module->group_lookup_name(module, sdata, entity, error)) {
 
464
                        lu_ent_add_module(entity, module->name);
 
465
                        return TRUE;
 
466
                }
 
467
                return FALSE;
 
468
        case group_lookup_id:
 
469
                g_return_val_if_fail(entity != NULL, FALSE);
 
470
                if (module->group_lookup_id(module, ldata, entity, error)) {
 
471
                        lu_ent_add_module(entity, module->name);
 
472
                        return TRUE;
 
473
                }
 
474
                return FALSE;
 
475
        case group_default:
 
476
                g_return_val_if_fail(entity != NULL, FALSE);
 
477
                if (module->group_default(module, sdata, ldata, entity, error)) {
 
478
                        lu_ent_add_module(entity, module->name);
 
479
                        return TRUE;
 
480
                }
 
481
                return FALSE;
 
482
        case group_add:
 
483
                g_return_val_if_fail(entity != NULL, FALSE);
 
484
                if (module->group_add(module, entity, error)) {
 
485
                        lu_ent_add_module(entity, module->name);
 
486
                        return TRUE;
 
487
                }
 
488
                return FALSE;
 
489
        case group_add_prep:
 
490
                g_return_val_if_fail(entity != NULL, FALSE);
 
491
                if (lu_name_allowed(entity, error) == FALSE) {
 
492
                        return FALSE;
 
493
                } else if (module->group_add_prep(module, entity, error)) {
 
494
                        lu_ent_add_module(entity, module->name);
 
495
                        return TRUE;
 
496
                }
 
497
                return FALSE;
 
498
        case group_mod:
 
499
                g_return_val_if_fail(entity != NULL, FALSE);
 
500
                return module->group_mod(module, entity, error);
 
501
        case group_del:
 
502
                g_return_val_if_fail(entity != NULL, FALSE);
 
503
                return module->group_del(module, entity, error);
 
504
        case group_lock:
 
505
                g_return_val_if_fail(entity != NULL, FALSE);
 
506
                return module->group_lock(module, entity, error);
 
507
        case group_unlock:
 
508
                g_return_val_if_fail(entity != NULL, FALSE);
 
509
                return module->group_unlock(module, entity, error);
 
510
        case group_unlock_nonempty:
 
511
                g_return_val_if_fail(entity != NULL, FALSE);
 
512
                return module->group_unlock_nonempty(module, entity, error);
 
513
        case group_is_locked:
 
514
                g_return_val_if_fail(entity != NULL, FALSE);
 
515
                return module->group_is_locked(module, entity, error);
 
516
        case group_setpass:
 
517
                g_return_val_if_fail(entity != NULL, FALSE);
 
518
                g_return_val_if_fail(sdata != NULL, FALSE);
 
519
                return module->group_setpass(module, entity, sdata, error);
 
520
        case group_removepass:
 
521
                g_return_val_if_fail(entity != NULL, FALSE);
 
522
                return module->group_removepass(module, entity, error);
 
523
        case groups_enumerate:
 
524
                g_return_val_if_fail(ret != NULL, FALSE);
 
525
                *ret = module->groups_enumerate(module, sdata, error);
 
526
                return TRUE;
 
527
        case groups_enumerate_by_user:
 
528
                g_return_val_if_fail(sdata != NULL, FALSE);
 
529
                g_return_val_if_fail(strlen(sdata) > 0, FALSE);
 
530
                g_return_val_if_fail(ret != NULL, FALSE);
 
531
                *ret = module->groups_enumerate_by_user(module,
 
532
                                                        sdata,
 
533
                                                        ldata,
 
534
                                                        error);
 
535
                return TRUE;
 
536
        case groups_enumerate_full:
 
537
                g_return_val_if_fail(ret != NULL, FALSE);
 
538
                *ret = module->groups_enumerate_full(module, sdata, error);
 
539
                if (*ret) {
 
540
                        ptrs = *ret;
 
541
                        for (i = 0; i < ptrs->len; i++) {
 
542
                                lu_ent_add_module(g_ptr_array_index(ptrs, i),
 
543
                                                  module->name);
 
544
                        }
 
545
                }
 
546
                return TRUE;
 
547
        case groups_enumerate_by_user_full:
 
548
                g_return_val_if_fail(sdata != NULL, FALSE);
 
549
                g_return_val_if_fail(strlen(sdata) > 0, FALSE);
 
550
                g_return_val_if_fail(ret != NULL, FALSE);
 
551
                *ret = module->groups_enumerate_by_user_full(module,
 
552
                                                             sdata,
 
553
                                                             ldata,
 
554
                                                             error);
 
555
                if (*ret) {
 
556
                        ptrs = *ret;
 
557
                        for (i = 0; i < ptrs->len; i++) {
 
558
                                lu_ent_add_module(g_ptr_array_index(ptrs, i),
 
559
                                                  module->name);
 
560
                        }
 
561
                }
 
562
                return TRUE;
 
563
        case uses_elevated_privileges:
 
564
                return module->uses_elevated_privileges(module);
 
565
        default:
 
566
                g_assert_not_reached(); /* not reached */
 
567
        }
 
568
        return FALSE;
 
569
}
 
570
 
 
571
static gboolean
 
572
logic_and(gboolean a, gboolean b)
 
573
{
 
574
        return a && b;
 
575
}
 
576
 
 
577
static gboolean
 
578
logic_or(gboolean a, gboolean b)
 
579
{
 
580
        return a || b;
 
581
}
 
582
 
 
583
static void
 
584
remove_duplicate_values(GValueArray *array)
 
585
{
 
586
        size_t i, j;
 
587
        GValue *ivalue, *jvalue;
 
588
 
 
589
        for (i = 0; i < array->n_values; i++) {
 
590
                ivalue = g_value_array_get_nth(array, i);
 
591
                for (j = i + 1; j < array->n_values; j++) {
 
592
                        jvalue = g_value_array_get_nth(array, j);
 
593
                        if (G_VALUE_TYPE(ivalue) == G_VALUE_TYPE(jvalue)
 
594
                            && lu_values_equal(ivalue, jvalue)) {
 
595
                                g_value_array_remove(array, j);
 
596
                                j--;
 
597
                        }
 
598
                }
 
599
        }
 
600
}
 
601
 
 
602
static int
 
603
compare_strings(gconstpointer a, gconstpointer b, gpointer data)
 
604
{
 
605
        (void)data;
 
606
        return strcmp(a, b);
 
607
}
 
608
 
 
609
static GPtrArray *
 
610
merge_ent_array_duplicates(GPtrArray *array)
 
611
{
 
612
        GPtrArray *ret = NULL;
 
613
        size_t i, j;
 
614
        const char *attr;
 
615
        struct lu_ent *current, *saved;
 
616
        GValueArray *values;
 
617
        GValue *value;
 
618
        GList *attributes, *list;
 
619
        GTree *users, *groups, *tree;
 
620
        g_return_val_if_fail(array != NULL, NULL);
 
621
        /* We need four trees to hold the known entities. */
 
622
        users = g_tree_new_full(compare_strings, NULL, g_free, NULL);
 
623
        groups = g_tree_new_full(compare_strings, NULL, g_free, NULL);
 
624
        /* A structure to hold the new list. */
 
625
        ret = g_ptr_array_new();
 
626
        /* Iterate over every entity in the incoming list. */
 
627
        for (i = 0; i < array->len; i++) {
 
628
                char *key;
 
629
 
 
630
                current = g_ptr_array_index(array, i);
 
631
                key = NULL;
 
632
                values = NULL;
 
633
                tree = NULL;
 
634
                /* Get the name of the user or group. */
 
635
                if (current->type == lu_user) {
 
636
                        values = lu_ent_get(current, LU_USERNAME);
 
637
                        tree = users;
 
638
                } else if (current->type == lu_group) {
 
639
                        values = lu_ent_get(current, LU_GROUPNAME);
 
640
                        tree = groups;
 
641
                } else {
 
642
                        g_warning("Unknown entity(%zu) type: %d.\n",
 
643
                                  i, current->type);
 
644
                        g_assert_not_reached();
 
645
                }
 
646
                value = g_value_array_get_nth(values, 0);
 
647
                /* Convert that name or number to a quark. */
 
648
                key = lu_value_strdup(value);
 
649
                /* Check if there's already an entity with that name. */
 
650
                saved = g_tree_lookup(tree, key);
 
651
                /* If it's not in there, add this one. */
 
652
                if (saved == NULL) {
 
653
                        g_tree_insert(tree, key, current);
 
654
                        g_ptr_array_add(ret, current);
 
655
                } else {
 
656
                        g_free (key);
 
657
                        /* Merge all of its data into the existing one; first,
 
658
                         * the current data. */
 
659
                        attributes = lu_ent_get_attributes_current(current);
 
660
                        list = attributes;
 
661
                        while (attributes != NULL) {
 
662
                                attr = (const char *)attributes->data;
 
663
                                values = lu_ent_get_current(current, attr);
 
664
                                for (j = 0; j < values->n_values; j++) {
 
665
                                        value = g_value_array_get_nth(values,
 
666
                                                                      j);
 
667
                                        lu_ent_add_current(saved, attr, value);
 
668
                                }
 
669
                                attributes = g_list_next(attributes);
 
670
                        }
 
671
                        g_list_free(list);
 
672
                        /* Merge the pending data. */
 
673
                        attributes = lu_ent_get_attributes(current);
 
674
                        while (attributes != NULL) {
 
675
                                attr = (const char *)attributes->data;
 
676
                                values = lu_ent_get(current, attr);
 
677
                                for (j = 0; j < values->n_values; j++) {
 
678
                                        value = g_value_array_get_nth(values,
 
679
                                                                      j);
 
680
                                        lu_ent_add(saved, attr, value);
 
681
                                }
 
682
                                attributes = g_list_next(attributes);
 
683
                        }
 
684
                        g_list_free(list);
 
685
                        /* Now merge the entity's list of modules. */
 
686
                        for (j = 0; j < current->modules->n_values; j++) {
 
687
                                value = g_value_array_get_nth(current->modules,
 
688
                                                              j);
 
689
                                g_value_array_append(saved->modules, value);
 
690
                        }
 
691
                        remove_duplicate_values(saved->modules);
 
692
                        lu_ent_free(current);
 
693
                }
 
694
        }
 
695
        g_tree_destroy(users);
 
696
        g_tree_destroy(groups);
 
697
        g_ptr_array_free(array, TRUE);
 
698
        return ret;
 
699
}
 
700
 
 
701
static gboolean
 
702
run_list(struct lu_context *context,
 
703
         GValueArray *list,
 
704
         gboolean (*logic_function)(gboolean a, gboolean b),
 
705
         enum lu_dispatch_id id,
 
706
         const char *sdata, id_t ldata,
 
707
         struct lu_ent *entity,
 
708
         gpointer ret,
 
709
         struct lu_error **firsterror)
 
710
{
 
711
        struct lu_module *module;
 
712
        GPtrArray *ptr_array = NULL, *tmp_ptr_array = NULL;
 
713
        GValueArray *value_array = NULL, *tmp_value_array = NULL;
 
714
        GValue *value;
 
715
        gpointer scratch;
 
716
        struct lu_ent *tmp_ent;
 
717
        char *name;
 
718
        gboolean success, tsuccess;
 
719
        struct lu_error *lasterror = NULL;
 
720
        size_t i, j;
 
721
 
 
722
        LU_ERROR_CHECK(firsterror);
 
723
 
 
724
        g_assert(context != NULL);
 
725
        g_assert(context->module_names != NULL);
 
726
        g_assert(context->modules != NULL);
 
727
        g_assert(entity != NULL);
 
728
        g_assert(logic_function != NULL);
 
729
        g_assert((id == user_lookup_name) ||
 
730
                 (id == user_lookup_id) ||
 
731
                 (id == user_default) ||
 
732
                 (id == user_add_prep) ||
 
733
                 (id == user_add) ||
 
734
                 (id == user_mod) ||
 
735
                 (id == user_del) ||
 
736
                 (id == user_lock) ||
 
737
                 (id == user_unlock) ||
 
738
                 (id == user_unlock_nonempty) ||
 
739
                 (id == user_is_locked) ||
 
740
                 (id == user_setpass) ||
 
741
                 (id == user_removepass) ||
 
742
                 (id == users_enumerate) ||
 
743
                 (id == users_enumerate_by_group) ||
 
744
                 (id == users_enumerate_full) ||
 
745
                 (id == users_enumerate_by_group_full) ||
 
746
                 (id == group_lookup_name) ||
 
747
                 (id == group_lookup_id) ||
 
748
                 (id == group_default) ||
 
749
                 (id == group_add_prep) ||
 
750
                 (id == group_add) ||
 
751
                 (id == group_mod) ||
 
752
                 (id == group_del) ||
 
753
                 (id == group_lock) ||
 
754
                 (id == group_unlock) ||
 
755
                 (id == group_unlock_nonempty) ||
 
756
                 (id == group_is_locked) ||
 
757
                 (id == group_setpass) ||
 
758
                 (id == group_removepass) ||
 
759
                 (id == groups_enumerate) ||
 
760
                 (id == groups_enumerate_by_user) ||
 
761
                 (id == groups_enumerate_full) ||
 
762
                 (id == groups_enumerate_by_user_full) ||
 
763
                 (id == uses_elevated_privileges));
 
764
 
 
765
        success = FALSE;
 
766
        for (i = 0; i < list->n_values; i++) {
 
767
                value = g_value_array_get_nth(list, i);
 
768
                name = g_value_dup_string(value);
 
769
                module = g_tree_lookup(context->modules, name);
 
770
                g_free(name);
 
771
                g_assert(module != NULL);
 
772
                scratch = NULL;
 
773
                tsuccess = run_single(context, module, id,
 
774
                                      sdata, ldata, entity, &scratch,
 
775
                                      &lasterror);
 
776
                if (scratch != NULL) switch (id) {
 
777
                        case users_enumerate:
 
778
                        case users_enumerate_by_group:
 
779
                        case groups_enumerate:
 
780
                        case groups_enumerate_by_user:
 
781
                                tmp_value_array = scratch;
 
782
                                value_array = *(GValueArray **)ret;
 
783
                                if (value_array == NULL) {
 
784
                                        value_array = g_value_array_new(0);
 
785
                                }
 
786
                                if (tmp_value_array != NULL) {
 
787
                                        for (j = 0; j < tmp_value_array->n_values; j++) {
 
788
                                                value = g_value_array_get_nth(tmp_value_array,
 
789
                                                                              j);
 
790
                                                g_value_array_append(value_array,
 
791
                                                                     value);
 
792
                                        }
 
793
                                        g_value_array_free(tmp_value_array);
 
794
                                }
 
795
                                remove_duplicate_values(value_array);
 
796
                                *(GValueArray **)ret = value_array;
 
797
                                break;
 
798
                        case users_enumerate_full:
 
799
                        case users_enumerate_by_group_full:
 
800
                        case groups_enumerate_full:
 
801
                        case groups_enumerate_by_user_full:
 
802
                                /* FIXME: do some kind of merging here. */
 
803
                                tmp_ptr_array = scratch;
 
804
                                ptr_array = *(GPtrArray **)ret;
 
805
                                if (ptr_array == NULL) {
 
806
                                        ptr_array = g_ptr_array_new();
 
807
                                }
 
808
                                if (tmp_ptr_array != NULL) {
 
809
                                        for (j = 0; j < tmp_ptr_array->len; j++) {
 
810
                                                tmp_ent = g_ptr_array_index(tmp_ptr_array,
 
811
                                                                            j);
 
812
                                                g_ptr_array_add(ptr_array, tmp_ent);
 
813
                                        }
 
814
                                        g_ptr_array_free(tmp_ptr_array, TRUE);
 
815
                                }
 
816
                                /* remove_duplicate_ptrs(ptr_array); */
 
817
                                *(GPtrArray **)ret = ptr_array;
 
818
                                break;
 
819
                        case user_lookup_name:
 
820
                        case user_lookup_id:
 
821
                        case user_default:
 
822
                        case user_add_prep:
 
823
                        case user_add:
 
824
                        case user_mod:
 
825
                        case user_del:
 
826
                        case group_lookup_name:
 
827
                        case group_lookup_id:
 
828
                        case group_default:
 
829
                        case group_add_prep:
 
830
                        case group_add:
 
831
                        case group_mod:
 
832
                        case group_del:
 
833
                        case uses_elevated_privileges:
 
834
                                break;
 
835
                        default:
 
836
                                g_assert_not_reached(); /* never reached */
 
837
                                break;
 
838
                }
 
839
                if (i == 0) {
 
840
                        success = tsuccess;
 
841
                } else {
 
842
                        success = logic_function(success, tsuccess);
 
843
                }
 
844
                if (firsterror != NULL) {
 
845
                        if (*firsterror == NULL) {
 
846
                                /* Make this the error we report. */
 
847
                                *firsterror = lasterror;
 
848
                                lasterror = NULL;
 
849
                        } else {
 
850
                                /* Already have an error, discard. */
 
851
                                if (lasterror != NULL) {
 
852
                                        lu_error_free(&lasterror);
 
853
                                }
 
854
                        }
 
855
                } else {
 
856
                        /* Can't report this error. */
 
857
                        if (lasterror != NULL) {
 
858
                                lu_error_free(&lasterror);
 
859
                        }
 
860
                }
 
861
        }
 
862
 
 
863
        return success;
 
864
}
 
865
 
 
866
static gboolean
 
867
lu_refresh_int(struct lu_context *context, struct lu_ent *entity,
 
868
               struct lu_error **error)
 
869
{
 
870
        enum lu_dispatch_id id = 0;
 
871
        const char *sdata;
 
872
        id_t ldata;
 
873
        gpointer scratch = NULL;
 
874
        g_return_val_if_fail((entity->type == lu_user) ||
 
875
                             (entity->type == lu_group),
 
876
                             FALSE);
 
877
        if (entity->type == lu_user) {
 
878
                id = user_lookup_name;
 
879
        } else
 
880
        if (entity->type == lu_group) {
 
881
                id = group_lookup_name;
 
882
        } else {
 
883
                g_assert_not_reached();
 
884
        }
 
885
        sdata = extract_name(entity);
 
886
        ldata = extract_id(entity);
 
887
        if (run_list(context, entity->modules, logic_and, id,
 
888
                     sdata, ldata, entity, &scratch, error)) {
 
889
                lu_ent_revert(entity);
 
890
                return TRUE;
 
891
        }
 
892
        return FALSE;
 
893
}
 
894
 
 
895
static gboolean
 
896
lu_dispatch(struct lu_context *context,
 
897
            enum lu_dispatch_id id,
 
898
            const char *sdata, id_t ldata,
 
899
            struct lu_ent *entity,
 
900
            gpointer ret,
 
901
            struct lu_error **error)
 
902
{
 
903
        struct lu_ent *tmp = NULL;
 
904
        gboolean success;
 
905
        GValueArray *values = NULL;
 
906
        GPtrArray *ptrs = NULL;
 
907
        GValue *value = NULL;
 
908
        gpointer scratch = NULL;
 
909
        size_t i;
 
910
 
 
911
        LU_ERROR_CHECK(error);
 
912
 
 
913
        g_assert(context != NULL);
 
914
 
 
915
        tmp = lu_ent_new();
 
916
        if (entity != NULL) {
 
917
                lu_ent_copy(entity, tmp);
 
918
        }
 
919
 
 
920
        success = FALSE;
 
921
 
 
922
        switch (id) {
 
923
        case user_lookup_id:
 
924
        case group_lookup_id:
 
925
                /* Make sure data items are right for this call. */
 
926
                sdata = NULL;
 
927
                g_assert(ldata != LU_VALUE_INVALID_ID);
 
928
                /* Run the list. */
 
929
                if (run_list(context, context->module_names,
 
930
                            logic_or, id,
 
931
                            sdata, ldata, tmp, &scratch, error)) {
 
932
                        /* Got a match on that ID, convert it to a
 
933
                         * name and look it up by name. */
 
934
                        const char *attr = NULL;
 
935
                        if (id == user_lookup_id) {
 
936
                                attr = LU_USERNAME;
 
937
                                id = user_lookup_name;
 
938
                        }
 
939
                        if (id == group_lookup_id) {
 
940
                                attr = LU_GROUPNAME;
 
941
                                id = group_lookup_name;
 
942
                        }
 
943
                        values = lu_ent_get_current(tmp, attr);
 
944
                        if (values != NULL) {
 
945
                                value = g_value_array_get_nth(values, 0);
 
946
                                attr = g_value_get_string(value);
 
947
                                sdata = tmp->cache->cache(tmp->cache, attr);
 
948
                        } else {
 
949
                                /* No values for the right attribute. */
 
950
                                break;
 
951
                        }
 
952
                } else {
 
953
                        /* No match on that ID. */
 
954
                        break;
 
955
                }
 
956
                /* fall through on successful ID->name conversion */
 
957
        case user_lookup_name:
 
958
        case group_lookup_name:
 
959
                /* Make sure data items are right for this call. */
 
960
                g_assert(sdata != NULL);
 
961
                ldata = LU_VALUE_INVALID_ID;
 
962
                /* Run the list. */
 
963
                if (run_list(context, context->module_names,
 
964
                            logic_or, id,
 
965
                            sdata, ldata, tmp, &scratch, error)) {
 
966
                        if (entity != NULL) {
 
967
                                lu_ent_revert(tmp);
 
968
                                lu_ent_copy(tmp, entity);
 
969
                        }
 
970
                        success = TRUE;
 
971
                }
 
972
                break;
 
973
        case user_default:
 
974
        case group_default:
 
975
                /* Make sure we have both name and boolean here. */
 
976
                g_return_val_if_fail(sdata != NULL, FALSE);
 
977
                /* Run the checks and preps. */
 
978
                if (run_list(context, context->create_module_names,
 
979
                            logic_and, id,
 
980
                            sdata, ldata, tmp, &scratch, error)) {
 
981
                        if (entity != NULL) {
 
982
                                lu_ent_copy(tmp, entity);
 
983
                        }
 
984
                        success = TRUE;
 
985
                }
 
986
                break;
 
987
        case user_add_prep:
 
988
        case group_add_prep:
 
989
                /* Make sure we have both name and ID here. */
 
990
                sdata = sdata ?: extract_name(tmp);
 
991
                if (ldata == LU_VALUE_INVALID_ID)
 
992
                        ldata = extract_id(tmp);
 
993
                g_return_val_if_fail(sdata != NULL, FALSE);
 
994
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
995
                /* Run the checks and preps. */
 
996
                if (run_list(context, context->create_module_names,
 
997
                            logic_and, id,
 
998
                            sdata, ldata, tmp, &scratch, error)) {
 
999
                        if (entity != NULL) {
 
1000
                                lu_ent_copy(tmp, entity);
 
1001
                        }
 
1002
                        success = TRUE;
 
1003
                }
 
1004
                break;
 
1005
        case user_add:
 
1006
        case group_add:
 
1007
                /* Make sure we have both name and ID here. */
 
1008
                sdata = sdata ?: extract_name(tmp);
 
1009
                if (ldata == LU_VALUE_INVALID_ID)
 
1010
                        ldata = extract_id(tmp);
 
1011
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1012
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
1013
                /* Add the account. */
 
1014
                if (run_list(context, context->create_module_names,
 
1015
                            logic_and, id,
 
1016
                            sdata, ldata, tmp, &scratch, error)) {
 
1017
                        if (entity != NULL) {
 
1018
                                lu_ent_copy(tmp, entity);
 
1019
                        }
 
1020
                        success = TRUE;
 
1021
                }
 
1022
                break;
 
1023
        case user_mod:
 
1024
        case group_mod:
 
1025
                /* Make sure we have both name and ID here. */
 
1026
                /* FIXME: sdata, ldata contain new values (and are not even
 
1027
                   used). */
 
1028
                sdata = sdata ?: extract_name(tmp);
 
1029
                if (ldata == LU_VALUE_INVALID_ID)
 
1030
                        ldata = extract_id(tmp);
 
1031
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1032
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
1033
                /* Make the changes. */
 
1034
                g_assert(entity != NULL);
 
1035
                if (run_list(context, entity->modules,
 
1036
                            logic_and, id,
 
1037
                            sdata, ldata, tmp, &scratch, error)) {
 
1038
                        lu_ent_commit(tmp);
 
1039
                        lu_ent_copy(tmp, entity);
 
1040
                        success = TRUE;
 
1041
                }
 
1042
                break;
 
1043
        case user_del:
 
1044
        case user_lock:
 
1045
        case user_unlock:
 
1046
        case user_unlock_nonempty:
 
1047
        case group_del:
 
1048
        case group_lock:
 
1049
        case group_unlock:
 
1050
        case group_unlock_nonempty:
 
1051
                /* Make sure we have both name and ID here. */
 
1052
                sdata = sdata ?: extract_name(tmp);
 
1053
                if (ldata == LU_VALUE_INVALID_ID)
 
1054
                        ldata = extract_id(tmp);
 
1055
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1056
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
1057
                /* Make the changes. */
 
1058
                g_assert(entity != NULL);
 
1059
                if (run_list(context, entity->modules,
 
1060
                            logic_and, id,
 
1061
                            sdata, ldata, tmp, &scratch, error)) {
 
1062
                        lu_ent_revert(tmp);
 
1063
                        lu_ent_copy(tmp, entity);
 
1064
                        success = TRUE;
 
1065
                }
 
1066
                break;
 
1067
        case user_setpass:
 
1068
        case group_setpass:
 
1069
                /* Make sure we have a valid password. */
 
1070
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1071
                /* fall through */
 
1072
        case user_removepass:
 
1073
        case group_removepass:
 
1074
                /* Make the changes. */
 
1075
                g_assert(entity != NULL);
 
1076
                if (run_list(context, entity->modules,
 
1077
                            logic_and, id,
 
1078
                            sdata, ldata, tmp, &scratch, error)) {
 
1079
                        lu_ent_revert(tmp);
 
1080
                        lu_ent_copy(tmp, entity);
 
1081
                        success = TRUE;
 
1082
                }
 
1083
                break;
 
1084
        case user_is_locked:
 
1085
        case group_is_locked:
 
1086
                /* Make sure we have both name and ID here. */
 
1087
                sdata = sdata ?: extract_name(tmp);
 
1088
                if (ldata == LU_VALUE_INVALID_ID)
 
1089
                        ldata = extract_id(tmp);
 
1090
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1091
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
1092
                /* Run the checks. */
 
1093
                g_assert(entity != NULL);
 
1094
                if (run_list(context, entity->modules,
 
1095
                            logic_or, id,
 
1096
                            sdata, ldata, tmp, &scratch, error)) {
 
1097
                        lu_ent_copy(tmp, entity);
 
1098
                        success = TRUE;
 
1099
                }
 
1100
                break;
 
1101
        case users_enumerate_by_group:
 
1102
        case groups_enumerate_by_user:
 
1103
                /* Make sure we have both name and ID here. */
 
1104
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1105
                if (id == users_enumerate_by_group) {
 
1106
                        ldata = convert_group_name_to_id(context, sdata);
 
1107
                } else
 
1108
                if (id == groups_enumerate_by_user) {
 
1109
                        ldata = convert_user_name_to_id(context, sdata);
 
1110
                } else {
 
1111
                        g_assert_not_reached();
 
1112
                }
 
1113
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
1114
                /* fall through */
 
1115
        case users_enumerate:
 
1116
        case groups_enumerate:
 
1117
                /* Get the lists. */
 
1118
                if (run_list(context, context->module_names,
 
1119
                            logic_or, id,
 
1120
                            sdata, ldata, tmp, &values, error)) {
 
1121
                        *(GValueArray **)ret = values;
 
1122
                        success = TRUE;
 
1123
                }
 
1124
                break;
 
1125
        case users_enumerate_by_group_full:
 
1126
        case groups_enumerate_by_user_full:
 
1127
                /* Make sure we have both name and ID here. */
 
1128
                g_return_val_if_fail(sdata != NULL, FALSE);
 
1129
                if (id == users_enumerate_by_group_full) {
 
1130
                        ldata = convert_group_name_to_id(context, sdata);
 
1131
                } else
 
1132
                if (id == groups_enumerate_by_user_full) {
 
1133
                        ldata = convert_user_name_to_id(context, sdata);
 
1134
                } else {
 
1135
                        g_assert_not_reached();
 
1136
                }
 
1137
                g_return_val_if_fail(ldata != LU_VALUE_INVALID_ID, FALSE);
 
1138
                /* fall through */
 
1139
        case users_enumerate_full:
 
1140
        case groups_enumerate_full:
 
1141
                /* Get the lists. */
 
1142
                if (run_list(context, context->module_names,
 
1143
                            logic_or, id,
 
1144
                            sdata, ldata, tmp, &ptrs, error)) {
 
1145
                        if (ptrs != NULL) {
 
1146
                                for (i = 0; i < ptrs->len; i++) {
 
1147
                                        struct lu_ent *ent;
 
1148
                                        ent = g_ptr_array_index(ptrs, i);
 
1149
                                        lu_ent_revert(ent);
 
1150
                                }
 
1151
                        }
 
1152
                        *(GPtrArray **)ret = ptrs;
 
1153
                        success = TRUE;
 
1154
                }
 
1155
                /* Clean up results. */
 
1156
                if (*(GPtrArray **)ret != NULL) {
 
1157
                        *(GPtrArray **)ret
 
1158
                                = merge_ent_array_duplicates(*(GPtrArray **)ret);
 
1159
                }
 
1160
                break;
 
1161
        case uses_elevated_privileges:
 
1162
                if (run_list(context, context->module_names,
 
1163
                            logic_or, id,
 
1164
                            sdata, ldata, tmp, &scratch, error)) {
 
1165
                        success = TRUE;
 
1166
                }
 
1167
                break;
 
1168
        default:
 
1169
                g_assert(0);    /* not reached */
 
1170
                break;
 
1171
        }
 
1172
        lu_ent_free(tmp);
 
1173
 
 
1174
        if (success) {
 
1175
                switch (id) {
 
1176
                        case user_lookup_id:
 
1177
                        case user_lookup_name:
 
1178
                                g_assert(entity != NULL);
 
1179
                                entity->type = lu_user;
 
1180
                                break;
 
1181
                        case group_lookup_name:
 
1182
                        case group_lookup_id:
 
1183
                                g_assert(entity != NULL);
 
1184
                                entity->type = lu_group;
 
1185
                                break;
 
1186
                        default:
 
1187
                                break;
 
1188
                }
 
1189
                if ((error != NULL) && (*error != NULL)) {
 
1190
                        lu_error_free(error);
 
1191
                }
 
1192
        }
 
1193
 
 
1194
        return success;
 
1195
}
 
1196
 
 
1197
/* FIXME: error status, if any, is not reported to the caller */
 
1198
gboolean
 
1199
lu_uses_elevated_privileges (struct lu_context *context)
 
1200
{
 
1201
        struct lu_error *error = NULL;
 
1202
        gboolean ret = lu_dispatch(context, uses_elevated_privileges, NULL, 0,
 
1203
                                   NULL, NULL, &error);
 
1204
        if (error != NULL) {
 
1205
                lu_error_free(&error);
 
1206
        }
 
1207
        return ret;
 
1208
}
 
1209
 
 
1210
gboolean
 
1211
lu_user_lookup_name(struct lu_context * context, const char *name,
 
1212
                    struct lu_ent * ent, struct lu_error ** error)
 
1213
{
 
1214
        LU_ERROR_CHECK(error);
 
1215
        g_return_val_if_fail(name != NULL, FALSE);
 
1216
        return lu_dispatch(context, user_lookup_name, name, 0,
 
1217
                           ent, NULL, error);
 
1218
}
 
1219
 
 
1220
gboolean
 
1221
lu_group_lookup_name(struct lu_context * context, const char *name,
 
1222
                     struct lu_ent * ent, struct lu_error ** error)
 
1223
{
 
1224
        LU_ERROR_CHECK(error);
 
1225
        g_return_val_if_fail(name != NULL, FALSE);
 
1226
        return lu_dispatch(context, group_lookup_name, name, 0,
 
1227
                           ent, NULL, error);
 
1228
}
 
1229
 
 
1230
gboolean
 
1231
lu_user_lookup_id(struct lu_context * context, uid_t uid,
 
1232
                  struct lu_ent * ent, struct lu_error ** error)
 
1233
{
 
1234
        LU_ERROR_CHECK(error);
 
1235
        return lu_dispatch(context, user_lookup_id, NULL, uid,
 
1236
                           ent, NULL, error);
 
1237
}
 
1238
 
 
1239
gboolean
 
1240
lu_group_lookup_id(struct lu_context * context, gid_t gid,
 
1241
                   struct lu_ent * ent, struct lu_error ** error)
 
1242
{
 
1243
        LU_ERROR_CHECK(error);
 
1244
        return lu_dispatch(context, group_lookup_id, NULL, gid,
 
1245
                           ent, NULL, error);
 
1246
}
 
1247
 
 
1248
gboolean
 
1249
lu_user_add(struct lu_context * context, struct lu_ent * ent,
 
1250
            struct lu_error ** error)
 
1251
{
 
1252
        gboolean ret = FALSE;
 
1253
        LU_ERROR_CHECK(error);
 
1254
 
 
1255
        g_return_val_if_fail(ent != NULL, FALSE);
 
1256
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1257
 
 
1258
        if (lu_dispatch(context, user_add_prep, NULL, LU_VALUE_INVALID_ID,
 
1259
                        ent, NULL, error)) {
 
1260
                ret = lu_dispatch(context, user_add, NULL, LU_VALUE_INVALID_ID,
 
1261
                                  ent, NULL, error) &&
 
1262
                      lu_refresh_user(context, ent, error);
 
1263
        }
 
1264
        return ret;
 
1265
}
 
1266
 
 
1267
gboolean
 
1268
lu_group_add(struct lu_context * context, struct lu_ent * ent,
 
1269
             struct lu_error ** error)
 
1270
{
 
1271
        gboolean ret = FALSE;
 
1272
        LU_ERROR_CHECK(error);
 
1273
 
 
1274
        g_return_val_if_fail(ent != NULL, FALSE);
 
1275
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1276
 
 
1277
        if (lu_dispatch(context, group_add_prep, NULL, LU_VALUE_INVALID_ID,
 
1278
                        ent, NULL, error)) {
 
1279
                ret = lu_dispatch(context, group_add, NULL,
 
1280
                                  LU_VALUE_INVALID_ID, ent, NULL, error) &&
 
1281
                      lu_refresh_group(context, ent, error);
 
1282
        }
 
1283
        return ret;
 
1284
}
 
1285
 
 
1286
gboolean
 
1287
lu_user_modify(struct lu_context * context, struct lu_ent * ent,
 
1288
               struct lu_error ** error)
 
1289
{
 
1290
        LU_ERROR_CHECK(error);
 
1291
        g_return_val_if_fail(ent != NULL, FALSE);
 
1292
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1293
        return lu_dispatch(context, user_mod, NULL, LU_VALUE_INVALID_ID, ent,
 
1294
                           NULL, error) &&
 
1295
               lu_refresh_user(context, ent, error);
 
1296
}
 
1297
 
 
1298
gboolean
 
1299
lu_group_modify(struct lu_context * context, struct lu_ent * ent,
 
1300
                struct lu_error ** error)
 
1301
{
 
1302
        LU_ERROR_CHECK(error);
 
1303
        g_return_val_if_fail(ent != NULL, FALSE);
 
1304
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1305
        return lu_dispatch(context, group_mod, NULL, LU_VALUE_INVALID_ID, ent,
 
1306
                           NULL, error) &&
 
1307
               lu_refresh_group(context, ent, error);
 
1308
}
 
1309
 
 
1310
gboolean
 
1311
lu_user_delete(struct lu_context * context, struct lu_ent * ent,
 
1312
               struct lu_error ** error)
 
1313
{
 
1314
        LU_ERROR_CHECK(error);
 
1315
        g_return_val_if_fail(ent != NULL, FALSE);
 
1316
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1317
        return lu_dispatch(context, user_del, NULL, LU_VALUE_INVALID_ID, ent,
 
1318
                           NULL, error);
 
1319
}
 
1320
 
 
1321
gboolean
 
1322
lu_group_delete(struct lu_context * context, struct lu_ent * ent,
 
1323
                struct lu_error ** error)
 
1324
{
 
1325
        LU_ERROR_CHECK(error);
 
1326
        g_return_val_if_fail(ent != NULL, FALSE);
 
1327
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1328
        return lu_dispatch(context, group_del, NULL, LU_VALUE_INVALID_ID, ent,
 
1329
                           NULL, error);
 
1330
}
 
1331
 
 
1332
gboolean
 
1333
lu_user_lock(struct lu_context * context, struct lu_ent * ent,
 
1334
             struct lu_error ** error)
 
1335
{
 
1336
        LU_ERROR_CHECK(error);
 
1337
        g_return_val_if_fail(ent != NULL, FALSE);
 
1338
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1339
        return lu_dispatch(context, user_lock, NULL, LU_VALUE_INVALID_ID, ent,
 
1340
                           NULL, error) &&
 
1341
               lu_refresh_user(context, ent, error);
 
1342
}
 
1343
 
 
1344
gboolean
 
1345
lu_user_unlock(struct lu_context * context, struct lu_ent * ent,
 
1346
               struct lu_error ** error)
 
1347
{
 
1348
        LU_ERROR_CHECK(error);
 
1349
        g_return_val_if_fail(ent != NULL, FALSE);
 
1350
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1351
        return lu_dispatch(context, user_unlock, NULL, LU_VALUE_INVALID_ID,
 
1352
                           ent, NULL, error) &&
 
1353
               lu_refresh_user(context, ent, error);
 
1354
}
 
1355
 
 
1356
gboolean
 
1357
lu_user_unlock_nonempty(struct lu_context * context, struct lu_ent * ent,
 
1358
                        struct lu_error ** error)
 
1359
{
 
1360
        LU_ERROR_CHECK(error);
 
1361
        g_return_val_if_fail(ent != NULL, FALSE);
 
1362
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1363
        return lu_dispatch(context, user_unlock_nonempty, NULL,
 
1364
                           LU_VALUE_INVALID_ID, ent, NULL, error) &&
 
1365
               lu_refresh_user(context, ent, error);
 
1366
}
 
1367
 
 
1368
gboolean
 
1369
lu_user_islocked(struct lu_context * context, struct lu_ent * ent,
 
1370
                 struct lu_error ** error)
 
1371
{
 
1372
        LU_ERROR_CHECK(error);
 
1373
 
 
1374
        g_return_val_if_fail(ent != NULL, FALSE);
 
1375
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1376
 
 
1377
        return lu_dispatch(context, user_is_locked, NULL, LU_VALUE_INVALID_ID,
 
1378
                           ent, NULL, error);
 
1379
}
 
1380
 
 
1381
gboolean
 
1382
lu_user_setpass(struct lu_context * context, struct lu_ent * ent,
 
1383
                const char *password, gboolean is_crypted,
 
1384
                struct lu_error ** error)
 
1385
{
 
1386
        gboolean ret;
 
1387
        char *tmp;
 
1388
        LU_ERROR_CHECK(error);
 
1389
 
 
1390
        g_return_val_if_fail(ent != NULL, FALSE);
 
1391
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1392
 
 
1393
        if (is_crypted) {
 
1394
                tmp = g_strconcat(LU_CRYPTED, password, NULL);
 
1395
        } else {
 
1396
                tmp = g_strdup(password);
 
1397
        }
 
1398
        ret = lu_dispatch(context, user_setpass, tmp, LU_VALUE_INVALID_ID,
 
1399
                          ent, NULL, error);
 
1400
        g_free(tmp);
 
1401
        if (ret) {
 
1402
                ret = lu_refresh_user(context, ent, error);
 
1403
        }
 
1404
        if (ret) {
 
1405
                GValue value;
 
1406
                lu_ent_clear(ent, LU_SHADOWLASTCHANGE);
 
1407
                memset(&value, 0, sizeof(value));
 
1408
                g_value_init(&value, G_TYPE_STRING);
 
1409
                g_value_set_string(&value,
 
1410
                                   lu_util_shadow_current_date(ent->cache));
 
1411
                lu_ent_add(ent, LU_SHADOWLASTCHANGE, &value);
 
1412
                g_value_unset(&value);
 
1413
        }
 
1414
        return ret;
 
1415
}
 
1416
 
 
1417
gboolean
 
1418
lu_user_removepass(struct lu_context * context, struct lu_ent * ent,
 
1419
                   struct lu_error ** error)
 
1420
{
 
1421
        gboolean ret;
 
1422
        LU_ERROR_CHECK(error);
 
1423
 
 
1424
        g_return_val_if_fail(ent != NULL, FALSE);
 
1425
        g_return_val_if_fail(ent->type == lu_user, FALSE);
 
1426
 
 
1427
        ret = lu_dispatch(context, user_removepass, NULL, LU_VALUE_INVALID_ID,
 
1428
                          ent, NULL, error);
 
1429
        if (ret) {
 
1430
                ret = lu_refresh_user(context, ent, error);
 
1431
        }
 
1432
        if (ret) {
 
1433
                GValue value;
 
1434
                lu_ent_clear(ent, LU_SHADOWLASTCHANGE);
 
1435
                memset(&value, 0, sizeof(value));
 
1436
                g_value_init(&value, G_TYPE_STRING);
 
1437
                g_value_set_string(&value,
 
1438
                                   lu_util_shadow_current_date(ent->cache));
 
1439
                lu_ent_add(ent, LU_SHADOWLASTCHANGE, &value);
 
1440
                g_value_unset(&value);
 
1441
        }
 
1442
        return ret;
 
1443
}
 
1444
 
 
1445
gboolean
 
1446
lu_group_lock(struct lu_context * context, struct lu_ent * ent,
 
1447
              struct lu_error ** error)
 
1448
{
 
1449
        LU_ERROR_CHECK(error);
 
1450
 
 
1451
        g_return_val_if_fail(ent != NULL, FALSE);
 
1452
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1453
 
 
1454
        return lu_dispatch(context, group_lock, NULL, LU_VALUE_INVALID_ID,
 
1455
                           ent, NULL, error) &&
 
1456
               lu_refresh_group(context, ent, error);
 
1457
}
 
1458
 
 
1459
gboolean
 
1460
lu_group_unlock(struct lu_context * context, struct lu_ent * ent,
 
1461
                struct lu_error ** error)
 
1462
{
 
1463
        LU_ERROR_CHECK(error);
 
1464
 
 
1465
        g_return_val_if_fail(ent != NULL, FALSE);
 
1466
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1467
 
 
1468
        return lu_dispatch(context, group_unlock, NULL, LU_VALUE_INVALID_ID,
 
1469
                           ent, NULL, error) &&
 
1470
               lu_refresh_group(context, ent, error);
 
1471
}
 
1472
 
 
1473
gboolean
 
1474
lu_group_unlock_nonempty(struct lu_context * context, struct lu_ent * ent,
 
1475
                         struct lu_error ** error)
 
1476
{
 
1477
        LU_ERROR_CHECK(error);
 
1478
 
 
1479
        g_return_val_if_fail(ent != NULL, FALSE);
 
1480
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1481
 
 
1482
        return lu_dispatch(context, group_unlock_nonempty, NULL,
 
1483
                           LU_VALUE_INVALID_ID, ent, NULL, error) &&
 
1484
               lu_refresh_group(context, ent, error);
 
1485
}
 
1486
 
 
1487
gboolean
 
1488
lu_group_islocked(struct lu_context * context, struct lu_ent * ent,
 
1489
                  struct lu_error ** error)
 
1490
{
 
1491
        LU_ERROR_CHECK(error);
 
1492
 
 
1493
        g_return_val_if_fail(ent != NULL, FALSE);
 
1494
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1495
 
 
1496
        return lu_dispatch(context, group_is_locked, NULL, LU_VALUE_INVALID_ID,
 
1497
                           ent, NULL, error);
 
1498
}
 
1499
 
 
1500
gboolean
 
1501
lu_group_setpass(struct lu_context * context, struct lu_ent * ent,
 
1502
                 const char *password, gboolean is_crypted,
 
1503
                 struct lu_error ** error)
 
1504
{
 
1505
        gboolean ret;
 
1506
        char *tmp;
 
1507
        LU_ERROR_CHECK(error);
 
1508
 
 
1509
        g_return_val_if_fail(ent != NULL, FALSE);
 
1510
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1511
 
 
1512
        if (is_crypted) {
 
1513
                tmp = g_strconcat(LU_CRYPTED, password, NULL);
 
1514
        } else {
 
1515
                tmp = g_strdup(password);
 
1516
        }
 
1517
        ret = lu_dispatch(context, group_setpass, tmp, LU_VALUE_INVALID_ID,
 
1518
                          ent, NULL, error);
 
1519
        g_free(tmp);
 
1520
        if (ret) {
 
1521
                ret = lu_refresh_group(context, ent, error);
 
1522
        }
 
1523
        if (ret) {
 
1524
                GValue value;
 
1525
                lu_ent_clear(ent, LU_SHADOWLASTCHANGE);
 
1526
                memset(&value, 0, sizeof(value));
 
1527
                g_value_init(&value, G_TYPE_STRING);
 
1528
                g_value_set_string(&value,
 
1529
                                   lu_util_shadow_current_date(ent->cache));
 
1530
                lu_ent_add(ent, LU_SHADOWLASTCHANGE, &value);
 
1531
                g_value_unset(&value);
 
1532
        }
 
1533
        return ret;
 
1534
}
 
1535
 
 
1536
gboolean
 
1537
lu_group_removepass(struct lu_context * context, struct lu_ent * ent,
 
1538
                    struct lu_error ** error)
 
1539
{
 
1540
        gboolean ret;
 
1541
        LU_ERROR_CHECK(error);
 
1542
 
 
1543
        g_return_val_if_fail(ent != NULL, FALSE);
 
1544
        g_return_val_if_fail(ent->type == lu_group, FALSE);
 
1545
 
 
1546
        ret = lu_dispatch(context, group_removepass, NULL, LU_VALUE_INVALID_ID,
 
1547
                          ent, NULL, error);
 
1548
        if (ret) {
 
1549
                ret = lu_refresh_group(context, ent, error);
 
1550
        }
 
1551
        if (ret) {
 
1552
                GValue value;
 
1553
                lu_ent_clear(ent, LU_SHADOWLASTCHANGE);
 
1554
                memset(&value, 0, sizeof(value));
 
1555
                g_value_init(&value, G_TYPE_STRING);
 
1556
                g_value_set_string(&value,
 
1557
                                   lu_util_shadow_current_date(ent->cache));
 
1558
                lu_ent_add(ent, LU_SHADOWLASTCHANGE, &value);
 
1559
                g_value_unset(&value);
 
1560
        }
 
1561
        return ret;
 
1562
}
 
1563
 
 
1564
GValueArray *
 
1565
lu_users_enumerate(struct lu_context * context, const char *pattern,
 
1566
                   struct lu_error ** error)
 
1567
{
 
1568
        GValueArray *ret = NULL;
 
1569
        LU_ERROR_CHECK(error);
 
1570
        lu_dispatch(context, users_enumerate, pattern, LU_VALUE_INVALID_ID,
 
1571
                    NULL, &ret, error);
 
1572
        return ret;
 
1573
}
 
1574
 
 
1575
GValueArray *
 
1576
lu_groups_enumerate(struct lu_context * context, const char *pattern,
 
1577
                    struct lu_error ** error)
 
1578
{
 
1579
        GValueArray *ret = NULL;
 
1580
        LU_ERROR_CHECK(error);
 
1581
        lu_dispatch(context, groups_enumerate, pattern, LU_VALUE_INVALID_ID,
 
1582
                    NULL, &ret, error);
 
1583
        return ret;
 
1584
}
 
1585
 
 
1586
GValueArray *
 
1587
lu_users_enumerate_by_group(struct lu_context * context, const char *group,
 
1588
                            struct lu_error ** error)
 
1589
{
 
1590
        GValueArray *ret = NULL;
 
1591
        LU_ERROR_CHECK(error);
 
1592
        lu_dispatch(context, users_enumerate_by_group, group,
 
1593
                    LU_VALUE_INVALID_ID, NULL, &ret, error);
 
1594
        return ret;
 
1595
}
 
1596
 
 
1597
GValueArray *
 
1598
lu_groups_enumerate_by_user(struct lu_context * context, const char *user,
 
1599
                            struct lu_error ** error)
 
1600
{
 
1601
        GValueArray *ret = NULL;
 
1602
        LU_ERROR_CHECK(error);
 
1603
        lu_dispatch(context, groups_enumerate_by_user, user,
 
1604
                    LU_VALUE_INVALID_ID, NULL, &ret, error);
 
1605
        return ret;
 
1606
}
 
1607
 
 
1608
GPtrArray *
 
1609
lu_users_enumerate_full(struct lu_context * context, const char *pattern,
 
1610
                        struct lu_error ** error)
 
1611
{
 
1612
        GPtrArray *ret = NULL;
 
1613
        LU_ERROR_CHECK(error);
 
1614
        lu_dispatch(context, users_enumerate_full, pattern,
 
1615
                    LU_VALUE_INVALID_ID, NULL, &ret, error);
 
1616
        return ret;
 
1617
}
 
1618
 
 
1619
GPtrArray *
 
1620
lu_groups_enumerate_full(struct lu_context * context, const char *pattern,
 
1621
                         struct lu_error ** error)
 
1622
{
 
1623
        GPtrArray *ret = NULL;
 
1624
        LU_ERROR_CHECK(error);
 
1625
        lu_dispatch(context, groups_enumerate_full, pattern,
 
1626
                    LU_VALUE_INVALID_ID, NULL, &ret, error);
 
1627
        return ret;
 
1628
}
 
1629
 
 
1630
#if 0
 
1631
GPtrArray *
 
1632
lu_users_enumerate_by_group_full(struct lu_context * context,
 
1633
                                 const char *pattern,
 
1634
                                 struct lu_error ** error)
 
1635
{
 
1636
        GPtrArray *ret = NULL;
 
1637
        LU_ERROR_CHECK(error);
 
1638
        lu_dispatch(context, users_enumerate_by_group_full, pattern,
 
1639
                    LU_VALUE_INVALID_ID, NULL, (gpointer*) &ret, error);
 
1640
        return ret;
 
1641
}
 
1642
 
 
1643
GPtrArray *
 
1644
lu_groups_enumerate_by_user_full(struct lu_context * context,
 
1645
                                 const char *pattern,
 
1646
                                 struct lu_error ** error)
 
1647
{
 
1648
        GPtrArray *ret = NULL;
 
1649
        LU_ERROR_CHECK(error);
 
1650
        lu_dispatch(context, groups_enumerate_by_user_full, pattern,
 
1651
                    LU_VALUE_INVALID_ID, NULL, (gpointer*) &ret, error);
 
1652
        return ret;
 
1653
}
 
1654
#endif
 
1655
 
 
1656
id_t
 
1657
lu_get_first_unused_id(struct lu_context *ctx,
 
1658
                       enum lu_entity_type type,
 
1659
                       id_t id)
 
1660
{
 
1661
        struct lu_ent *ent;
 
1662
        char buf[LINE_MAX * 4];
 
1663
 
 
1664
        g_return_val_if_fail(ctx != NULL, (id_t)-1);
 
1665
 
 
1666
        ent = lu_ent_new();
 
1667
        if (type == lu_user) {
 
1668
                struct passwd pwd, *err;
 
1669
                struct lu_error *error = NULL;
 
1670
                do {
 
1671
                        /* There may be read-only sources of user information
 
1672
                         * on the system, and we want to avoid allocating an ID
 
1673
                         * that's already in use by a service we can't write
 
1674
                         * to, so check with NSS first.  FIXME: use growing
 
1675
                         * buffers here. */
 
1676
                        if ((getpwuid_r(id, &pwd, buf, sizeof(buf), &err) == 0) &&
 
1677
                            (err == &pwd)) {
 
1678
                                id++;
 
1679
                                continue;
 
1680
                        }
 
1681
                        if (lu_user_lookup_id(ctx, id, ent, &error)) {
 
1682
                                lu_ent_free(ent);
 
1683
                                ent = lu_ent_new();
 
1684
                                id++;
 
1685
                                continue;
 
1686
                        }
 
1687
                        if (error) {
 
1688
                                lu_error_free(&error);
 
1689
                        }
 
1690
                        break;
 
1691
                } while (id != (id_t)-1);
 
1692
        } else if (type == lu_group) {
 
1693
                struct group grp, *err;
 
1694
                struct lu_error *error = NULL;
 
1695
                do {
 
1696
                        /* There may be read-only sources of user information
 
1697
                         * on the system, and we want to avoid allocating an ID
 
1698
                         * that's already in use by a service we can't write
 
1699
                         * to, so check with NSS first. */
 
1700
                        getgrgid_r(id, &grp, buf, sizeof(buf), &err);
 
1701
                        if (err == &grp) {
 
1702
                                id++;
 
1703
                                continue;
 
1704
                        }
 
1705
                        if (lu_group_lookup_id(ctx, id, ent, &error)) {
 
1706
                                lu_ent_free(ent);
 
1707
                                ent = lu_ent_new();
 
1708
                                id++;
 
1709
                                continue;
 
1710
                        }
 
1711
                        if (error) {
 
1712
                                lu_error_free(&error);
 
1713
                        }
 
1714
                        break;
 
1715
                } while (id != (id_t)-1);
 
1716
        }
 
1717
        if (id == (id_t)-1)
 
1718
                id = 0;
 
1719
        lu_ent_free(ent);
 
1720
        return id;
 
1721
}
 
1722
 
 
1723
static gboolean
 
1724
lu_default_int(struct lu_context *context, const char *name,
 
1725
               enum lu_entity_type type, gboolean is_system, struct lu_ent *ent)
 
1726
{
 
1727
        GList *keys, *p;
 
1728
        GValue value;
 
1729
        char *cfgkey, *tmp, *end;
 
1730
        char buf[LINE_MAX * 4];
 
1731
        const char *top, *idkey, *idkeystring, *val, *key;
 
1732
        id_t id = DEFAULT_ID;
 
1733
        struct group grp, *err;
 
1734
        struct lu_error *error = NULL;
 
1735
        gpointer macguffin = NULL;
 
1736
        size_t i;
 
1737
 
 
1738
        g_return_val_if_fail(context != NULL, FALSE);
 
1739
        g_return_val_if_fail(name != NULL, FALSE);
 
1740
        g_return_val_if_fail(strlen(name) > 0, FALSE);
 
1741
        g_return_val_if_fail((type == lu_user) || (type == lu_group), FALSE);
 
1742
        g_return_val_if_fail(ent != NULL, FALSE);
 
1743
        g_return_val_if_fail(ent->magic == LU_ENT_MAGIC, FALSE);
 
1744
 
 
1745
        /* Clear out and initialize the record. */
 
1746
        lu_ent_clear_all(ent);
 
1747
        lu_ent_clear_modules(ent);
 
1748
        ent->type = type;
 
1749
 
 
1750
        /* Set the name of the user/group. */
 
1751
        memset(&value, 0, sizeof(value));
 
1752
        g_value_init(&value, G_TYPE_STRING);
 
1753
        g_value_set_string(&value, name);
 
1754
        if (ent->type == lu_user) {
 
1755
                lu_ent_clear(ent, LU_USERNAME);
 
1756
                lu_ent_add(ent, LU_USERNAME, &value);
 
1757
                /* Additionally, pick a default default group. */
 
1758
                g_value_unset(&value);
 
1759
                /* FIXME: handle arbitrarily long lines. */
 
1760
                if ((getgrnam_r("users", &grp, buf, sizeof(buf), &err) == 0) &&
 
1761
                    (err == &grp))
 
1762
                        lu_value_init_set_id(&value, grp.gr_gid);
 
1763
                else {
 
1764
                        g_value_init(&value, G_TYPE_LONG);
 
1765
                        g_value_set_long(&value, -1);
 
1766
                }
 
1767
                lu_ent_clear(ent, LU_GIDNUMBER);
 
1768
                lu_ent_add(ent, LU_GIDNUMBER, &value);
 
1769
        } else if (ent->type == lu_group) {
 
1770
                lu_ent_clear(ent, LU_GROUPNAME);
 
1771
                lu_ent_add(ent, LU_GROUPNAME, &value);
 
1772
        }
 
1773
        g_value_unset(&value);
 
1774
 
 
1775
        /* Figure out which part of the configuration we need to iterate over
 
1776
         * to initialize the structure. */
 
1777
        if (type == lu_user) {
 
1778
                top = "userdefaults";
 
1779
                idkey = LU_UIDNUMBER;
 
1780
                idkeystring = G_STRINGIFY_ARG(LU_UIDNUMBER);
 
1781
        } else {
 
1782
                top = "groupdefaults";
 
1783
                idkey = LU_GIDNUMBER;
 
1784
                idkeystring = G_STRINGIFY_ARG(LU_GIDNUMBER);
 
1785
        }
 
1786
 
 
1787
        /* The system flag determines where we will start searching for
 
1788
         * unused IDs to assign to this entity. */
 
1789
        if (is_system) {
 
1790
                id = 1;
 
1791
        } else {
 
1792
                cfgkey = g_strdup_printf("%s/%s", top, idkey);
 
1793
                val = lu_cfg_read_single(context, cfgkey, NULL);
 
1794
                g_free(cfgkey);
 
1795
                if (val == NULL) {
 
1796
                        cfgkey = g_strdup_printf("%s/%s", top, idkeystring);
 
1797
                        val = lu_cfg_read_single(context, cfgkey, NULL);
 
1798
                        g_free(cfgkey);
 
1799
                }
 
1800
                if (val != NULL) {
 
1801
                        intmax_t imax;
 
1802
 
 
1803
                        errno = 0;
 
1804
                        imax = strtoimax(val, &tmp, 10);
 
1805
                        if (errno == 0 && *tmp == 0 && tmp != val
 
1806
                            && (id_t)imax == imax)
 
1807
                                id = imax;
 
1808
                        else
 
1809
                                id = DEFAULT_ID;
 
1810
                }
 
1811
        }
 
1812
 
 
1813
        /* Search for a free ID. */
 
1814
        id = lu_get_first_unused_id(context, type, id);
 
1815
 
 
1816
        /* Add this ID to the entity. */
 
1817
        lu_value_init_set_id(&value, id);
 
1818
        lu_ent_add(ent, idkey, &value);
 
1819
        g_value_unset(&value);
 
1820
 
 
1821
        /* Now iterate to find the rest. */
 
1822
        keys = lu_cfg_read_keys(context, top);
 
1823
        for (p = keys; p && p->data; p = g_list_next(p)) {
 
1824
                intmax_t imax;
 
1825
 
 
1826
                struct {
 
1827
                        const char *realkey, *configkey;
 
1828
                } keymap[] = {
 
1829
                        {LU_USERNAME, G_STRINGIFY_ARG(LU_USERNAME)},
 
1830
                        {LU_USERPASSWORD, G_STRINGIFY_ARG(LU_USERPASSWORD)},
 
1831
                        {LU_UIDNUMBER, G_STRINGIFY_ARG(LU_UIDNUMBER)},
 
1832
                        {LU_GIDNUMBER, G_STRINGIFY_ARG(LU_GIDNUMBER)},
 
1833
                        {LU_GECOS, G_STRINGIFY_ARG(LU_GECOS)},
 
1834
                        {LU_HOMEDIRECTORY, G_STRINGIFY_ARG(LU_HOMEDIRECTORY)},
 
1835
                        {LU_LOGINSHELL, G_STRINGIFY_ARG(LU_LOGINSHELL)},
 
1836
 
 
1837
                        {LU_GROUPNAME, G_STRINGIFY_ARG(LU_GROUPNAME)},
 
1838
                        {LU_GROUPPASSWORD, G_STRINGIFY_ARG(LU_GROUPPASSWORD)},
 
1839
                        {LU_MEMBERNAME, G_STRINGIFY_ARG(LU_MEMBERNAME)},
 
1840
                        {LU_ADMINISTRATORNAME,
 
1841
                                G_STRINGIFY_ARG(LU_ADMINISTRATORNAME)},
 
1842
 
 
1843
                        {LU_SHADOWNAME, G_STRINGIFY_ARG(LU_SHADOWNAME)},
 
1844
                        {LU_SHADOWPASSWORD, G_STRINGIFY_ARG(LU_SHADOWPASSWORD)},
 
1845
                        {LU_SHADOWLASTCHANGE,
 
1846
                                G_STRINGIFY_ARG(LU_SHADOWLASTCHANGE)},
 
1847
                        {LU_SHADOWMIN, G_STRINGIFY_ARG(LU_SHADOWMIN)},
 
1848
                        {LU_SHADOWMAX, G_STRINGIFY_ARG(LU_SHADOWMAX)},
 
1849
                        {LU_SHADOWWARNING, G_STRINGIFY_ARG(LU_SHADOWWARNING)},
 
1850
                        {LU_SHADOWINACTIVE, G_STRINGIFY_ARG(LU_SHADOWINACTIVE)},
 
1851
                        {LU_SHADOWEXPIRE, G_STRINGIFY_ARG(LU_SHADOWEXPIRE)},
 
1852
                        {LU_SHADOWFLAG, G_STRINGIFY_ARG(LU_SHADOWFLAG)},
 
1853
 
 
1854
                        {LU_COMMONNAME, G_STRINGIFY_ARG(LU_COMMONNAME)},
 
1855
                        {LU_GIVENNAME, G_STRINGIFY_ARG(LU_GIVENNAME)},
 
1856
                        {LU_SN, G_STRINGIFY_ARG(LU_SN)},
 
1857
                        {LU_ROOMNUMBER, G_STRINGIFY_ARG(LU_ROOMNUMBER)},
 
1858
                        {LU_TELEPHONENUMBER,
 
1859
                                G_STRINGIFY_ARG(LU_TELEPHONENUMBER)},
 
1860
                        {LU_HOMEPHONE, G_STRINGIFY_ARG(LU_HOMEPHONE)},
 
1861
                        {LU_EMAIL, G_STRINGIFY_ARG(LU_EMAIL)},
 
1862
                };
 
1863
                struct {
 
1864
                        const char *format;
 
1865
                        const char *value;
 
1866
                } subst[] = {
 
1867
                        {"%n", name},
 
1868
                        {"%d", lu_util_shadow_current_date(context->scache)},
 
1869
                        /* Must be index 2, see below! */
 
1870
                        {"%u", NULL} /* value set later */
 
1871
                };
 
1872
 
 
1873
                /* Possibly map the key to an internal name. */
 
1874
                key = (const char *) p->data;
 
1875
                for (i = 0; i < G_N_ELEMENTS(keymap); i++) {
 
1876
                        if (strcmp(key, keymap[i].configkey) == 0) {
 
1877
                                key = keymap[i].realkey;
 
1878
                                break;
 
1879
                        }
 
1880
                }
 
1881
 
 
1882
                /* Skip over the key which represents the user/group ID,
 
1883
                 * because we only used it as a starting point. */
 
1884
                if (g_ascii_strcasecmp(idkey, key) == 0) {
 
1885
                        continue;
 
1886
                }
 
1887
 
 
1888
                /* Generate the key and read the value for the item. */
 
1889
                cfgkey = g_strdup_printf("%s/%s", top, (const char *)p->data);
 
1890
                val = lu_cfg_read_single(context, cfgkey, NULL);
 
1891
                g_free(cfgkey);
 
1892
 
 
1893
                /* Create a copy of the value to mess with. */
 
1894
                g_assert(val != NULL);
 
1895
                tmp = g_strdup(val);
 
1896
 
 
1897
                subst[2].value = g_strdup_printf("%jd", (intmax_t)id);
 
1898
                /* Perform substitutions. */
 
1899
                for (i = 0; i < G_N_ELEMENTS(subst); i++) {
 
1900
                        while (strstr(tmp, subst[i].format) != NULL) {
 
1901
                                char *pre, *post, *tmp2, *where;
 
1902
 
 
1903
                                where = strstr(tmp, subst[i].format);
 
1904
                                pre = g_strndup(tmp, where - tmp);
 
1905
                                post = g_strdup(where +
 
1906
                                                strlen(subst[i].format));
 
1907
                                tmp2 = g_strconcat(pre,
 
1908
                                                   subst[i].value,
 
1909
                                                   post,
 
1910
                                                   NULL);
 
1911
                                g_free(pre);
 
1912
                                g_free(post);
 
1913
                                g_free(tmp);
 
1914
                                tmp = tmp2;
 
1915
                        }
 
1916
                }
 
1917
                g_free((char *)subst[2].value);
 
1918
 
 
1919
                /* Check if we can represent this value as a number. */
 
1920
                errno = 0;
 
1921
                imax = strtoimax(tmp, &end, 10);
 
1922
                if (errno == 0 && *end == 0 && end != tmp
 
1923
                    && (long)imax == imax) {
 
1924
                        g_value_init(&value, G_TYPE_LONG);
 
1925
                        g_value_set_long(&value, imax);
 
1926
                } else if (errno == 0 && *end == 0 && end != tmp
 
1927
                           && (id_t)imax == imax)
 
1928
                        lu_value_init_set_id(&value, imax);
 
1929
                else {
 
1930
                        g_value_init(&value, G_TYPE_STRING);
 
1931
                        g_value_set_string(&value, tmp);
 
1932
                }
 
1933
                g_free(tmp);
 
1934
 
 
1935
                /* Add the transformed value. */
 
1936
                lu_ent_clear(ent, key);
 
1937
                lu_ent_add(ent, key, &value);
 
1938
                g_value_unset(&value);
 
1939
        }
 
1940
        if (keys != NULL) {
 
1941
                g_list_free(keys);
 
1942
        }
 
1943
 
 
1944
        /* Now let the modules do their thing. */
 
1945
        lu_dispatch(context, (type == lu_user) ? user_default : group_default,
 
1946
                    name, is_system, ent, &macguffin, &error);
 
1947
        if (error != NULL) {
 
1948
                lu_error_free(&error);
 
1949
        }
 
1950
 
 
1951
        /* Make the pending set be the same as the current set. */
 
1952
        lu_ent_commit(ent);
 
1953
 
 
1954
        return TRUE;
 
1955
}
 
1956
 
 
1957
gboolean
 
1958
lu_user_default(struct lu_context *context, const char *name,
 
1959
                gboolean system_account, struct lu_ent *ent)
 
1960
{
 
1961
        return lu_default_int(context, name, lu_user, system_account, ent);
 
1962
}
 
1963
 
 
1964
gboolean
 
1965
lu_group_default(struct lu_context *context, const char *name,
 
1966
                 gboolean system_account, struct lu_ent *ent)
 
1967
{
 
1968
        return lu_default_int(context, name, lu_group, system_account, ent);
 
1969
}