~ubuntu-branches/ubuntu/saucy/sssd/saucy

« back to all changes in this revision

Viewing changes to server/providers/proxy.c

  • Committer: Stéphane Graber
  • Date: 2011-06-15 16:23:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: stgraber@ubuntu.com-20110615162314-rbhoppnpaxfqo5q7
Merge 1.5.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
   SSSD
3
 
 
4
 
   Proxy Module
5
 
 
6
 
   Copyright (C) Simo Sorce <ssorce@redhat.com> 2008-2009
7
 
 
8
 
   This program is free software; you can redistribute it and/or modify
9
 
   it under the terms of the GNU General Public License as published by
10
 
   the Free Software Foundation; either version 3 of the License, or
11
 
   (at your option) any later version.
12
 
 
13
 
   This program is distributed in the hope that it will be useful,
14
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
   GNU General Public License for more details.
17
 
 
18
 
   You should have received a copy of the GNU General Public License
19
 
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 
*/
21
 
 
22
 
#include <nss.h>
23
 
#include <errno.h>
24
 
#include <pwd.h>
25
 
#include <grp.h>
26
 
#include <dlfcn.h>
27
 
 
28
 
#include <security/pam_appl.h>
29
 
#include <security/pam_modules.h>
30
 
 
31
 
#include "util/util.h"
32
 
#include "providers/dp_backend.h"
33
 
#include "db/sysdb.h"
34
 
 
35
 
struct proxy_nss_ops {
36
 
    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
37
 
                                  char *buffer, size_t buflen, int *errnop);
38
 
    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
39
 
                                  char *buffer, size_t buflen, int *errnop);
40
 
    enum nss_status (*setpwent)(void);
41
 
    enum nss_status (*getpwent_r)(struct passwd *result,
42
 
                                  char *buffer, size_t buflen, int *errnop);
43
 
    enum nss_status (*endpwent)(void);
44
 
 
45
 
    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
46
 
                                  char *buffer, size_t buflen, int *errnop);
47
 
    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
48
 
                                  char *buffer, size_t buflen, int *errnop);
49
 
    enum nss_status (*setgrent)(void);
50
 
    enum nss_status (*getgrent_r)(struct group *result,
51
 
                                  char *buffer, size_t buflen, int *errnop);
52
 
    enum nss_status (*endgrent)(void);
53
 
    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
54
 
                                      long int *start, long int *size,
55
 
                                      gid_t **groups, long int limit,
56
 
                                      int *errnop);
57
 
};
58
 
 
59
 
struct proxy_ctx {
60
 
    struct be_ctx *be;
61
 
    int entry_cache_timeout;
62
 
    struct proxy_nss_ops ops;
63
 
};
64
 
 
65
 
struct proxy_auth_ctx {
66
 
    struct be_ctx *be;
67
 
    char *pam_target;
68
 
};
69
 
 
70
 
struct authtok_conv {
71
 
    uint32_t authtok_size;
72
 
    uint8_t *authtok;
73
 
};
74
 
 
75
 
static int proxy_internal_conv(int num_msg, const struct pam_message **msgm,
76
 
                            struct pam_response **response,
77
 
                            void *appdata_ptr) {
78
 
    int i;
79
 
    struct pam_response *reply;
80
 
    struct authtok_conv *auth_data;
81
 
 
82
 
    auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
83
 
 
84
 
    if (num_msg <= 0) return PAM_CONV_ERR;
85
 
 
86
 
    reply = (struct pam_response *) calloc(num_msg,
87
 
                                           sizeof(struct pam_response));
88
 
    if (reply == NULL) return PAM_CONV_ERR;
89
 
 
90
 
    for (i=0; i < num_msg; i++) {
91
 
        switch( msgm[i]->msg_style ) {
92
 
            case PAM_PROMPT_ECHO_OFF:
93
 
                DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg));
94
 
                reply[i].resp_retcode = 0;
95
 
                reply[i].resp = calloc(auth_data->authtok_size + 1,
96
 
                                       sizeof(char));
97
 
                if (reply[i].resp == NULL) goto failed;
98
 
                memcpy(reply[i].resp, auth_data->authtok, auth_data->authtok_size);
99
 
 
100
 
                break;
101
 
            default:
102
 
                DEBUG(1, ("Conversation style %d not supported.\n",
103
 
                           msgm[i]->msg_style));
104
 
                goto failed;
105
 
        }
106
 
    }
107
 
 
108
 
    *response = reply;
109
 
    reply = NULL;
110
 
 
111
 
    return PAM_SUCCESS;
112
 
 
113
 
failed:
114
 
    free(reply);
115
 
    return PAM_CONV_ERR;
116
 
}
117
 
 
118
 
static void proxy_pam_handler_cache_done(struct tevent_req *treq);
119
 
static void proxy_reply(struct be_req *req, int dp_err,
120
 
                        int error, const char *errstr);
121
 
 
122
 
static void proxy_pam_handler(struct be_req *req) {
123
 
    int ret;
124
 
    int pam_status;
125
 
    pam_handle_t *pamh=NULL;
126
 
    struct authtok_conv *auth_data;
127
 
    struct pam_conv conv;
128
 
    struct pam_data *pd;
129
 
    struct proxy_auth_ctx *ctx;;
130
 
    bool cache_auth_data = false;
131
 
 
132
 
    pd = talloc_get_type(req->req_data, struct pam_data);
133
 
 
134
 
    switch (pd->cmd) {
135
 
        case SSS_PAM_AUTHENTICATE:
136
 
            ctx = talloc_get_type(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
137
 
                                  struct proxy_auth_ctx);
138
 
            break;
139
 
        case SSS_PAM_CHAUTHTOK:
140
 
        case SSS_PAM_CHAUTHTOK_PRELIM:
141
 
            ctx = talloc_get_type(req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
142
 
                                  struct proxy_auth_ctx);
143
 
            break;
144
 
        case SSS_PAM_ACCT_MGMT:
145
 
            ctx = talloc_get_type(req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
146
 
                                  struct proxy_auth_ctx);
147
 
            break;
148
 
        default:
149
 
            DEBUG(1, ("Unsupported PAM task.\n"));
150
 
            pd->pam_status = PAM_SUCCESS;
151
 
            proxy_reply(req, DP_ERR_OK, PAM_SUCCESS, NULL);
152
 
            return;
153
 
    }
154
 
 
155
 
    conv.conv=proxy_internal_conv;
156
 
    auth_data = talloc_zero(req, struct authtok_conv);
157
 
    conv.appdata_ptr=auth_data;
158
 
 
159
 
    ret = pam_start(ctx->pam_target, pd->user, &conv, &pamh);
160
 
    if (ret == PAM_SUCCESS) {
161
 
        DEBUG(1, ("Pam transaction started.\n"));
162
 
        ret = pam_set_item(pamh, PAM_TTY, pd->tty);
163
 
        if (ret != PAM_SUCCESS) {
164
 
            DEBUG(1, ("Setting PAM_TTY failed: %s.\n", pam_strerror(pamh, ret)));
165
 
        }
166
 
        ret = pam_set_item(pamh, PAM_RUSER, pd->ruser);
167
 
        if (ret != PAM_SUCCESS) {
168
 
            DEBUG(1, ("Setting PAM_RUSER failed: %s.\n", pam_strerror(pamh, ret)));
169
 
        }
170
 
        ret = pam_set_item(pamh, PAM_RHOST, pd->rhost);
171
 
        if (ret != PAM_SUCCESS) {
172
 
            DEBUG(1, ("Setting PAM_RHOST failed: %s.\n", pam_strerror(pamh, ret)));
173
 
        }
174
 
        switch (pd->cmd) {
175
 
            case SSS_PAM_AUTHENTICATE:
176
 
                auth_data->authtok_size = pd->authtok_size;
177
 
                auth_data->authtok = pd->authtok;
178
 
                pam_status = pam_authenticate(pamh, 0);
179
 
                if ((pam_status == PAM_SUCCESS) &&
180
 
                    (req->be_ctx->domain->cache_credentials)) {
181
 
                    cache_auth_data = true;
182
 
                }
183
 
                break;
184
 
            case SSS_PAM_SETCRED:
185
 
                pam_status=pam_setcred(pamh, 0);
186
 
                break;
187
 
            case SSS_PAM_ACCT_MGMT:
188
 
                pam_status=pam_acct_mgmt(pamh, 0);
189
 
                break;
190
 
            case SSS_PAM_OPEN_SESSION:
191
 
                pam_status=pam_open_session(pamh, 0);
192
 
                break;
193
 
            case SSS_PAM_CLOSE_SESSION:
194
 
                pam_status=pam_close_session(pamh, 0);
195
 
                break;
196
 
            case SSS_PAM_CHAUTHTOK:
197
 
                if (pd->priv != 1) {
198
 
                    auth_data->authtok_size = pd->authtok_size;
199
 
                    auth_data->authtok = pd->authtok;
200
 
                    pam_status = pam_authenticate(pamh, 0);
201
 
                    if (pam_status != PAM_SUCCESS) break;
202
 
                }
203
 
                auth_data->authtok_size = pd->newauthtok_size;
204
 
                auth_data->authtok = pd->newauthtok;
205
 
                pam_status = pam_chauthtok(pamh, 0);
206
 
                if ((pam_status == PAM_SUCCESS) &&
207
 
                    (req->be_ctx->domain->cache_credentials)) {
208
 
                    cache_auth_data = true;
209
 
                }
210
 
                break;
211
 
            case SSS_PAM_CHAUTHTOK_PRELIM:
212
 
                if (pd->priv != 1) {
213
 
                    auth_data->authtok_size = pd->authtok_size;
214
 
                    auth_data->authtok = pd->authtok;
215
 
                    pam_status = pam_authenticate(pamh, 0);
216
 
                } else {
217
 
                    pam_status = PAM_SUCCESS;
218
 
                }
219
 
                break;
220
 
            default:
221
 
                DEBUG(1, ("unknown PAM call"));
222
 
                pam_status=PAM_ABORT;
223
 
        }
224
 
 
225
 
        DEBUG(4, ("Pam result: [%d][%s]\n", pam_status,
226
 
                  pam_strerror(pamh, pam_status)));
227
 
 
228
 
        if (pam_status == PAM_AUTHINFO_UNAVAIL) {
229
 
            be_mark_offline(req->be_ctx);
230
 
        }
231
 
 
232
 
        ret = pam_end(pamh, pam_status);
233
 
        if (ret != PAM_SUCCESS) {
234
 
            pamh=NULL;
235
 
            DEBUG(1, ("Cannot terminate pam transaction.\n"));
236
 
        }
237
 
 
238
 
    } else {
239
 
        DEBUG(1, ("Failed to initialize pam transaction.\n"));
240
 
        pam_status = PAM_SYSTEM_ERR;
241
 
    }
242
 
 
243
 
    pd->pam_status = pam_status;
244
 
 
245
 
    if (cache_auth_data) {
246
 
        struct tevent_req *subreq;
247
 
        char *password;
248
 
 
249
 
        password = talloc_size(req, auth_data->authtok_size + 1);
250
 
        if (!password) {
251
 
            /* password caching failures are not fatal errors */
252
 
            return proxy_reply(req, DP_ERR_OK, EOK, NULL);
253
 
        }
254
 
        memcpy(password, auth_data->authtok, auth_data->authtok_size);
255
 
        password[auth_data->authtok_size] = '\0';
256
 
        talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
257
 
 
258
 
        subreq = sysdb_cache_password_send(req, req->be_ctx->ev,
259
 
                                           req->be_ctx->sysdb, NULL,
260
 
                                           req->be_ctx->domain,
261
 
                                           pd->user, password);
262
 
        if (!subreq) {
263
 
            /* password caching failures are not fatal errors */
264
 
            return proxy_reply(req, DP_ERR_OK, EOK, NULL);
265
 
        }
266
 
        tevent_req_set_callback(subreq, proxy_pam_handler_cache_done, req);
267
 
    }
268
 
 
269
 
    proxy_reply(req, DP_ERR_OK, EOK, NULL);
270
 
}
271
 
 
272
 
static void proxy_pam_handler_cache_done(struct tevent_req *subreq)
273
 
{
274
 
    struct be_req *req = tevent_req_callback_data(subreq, struct be_req);
275
 
    int ret;
276
 
 
277
 
    /* password caching failures are not fatal errors */
278
 
    ret = sysdb_cache_password_recv(subreq);
279
 
    talloc_zfree(subreq);
280
 
 
281
 
    /* so we just log it any return */
282
 
    if (ret) {
283
 
        DEBUG(2, ("Failed to cache password (%d)[%s]!?\n",
284
 
                  ret, strerror(ret)));
285
 
    }
286
 
 
287
 
    return proxy_reply(req, DP_ERR_OK, EOK, NULL);
288
 
}
289
 
 
290
 
static void proxy_reply(struct be_req *req, int dp_err,
291
 
                        int error, const char *errstr)
292
 
{
293
 
    return req->fn(req, dp_err, error, errstr);
294
 
}
295
 
 
296
 
/* =Common-proxy-tevent_req-utils=========================================*/
297
 
 
298
 
#define DEFAULT_BUFSIZE 4096
299
 
#define MAX_BUF_SIZE 1024*1024 /* max 1MiB */
300
 
 
301
 
struct proxy_state {
302
 
    struct tevent_context *ev;
303
 
    struct proxy_ctx *ctx;
304
 
    struct sysdb_ctx *sysdb;
305
 
    struct sss_domain_info *domain;
306
 
    const char *name;
307
 
 
308
 
    struct sysdb_handle *handle;
309
 
    struct passwd *pwd;
310
 
    struct group *grp;
311
 
    uid_t uid;
312
 
    gid_t gid;
313
 
};
314
 
 
315
 
static void proxy_default_done(struct tevent_req *subreq)
316
 
{
317
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
318
 
                                                      struct tevent_req);
319
 
    int ret;
320
 
 
321
 
    ret = sysdb_transaction_commit_recv(subreq);
322
 
    talloc_zfree(subreq);
323
 
    if (ret) {
324
 
        tevent_req_error(req, ret);
325
 
        return;
326
 
    }
327
 
 
328
 
    tevent_req_done(req);
329
 
}
330
 
 
331
 
static int proxy_default_recv(struct tevent_req *req)
332
 
{
333
 
    TEVENT_REQ_RETURN_ON_ERROR(req);
334
 
 
335
 
    return EOK;
336
 
}
337
 
 
338
 
 
339
 
/* =Getpwnam-wrapper======================================================*/
340
 
 
341
 
static void get_pw_name_process(struct tevent_req *subreq);
342
 
static void get_pw_name_remove_done(struct tevent_req *subreq);
343
 
static void get_pw_name_add_done(struct tevent_req *subreq);
344
 
 
345
 
static struct tevent_req *get_pw_name_send(TALLOC_CTX *mem_ctx,
346
 
                                           struct tevent_context *ev,
347
 
                                           struct proxy_ctx *ctx,
348
 
                                           struct sysdb_ctx *sysdb,
349
 
                                           struct sss_domain_info *domain,
350
 
                                           const char *name)
351
 
{
352
 
    struct tevent_req *req, *subreq;
353
 
    struct proxy_state *state;
354
 
 
355
 
    req = tevent_req_create(mem_ctx, &state, struct proxy_state);
356
 
    if (!req) return NULL;
357
 
 
358
 
    memset(state, 0, sizeof(struct proxy_state));
359
 
 
360
 
    state->ev = ev;
361
 
    state->ctx = ctx;
362
 
    state->sysdb = sysdb;
363
 
    state->domain = domain;
364
 
    state->name = name;
365
 
 
366
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
367
 
    if (!subreq) {
368
 
        talloc_zfree(req);
369
 
        return NULL;
370
 
    }
371
 
    tevent_req_set_callback(subreq, get_pw_name_process, req);
372
 
 
373
 
    return req;
374
 
}
375
 
 
376
 
static void get_pw_name_process(struct tevent_req *subreq)
377
 
{
378
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
379
 
                                                      struct tevent_req);
380
 
    struct proxy_state *state = tevent_req_data(req,
381
 
                                                struct proxy_state);
382
 
    struct proxy_ctx *ctx = state->ctx;
383
 
    struct sss_domain_info *dom = ctx->be->domain;
384
 
    enum nss_status status;
385
 
    char *buffer;
386
 
    size_t buflen;
387
 
    bool delete_user = false;
388
 
    int ret;
389
 
 
390
 
    DEBUG(7, ("Searching user by name (%s)\n", state->name));
391
 
 
392
 
    ret = sysdb_transaction_recv(subreq, state, &state->handle);
393
 
    if (ret) {
394
 
        tevent_req_error(req, ret);
395
 
        return;
396
 
    }
397
 
    talloc_zfree(subreq);
398
 
 
399
 
    state->pwd = talloc(state, struct passwd);
400
 
    if (!state->pwd) {
401
 
        tevent_req_error(req, ENOMEM);
402
 
        return;
403
 
    }
404
 
 
405
 
    buflen = DEFAULT_BUFSIZE;
406
 
    buffer = talloc_size(state, buflen);
407
 
    if (!buffer) {
408
 
        tevent_req_error(req, ENOMEM);
409
 
        return;
410
 
    }
411
 
 
412
 
    /* FIXME: should we move this call outside the transaction to keep the
413
 
     * transaction as short as possible ? */
414
 
    status = ctx->ops.getpwnam_r(state->name, state->pwd,
415
 
                                 buffer, buflen, &ret);
416
 
 
417
 
    switch (status) {
418
 
    case NSS_STATUS_NOTFOUND:
419
 
 
420
 
        DEBUG(7, ("User %s not found.\n", state->name));
421
 
        delete_user = true;
422
 
        break;
423
 
 
424
 
    case NSS_STATUS_SUCCESS:
425
 
 
426
 
        DEBUG(7, ("User %s found: (%s, %d, %d)\n",
427
 
                  state->name, state->pwd->pw_name,
428
 
                  state->pwd->pw_uid, state->pwd->pw_gid));
429
 
 
430
 
        /* uid=0 or gid=0 are invalid values */
431
 
        /* also check that the id is in the valid range for this domain */
432
 
        if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
433
 
            OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
434
 
 
435
 
                DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
436
 
                          state->name));
437
 
            delete_user = true;
438
 
            break;
439
 
        }
440
 
 
441
 
        subreq = sysdb_store_user_send(state, state->ev, state->handle,
442
 
                                       state->domain,
443
 
                                       state->pwd->pw_name,
444
 
                                       state->pwd->pw_passwd,
445
 
                                       state->pwd->pw_uid,
446
 
                                       state->pwd->pw_gid,
447
 
                                       state->pwd->pw_gecos,
448
 
                                       state->pwd->pw_dir,
449
 
                                       state->pwd->pw_shell,
450
 
                                       NULL, ctx->entry_cache_timeout);
451
 
        if (!subreq) {
452
 
            tevent_req_error(req, ENOMEM);
453
 
            return;
454
 
        }
455
 
        tevent_req_set_callback(subreq, get_pw_name_add_done, req);
456
 
        return;
457
 
 
458
 
    case NSS_STATUS_UNAVAIL:
459
 
        /* "remote" backend unavailable. Enter offline mode */
460
 
        tevent_req_error(req, ENXIO);
461
 
        return;
462
 
 
463
 
    default:
464
 
        DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
465
 
                  state->name, status));
466
 
        tevent_req_error(req, EIO);
467
 
        return;
468
 
    }
469
 
 
470
 
    if (delete_user) {
471
 
        struct ldb_dn *dn;
472
 
 
473
 
        DEBUG(7, ("User %s does not exist (or is invalid) on remote server,"
474
 
                  " deleting!\n", state->name));
475
 
 
476
 
        dn = sysdb_user_dn(state->sysdb, state,
477
 
                           state->domain->name, state->name);
478
 
        if (!dn) {
479
 
            tevent_req_error(req, ENOMEM);
480
 
            return;
481
 
        }
482
 
 
483
 
        subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
484
 
        if (!subreq) {
485
 
            tevent_req_error(req, ENOMEM);
486
 
            return;
487
 
        }
488
 
        tevent_req_set_callback(subreq, get_pw_name_remove_done, req);
489
 
    }
490
 
}
491
 
 
492
 
static void get_pw_name_add_done(struct tevent_req *subreq)
493
 
{
494
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
495
 
                                                      struct tevent_req);
496
 
    struct proxy_state *state = tevent_req_data(req,
497
 
                                                struct proxy_state);
498
 
    int ret;
499
 
 
500
 
    ret = sysdb_store_user_recv(subreq);
501
 
    talloc_zfree(subreq);
502
 
    if (ret) {
503
 
        tevent_req_error(req, ret);
504
 
        return;
505
 
    }
506
 
 
507
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
508
 
    if (!subreq) {
509
 
        tevent_req_error(req, ENOMEM);
510
 
        return;
511
 
    }
512
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
513
 
}
514
 
 
515
 
static void get_pw_name_remove_done(struct tevent_req *subreq)
516
 
{
517
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
518
 
                                                      struct tevent_req);
519
 
    struct proxy_state *state = tevent_req_data(req,
520
 
                                                struct proxy_state);
521
 
    int ret;
522
 
 
523
 
    ret = sysdb_delete_entry_recv(subreq);
524
 
    talloc_zfree(subreq);
525
 
    if (ret) {
526
 
        tevent_req_error(req, ret);
527
 
        return;
528
 
    }
529
 
 
530
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
531
 
    if (!subreq) {
532
 
        tevent_req_error(req, ENOMEM);
533
 
        return;
534
 
    }
535
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
536
 
}
537
 
 
538
 
/* =Getpwuid-wrapper======================================================*/
539
 
 
540
 
static void get_pw_uid_process(struct tevent_req *subreq);
541
 
static void get_pw_uid_remove_done(struct tevent_req *subreq);
542
 
 
543
 
static struct tevent_req *get_pw_uid_send(TALLOC_CTX *mem_ctx,
544
 
                                           struct tevent_context *ev,
545
 
                                           struct proxy_ctx *ctx,
546
 
                                           struct sysdb_ctx *sysdb,
547
 
                                           struct sss_domain_info *domain,
548
 
                                           uid_t uid)
549
 
{
550
 
    struct tevent_req *req, *subreq;
551
 
    struct proxy_state *state;
552
 
 
553
 
    req = tevent_req_create(mem_ctx, &state, struct proxy_state);
554
 
    if (!req) return NULL;
555
 
 
556
 
    memset(state, 0, sizeof(struct proxy_state));
557
 
 
558
 
    state->ev = ev;
559
 
    state->ctx = ctx;
560
 
    state->sysdb = sysdb;
561
 
    state->domain = domain;
562
 
    state->uid = uid;
563
 
 
564
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
565
 
    if (!subreq) {
566
 
        talloc_zfree(req);
567
 
        return NULL;
568
 
    }
569
 
    tevent_req_set_callback(subreq, get_pw_uid_process, req);
570
 
 
571
 
    return req;
572
 
}
573
 
 
574
 
static void get_pw_uid_process(struct tevent_req *subreq)
575
 
{
576
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
577
 
                                                      struct tevent_req);
578
 
    struct proxy_state *state = tevent_req_data(req,
579
 
                                                struct proxy_state);
580
 
    struct proxy_ctx *ctx = state->ctx;
581
 
    struct sss_domain_info *dom = ctx->be->domain;
582
 
    enum nss_status status;
583
 
    char *buffer;
584
 
    size_t buflen;
585
 
    bool delete_user = false;
586
 
    int ret;
587
 
 
588
 
    DEBUG(7, ("Searching user by uid (%d)\n", state->uid));
589
 
 
590
 
    ret = sysdb_transaction_recv(subreq, state, &state->handle);
591
 
    if (ret) {
592
 
        tevent_req_error(req, ret);
593
 
        return;
594
 
    }
595
 
    talloc_zfree(subreq);
596
 
 
597
 
    state->pwd = talloc(state, struct passwd);
598
 
    if (!state->pwd) {
599
 
        tevent_req_error(req, ENOMEM);
600
 
        return;
601
 
    }
602
 
 
603
 
    buflen = DEFAULT_BUFSIZE;
604
 
    buffer = talloc_size(state, buflen);
605
 
    if (!buffer) {
606
 
        tevent_req_error(req, ENOMEM);
607
 
        return;
608
 
    }
609
 
 
610
 
    /* always zero out the pwd structure */
611
 
    memset(state->pwd, 0, sizeof(struct passwd));
612
 
 
613
 
    status = ctx->ops.getpwuid_r(state->uid, state->pwd,
614
 
                                 buffer, buflen, &ret);
615
 
 
616
 
    switch (status) {
617
 
    case NSS_STATUS_NOTFOUND:
618
 
 
619
 
        DEBUG(7, ("User %d not found.\n", state->uid));
620
 
        delete_user = true;
621
 
        break;
622
 
 
623
 
    case NSS_STATUS_SUCCESS:
624
 
 
625
 
        DEBUG(7, ("User %d found (%s, %d, %d)\n",
626
 
                  state->uid, state->pwd->pw_name,
627
 
                  state->pwd->pw_uid, state->pwd->pw_gid));
628
 
 
629
 
        /* uid=0 or gid=0 are invalid values */
630
 
        /* also check that the id is in the valid range for this domain */
631
 
        if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
632
 
            OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
633
 
 
634
 
                DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
635
 
                          state->name));
636
 
            delete_user = true;
637
 
            break;
638
 
        }
639
 
 
640
 
        subreq = sysdb_store_user_send(state, state->ev, state->handle,
641
 
                                       state->domain,
642
 
                                       state->pwd->pw_name,
643
 
                                       state->pwd->pw_passwd,
644
 
                                       state->pwd->pw_uid,
645
 
                                       state->pwd->pw_gid,
646
 
                                       state->pwd->pw_gecos,
647
 
                                       state->pwd->pw_dir,
648
 
                                       state->pwd->pw_shell,
649
 
                                       NULL, ctx->entry_cache_timeout);
650
 
        if (!subreq) {
651
 
            tevent_req_error(req, ENOMEM);
652
 
            return;
653
 
        }
654
 
        tevent_req_set_callback(subreq, get_pw_name_add_done, req);
655
 
        return;
656
 
 
657
 
    case NSS_STATUS_UNAVAIL:
658
 
        /* "remote" backend unavailable. Enter offline mode */
659
 
        tevent_req_error(req, ENXIO);
660
 
        return;
661
 
 
662
 
    default:
663
 
        DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
664
 
                  state->name, status));
665
 
        tevent_req_error(req, EIO);
666
 
        return;
667
 
    }
668
 
 
669
 
    if (delete_user) {
670
 
        DEBUG(7, ("User %d does not exist (or is invalid) on remote server,"
671
 
                  " deleting!\n", state->uid));
672
 
 
673
 
        subreq = sysdb_delete_user_send(state, state->ev,
674
 
                                        NULL, state->handle,
675
 
                                        state->domain,
676
 
                                        NULL, state->uid);
677
 
        if (!subreq) {
678
 
            tevent_req_error(req, ENOMEM);
679
 
            return;
680
 
        }
681
 
        tevent_req_set_callback(subreq, get_pw_uid_remove_done, req);
682
 
    }
683
 
}
684
 
 
685
 
static void get_pw_uid_remove_done(struct tevent_req *subreq)
686
 
{
687
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
688
 
                                                      struct tevent_req);
689
 
    struct proxy_state *state = tevent_req_data(req,
690
 
                                                struct proxy_state);
691
 
    int ret;
692
 
 
693
 
    ret = sysdb_delete_user_recv(subreq);
694
 
    talloc_zfree(subreq);
695
 
    if (ret && ret != ENOENT) {
696
 
        tevent_req_error(req, ret);
697
 
        return;
698
 
    }
699
 
 
700
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
701
 
    if (!subreq) {
702
 
        tevent_req_error(req, ENOMEM);
703
 
        return;
704
 
    }
705
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
706
 
}
707
 
 
708
 
/* =Getpwent-wrapper======================================================*/
709
 
 
710
 
struct enum_users_state {
711
 
    struct tevent_context *ev;
712
 
    struct proxy_ctx *ctx;
713
 
    struct sysdb_ctx *sysdb;
714
 
    struct sss_domain_info *domain;
715
 
    struct sysdb_handle *handle;
716
 
 
717
 
    struct passwd *pwd;
718
 
 
719
 
    size_t buflen;
720
 
    char *buffer;
721
 
 
722
 
    bool in_transaction;
723
 
};
724
 
 
725
 
static void enum_users_process(struct tevent_req *subreq);
726
 
 
727
 
static struct tevent_req *enum_users_send(TALLOC_CTX *mem_ctx,
728
 
                                          struct tevent_context *ev,
729
 
                                          struct proxy_ctx *ctx,
730
 
                                          struct sysdb_ctx *sysdb,
731
 
                                          struct sss_domain_info *domain)
732
 
{
733
 
    struct tevent_req *req, *subreq;
734
 
    struct enum_users_state *state;
735
 
    enum nss_status status;
736
 
 
737
 
    DEBUG(7, ("Enumerating users\n"));
738
 
 
739
 
    req = tevent_req_create(mem_ctx, &state, struct enum_users_state);
740
 
    if (!req) return NULL;
741
 
 
742
 
    state->ev = ev;
743
 
    state->ctx = ctx;
744
 
    state->sysdb = sysdb;
745
 
    state->domain = domain;
746
 
    state->handle = NULL;
747
 
 
748
 
    state->pwd = talloc(state, struct passwd);
749
 
    if (!state->pwd) {
750
 
        tevent_req_error(req, ENOMEM);
751
 
        goto fail;
752
 
    }
753
 
 
754
 
    state->buflen = DEFAULT_BUFSIZE;
755
 
    state->buffer = talloc_size(state, state->buflen);
756
 
    if (!state->buffer) {
757
 
        tevent_req_error(req, ENOMEM);
758
 
        goto fail;
759
 
    }
760
 
 
761
 
    state->in_transaction = false;
762
 
 
763
 
    status = ctx->ops.setpwent();
764
 
    if (status != NSS_STATUS_SUCCESS) {
765
 
        tevent_req_error(req, EIO);
766
 
        goto fail;
767
 
    }
768
 
 
769
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
770
 
    if (!subreq) {
771
 
        tevent_req_error(req, ENOMEM);
772
 
        goto fail;
773
 
    }
774
 
    tevent_req_set_callback(subreq, enum_users_process, req);
775
 
 
776
 
    return req;
777
 
 
778
 
fail:
779
 
    tevent_req_post(req, ev);
780
 
    return req;
781
 
}
782
 
 
783
 
static void enum_users_process(struct tevent_req *subreq)
784
 
{
785
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
786
 
                                                      struct tevent_req);
787
 
    struct enum_users_state *state = tevent_req_data(req,
788
 
                                                struct enum_users_state);
789
 
    struct proxy_ctx *ctx = state->ctx;
790
 
    struct sss_domain_info *dom = ctx->be->domain;
791
 
    enum nss_status status;
792
 
    char *newbuf;
793
 
    int ret;
794
 
 
795
 
    if (!state->in_transaction) {
796
 
        ret = sysdb_transaction_recv(subreq, state, &state->handle);
797
 
        if (ret) {
798
 
            goto fail;
799
 
        }
800
 
        talloc_zfree(subreq);
801
 
 
802
 
        state->in_transaction = true;
803
 
    } else {
804
 
        ret = sysdb_store_user_recv(subreq);
805
 
        if (ret) {
806
 
            /* Do not fail completely on errors.
807
 
             * Just report the failure to save and go on */
808
 
            DEBUG(2, ("Failed to store user. Ignoring.\n"));
809
 
        }
810
 
        talloc_zfree(subreq);
811
 
    }
812
 
 
813
 
again:
814
 
    /* always zero out the pwd structure */
815
 
    memset(state->pwd, 0, sizeof(struct passwd));
816
 
 
817
 
    /* get entry */
818
 
    status = ctx->ops.getpwent_r(state->pwd,
819
 
                                 state->buffer, state->buflen, &ret);
820
 
 
821
 
    switch (status) {
822
 
    case NSS_STATUS_TRYAGAIN:
823
 
        /* buffer too small ? */
824
 
        if (state->buflen < MAX_BUF_SIZE) {
825
 
            state->buflen *= 2;
826
 
        }
827
 
        if (state->buflen > MAX_BUF_SIZE) {
828
 
            state->buflen = MAX_BUF_SIZE;
829
 
        }
830
 
        newbuf = talloc_realloc_size(state, state->buffer, state->buflen);
831
 
        if (!newbuf) {
832
 
            ret = ENOMEM;
833
 
            goto fail;
834
 
        }
835
 
        state->buffer = newbuf;
836
 
        goto again;
837
 
 
838
 
    case NSS_STATUS_NOTFOUND:
839
 
 
840
 
        /* we are done here */
841
 
        DEBUG(7, ("Enumeration completed.\n"));
842
 
 
843
 
        ctx->ops.endpwent();
844
 
        subreq = sysdb_transaction_commit_send(state, state->ev,
845
 
                                               state->handle);
846
 
        if (!subreq) {
847
 
            tevent_req_error(req, ENOMEM);
848
 
            return;
849
 
        }
850
 
        tevent_req_set_callback(subreq, proxy_default_done, req);
851
 
        return;
852
 
 
853
 
    case NSS_STATUS_SUCCESS:
854
 
 
855
 
        DEBUG(7, ("User found (%s, %d, %d)\n", state->pwd->pw_name,
856
 
                  state->pwd->pw_uid, state->pwd->pw_gid));
857
 
 
858
 
        /* uid=0 or gid=0 are invalid values */
859
 
        /* also check that the id is in the valid range for this domain */
860
 
        if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
861
 
            OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
862
 
 
863
 
                DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
864
 
                          state->pwd->pw_name));
865
 
 
866
 
            goto again; /* skip */
867
 
        }
868
 
 
869
 
        subreq = sysdb_store_user_send(state, state->ev, state->handle,
870
 
                                       state->domain,
871
 
                                       state->pwd->pw_name,
872
 
                                       state->pwd->pw_passwd,
873
 
                                       state->pwd->pw_uid,
874
 
                                       state->pwd->pw_gid,
875
 
                                       state->pwd->pw_gecos,
876
 
                                       state->pwd->pw_dir,
877
 
                                       state->pwd->pw_shell,
878
 
                                       NULL, ctx->entry_cache_timeout);
879
 
        if (!subreq) {
880
 
            tevent_req_error(req, ENOMEM);
881
 
            return;
882
 
        }
883
 
        tevent_req_set_callback(subreq, enum_users_process, req);
884
 
        return;
885
 
 
886
 
    case NSS_STATUS_UNAVAIL:
887
 
        /* "remote" backend unavailable. Enter offline mode */
888
 
        ret = ENXIO;
889
 
        goto fail;
890
 
 
891
 
    default:
892
 
        DEBUG(2, ("proxy -> getpwent_r failed (%d)[%s]\n",
893
 
                  ret, strerror(ret)));
894
 
        goto fail;
895
 
    }
896
 
 
897
 
fail:
898
 
    ctx->ops.endpwent();
899
 
    tevent_req_error(req, ret);
900
 
}
901
 
 
902
 
/* =Getgrnam-wrapper======================================================*/
903
 
 
904
 
#define DEBUG_GR_MEM(level, state) \
905
 
    do { \
906
 
        if (debug_level >= level) { \
907
 
            if (!state->grp->gr_mem || !state->grp->gr_mem[0]) { \
908
 
                DEBUG(level, ("Group %s has no members!\n", \
909
 
                              state->grp->gr_name)); \
910
 
            } else { \
911
 
                int i = 0; \
912
 
                while (state->grp->gr_mem[i]) { \
913
 
                    /* count */ \
914
 
                    i++; \
915
 
                } \
916
 
                DEBUG(level, ("Group %s has %d members!\n", \
917
 
                              state->grp->gr_name, i)); \
918
 
            } \
919
 
        } \
920
 
    } while(0)
921
 
 
922
 
static void get_gr_name_process(struct tevent_req *subreq);
923
 
static void get_gr_name_remove_done(struct tevent_req *subreq);
924
 
static void get_gr_name_add_done(struct tevent_req *subreq);
925
 
 
926
 
static struct tevent_req *get_gr_name_send(TALLOC_CTX *mem_ctx,
927
 
                                           struct tevent_context *ev,
928
 
                                           struct proxy_ctx *ctx,
929
 
                                           struct sysdb_ctx *sysdb,
930
 
                                           struct sss_domain_info *domain,
931
 
                                           const char *name)
932
 
{
933
 
    struct tevent_req *req, *subreq;
934
 
    struct proxy_state *state;
935
 
 
936
 
    req = tevent_req_create(mem_ctx, &state, struct proxy_state);
937
 
    if (!req) return NULL;
938
 
 
939
 
    memset(state, 0, sizeof(struct proxy_state));
940
 
 
941
 
    state->ev = ev;
942
 
    state->ctx = ctx;
943
 
    state->sysdb = sysdb;
944
 
    state->domain = domain;
945
 
    state->name = name;
946
 
 
947
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
948
 
    if (!subreq) {
949
 
        talloc_zfree(req);
950
 
        return NULL;
951
 
    }
952
 
    tevent_req_set_callback(subreq, get_gr_name_process, req);
953
 
 
954
 
    return req;
955
 
}
956
 
 
957
 
static void get_gr_name_process(struct tevent_req *subreq)
958
 
{
959
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
960
 
                                                      struct tevent_req);
961
 
    struct proxy_state *state = tevent_req_data(req,
962
 
                                                struct proxy_state);
963
 
    struct proxy_ctx *ctx = state->ctx;
964
 
    struct sss_domain_info *dom = ctx->be->domain;
965
 
    enum nss_status status;
966
 
    char *buffer;
967
 
    char *newbuf;
968
 
    size_t buflen;
969
 
    bool delete_group = false;
970
 
    struct sysdb_attrs *members;
971
 
    int ret;
972
 
 
973
 
    DEBUG(7, ("Searching group by name (%s)\n", state->name));
974
 
 
975
 
    ret = sysdb_transaction_recv(subreq, state, &state->handle);
976
 
    if (ret) {
977
 
        tevent_req_error(req, ret);
978
 
        return;
979
 
    }
980
 
    talloc_zfree(subreq);
981
 
 
982
 
    state->grp = talloc(state, struct group);
983
 
    if (!state->grp) {
984
 
        tevent_req_error(req, ENOMEM);
985
 
        return;
986
 
    }
987
 
 
988
 
    buflen = DEFAULT_BUFSIZE;
989
 
    buffer = talloc_size(state, buflen);
990
 
    if (!buffer) {
991
 
        tevent_req_error(req, ENOMEM);
992
 
        return;
993
 
    }
994
 
 
995
 
    /* FIXME: should we move this call outside the transaction to keep the
996
 
     * transaction as short as possible ? */
997
 
again:
998
 
    /* always zero out the grp structure */
999
 
    memset(state->grp, 0, sizeof(struct group));
1000
 
 
1001
 
    status = ctx->ops.getgrnam_r(state->name, state->grp,
1002
 
                                 buffer, buflen, &ret);
1003
 
 
1004
 
    switch (status) {
1005
 
    case NSS_STATUS_TRYAGAIN:
1006
 
        /* buffer too small ? */
1007
 
        if (buflen < MAX_BUF_SIZE) {
1008
 
            buflen *= 2;
1009
 
        }
1010
 
        if (buflen > MAX_BUF_SIZE) {
1011
 
            buflen = MAX_BUF_SIZE;
1012
 
        }
1013
 
        newbuf = talloc_realloc_size(state, buffer, buflen);
1014
 
        if (!newbuf) {
1015
 
            tevent_req_error(req, ENOMEM);
1016
 
            return;
1017
 
        }
1018
 
        buffer = newbuf;
1019
 
        goto again;
1020
 
 
1021
 
    case NSS_STATUS_NOTFOUND:
1022
 
 
1023
 
        DEBUG(7, ("Group %s not found.\n", state->name));
1024
 
        delete_group = true;
1025
 
        break;
1026
 
 
1027
 
    case NSS_STATUS_SUCCESS:
1028
 
 
1029
 
        DEBUG(7, ("Group %s found: (%s, %d)\n", state->name,
1030
 
                  state->grp->gr_name, state->grp->gr_gid));
1031
 
 
1032
 
        /* gid=0 is an invalid value */
1033
 
        /* also check that the id is in the valid range for this domain */
1034
 
        if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1035
 
 
1036
 
                DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1037
 
                          state->name));
1038
 
            delete_group = true;
1039
 
            break;
1040
 
        }
1041
 
 
1042
 
        DEBUG_GR_MEM(7, state);
1043
 
 
1044
 
        if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1045
 
            members = sysdb_new_attrs(state);
1046
 
            if (!members) {
1047
 
                tevent_req_error(req, ENOMEM);
1048
 
                return;
1049
 
            }
1050
 
            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1051
 
                                                  state->domain->name,
1052
 
                                                  (const char **)state->grp->gr_mem);
1053
 
            if (ret) {
1054
 
                tevent_req_error(req, ret);
1055
 
                return;
1056
 
            }
1057
 
        } else {
1058
 
            members = NULL;
1059
 
        }
1060
 
 
1061
 
        subreq = sysdb_store_group_send(state, state->ev, state->handle,
1062
 
                                        state->domain,
1063
 
                                        state->grp->gr_name,
1064
 
                                        state->grp->gr_gid,
1065
 
                                        members,
1066
 
                                        ctx->entry_cache_timeout);
1067
 
        if (!subreq) {
1068
 
            tevent_req_error(req, ENOMEM);
1069
 
            return;
1070
 
        }
1071
 
        tevent_req_set_callback(subreq, get_gr_name_add_done, req);
1072
 
        return;
1073
 
 
1074
 
    case NSS_STATUS_UNAVAIL:
1075
 
        /* "remote" backend unavailable. Enter offline mode */
1076
 
        tevent_req_error(req, ENXIO);
1077
 
        return;
1078
 
 
1079
 
    default:
1080
 
        DEBUG(2, ("proxy -> getgrnam_r failed for '%s' <%d>\n",
1081
 
                  state->name, status));
1082
 
        tevent_req_error(req, EIO);
1083
 
        return;
1084
 
    }
1085
 
 
1086
 
    if (delete_group) {
1087
 
        struct ldb_dn *dn;
1088
 
 
1089
 
        DEBUG(7, ("Group %s does not exist (or is invalid) on remote server,"
1090
 
                  " deleting!\n", state->name));
1091
 
 
1092
 
        dn = sysdb_group_dn(state->sysdb, state,
1093
 
                            state->domain->name, state->name);
1094
 
        if (!dn) {
1095
 
            tevent_req_error(req, ENOMEM);
1096
 
            return;
1097
 
        }
1098
 
 
1099
 
        subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
1100
 
        if (!subreq) {
1101
 
            tevent_req_error(req, ENOMEM);
1102
 
            return;
1103
 
        }
1104
 
        tevent_req_set_callback(subreq, get_gr_name_remove_done, req);
1105
 
    }
1106
 
}
1107
 
 
1108
 
static void get_gr_name_add_done(struct tevent_req *subreq)
1109
 
{
1110
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1111
 
                                                      struct tevent_req);
1112
 
    struct proxy_state *state = tevent_req_data(req,
1113
 
                                                struct proxy_state);
1114
 
    int ret;
1115
 
 
1116
 
    ret = sysdb_store_group_recv(subreq);
1117
 
    talloc_zfree(subreq);
1118
 
    if (ret) {
1119
 
        tevent_req_error(req, ret);
1120
 
        return;
1121
 
    }
1122
 
 
1123
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1124
 
    if (!subreq) {
1125
 
        tevent_req_error(req, ENOMEM);
1126
 
        return;
1127
 
    }
1128
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
1129
 
}
1130
 
 
1131
 
static void get_gr_name_remove_done(struct tevent_req *subreq)
1132
 
{
1133
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1134
 
                                                      struct tevent_req);
1135
 
    struct proxy_state *state = tevent_req_data(req,
1136
 
                                                struct proxy_state);
1137
 
    int ret;
1138
 
 
1139
 
    ret = sysdb_delete_entry_recv(subreq);
1140
 
    talloc_zfree(subreq);
1141
 
    if (ret) {
1142
 
        tevent_req_error(req, ret);
1143
 
        return;
1144
 
    }
1145
 
 
1146
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1147
 
    if (!subreq) {
1148
 
        tevent_req_error(req, ENOMEM);
1149
 
        return;
1150
 
    }
1151
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
1152
 
}
1153
 
 
1154
 
/* =Getgrgid-wrapper======================================================*/
1155
 
 
1156
 
static void get_gr_gid_process(struct tevent_req *subreq);
1157
 
static void get_gr_gid_remove_done(struct tevent_req *subreq);
1158
 
 
1159
 
static struct tevent_req *get_gr_gid_send(TALLOC_CTX *mem_ctx,
1160
 
                                           struct tevent_context *ev,
1161
 
                                           struct proxy_ctx *ctx,
1162
 
                                           struct sysdb_ctx *sysdb,
1163
 
                                           struct sss_domain_info *domain,
1164
 
                                           gid_t gid)
1165
 
{
1166
 
    struct tevent_req *req, *subreq;
1167
 
    struct proxy_state *state;
1168
 
 
1169
 
    req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1170
 
    if (!req) return NULL;
1171
 
 
1172
 
    memset(state, 0, sizeof(struct proxy_state));
1173
 
 
1174
 
    state->ev = ev;
1175
 
    state->ctx = ctx;
1176
 
    state->sysdb = sysdb;
1177
 
    state->domain = domain;
1178
 
    state->gid = gid;
1179
 
 
1180
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1181
 
    if (!subreq) {
1182
 
        talloc_zfree(req);
1183
 
        return NULL;
1184
 
    }
1185
 
    tevent_req_set_callback(subreq, get_gr_gid_process, req);
1186
 
 
1187
 
    return req;
1188
 
}
1189
 
 
1190
 
static void get_gr_gid_process(struct tevent_req *subreq)
1191
 
{
1192
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1193
 
                                                      struct tevent_req);
1194
 
    struct proxy_state *state = tevent_req_data(req,
1195
 
                                                struct proxy_state);
1196
 
    struct proxy_ctx *ctx = state->ctx;
1197
 
    struct sss_domain_info *dom = ctx->be->domain;
1198
 
    enum nss_status status;
1199
 
    char *buffer;
1200
 
    char *newbuf;
1201
 
    size_t buflen;
1202
 
    bool delete_group = false;
1203
 
    struct sysdb_attrs *members;
1204
 
    int ret;
1205
 
 
1206
 
    DEBUG(7, ("Searching group by gid (%d)\n", state->gid));
1207
 
 
1208
 
    ret = sysdb_transaction_recv(subreq, state, &state->handle);
1209
 
    if (ret) {
1210
 
        tevent_req_error(req, ret);
1211
 
        return;
1212
 
    }
1213
 
    talloc_zfree(subreq);
1214
 
 
1215
 
    state->grp = talloc(state, struct group);
1216
 
    if (!state->grp) {
1217
 
        tevent_req_error(req, ENOMEM);
1218
 
        return;
1219
 
    }
1220
 
 
1221
 
    buflen = DEFAULT_BUFSIZE;
1222
 
    buffer = talloc_size(state, buflen);
1223
 
    if (!buffer) {
1224
 
        tevent_req_error(req, ENOMEM);
1225
 
        return;
1226
 
    }
1227
 
 
1228
 
again:
1229
 
    /* always zero out the group structure */
1230
 
    memset(state->grp, 0, sizeof(struct group));
1231
 
 
1232
 
    status = ctx->ops.getgrgid_r(state->gid, state->grp,
1233
 
                                 buffer, buflen, &ret);
1234
 
 
1235
 
    switch (status) {
1236
 
    case NSS_STATUS_TRYAGAIN:
1237
 
        /* buffer too small ? */
1238
 
        if (buflen < MAX_BUF_SIZE) {
1239
 
            buflen *= 2;
1240
 
        }
1241
 
        if (buflen > MAX_BUF_SIZE) {
1242
 
            buflen = MAX_BUF_SIZE;
1243
 
        }
1244
 
        newbuf = talloc_realloc_size(state, buffer, buflen);
1245
 
        if (!newbuf) {
1246
 
            tevent_req_error(req, ENOMEM);
1247
 
            return;
1248
 
        }
1249
 
        buffer = newbuf;
1250
 
        goto again;
1251
 
 
1252
 
    case NSS_STATUS_NOTFOUND:
1253
 
 
1254
 
        DEBUG(7, ("Group %d not found.\n", state->gid));
1255
 
        delete_group = true;
1256
 
        break;
1257
 
 
1258
 
    case NSS_STATUS_SUCCESS:
1259
 
 
1260
 
        DEBUG(7, ("Group %d found (%s, %d)\n", state->gid,
1261
 
                  state->grp->gr_name, state->grp->gr_gid));
1262
 
 
1263
 
        /* gid=0 is an invalid value */
1264
 
        /* also check that the id is in the valid range for this domain */
1265
 
        if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1266
 
 
1267
 
                DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1268
 
                          state->grp->gr_name));
1269
 
            delete_group = true;
1270
 
            break;
1271
 
        }
1272
 
 
1273
 
        DEBUG_GR_MEM(7, state);
1274
 
 
1275
 
        if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1276
 
            members = sysdb_new_attrs(state);
1277
 
            if (!members) {
1278
 
                tevent_req_error(req, ENOMEM);
1279
 
                return;
1280
 
            }
1281
 
            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1282
 
                                                  state->domain->name,
1283
 
                                                  (const char **)state->grp->gr_mem);
1284
 
            if (ret) {
1285
 
                tevent_req_error(req, ret);
1286
 
                return;
1287
 
            }
1288
 
        } else {
1289
 
            members = NULL;
1290
 
        }
1291
 
 
1292
 
        subreq = sysdb_store_group_send(state, state->ev, state->handle,
1293
 
                                        state->domain,
1294
 
                                        state->grp->gr_name,
1295
 
                                        state->grp->gr_gid,
1296
 
                                        members,
1297
 
                                        ctx->entry_cache_timeout);
1298
 
        if (!subreq) {
1299
 
            tevent_req_error(req, ENOMEM);
1300
 
            return;
1301
 
        }
1302
 
        tevent_req_set_callback(subreq, get_gr_name_add_done, req);
1303
 
        return;
1304
 
 
1305
 
    case NSS_STATUS_UNAVAIL:
1306
 
        /* "remote" backend unavailable. Enter offline mode */
1307
 
        tevent_req_error(req, ENXIO);
1308
 
        return;
1309
 
 
1310
 
    default:
1311
 
        DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n",
1312
 
                  state->gid, status));
1313
 
        tevent_req_error(req, EIO);
1314
 
        return;
1315
 
    }
1316
 
 
1317
 
    if (delete_group) {
1318
 
 
1319
 
        DEBUG(7, ("Group %d does not exist (or is invalid) on remote server,"
1320
 
                  " deleting!\n", state->gid));
1321
 
 
1322
 
        subreq = sysdb_delete_group_send(state, state->ev,
1323
 
                                         NULL, state->handle,
1324
 
                                         state->domain,
1325
 
                                         NULL, state->gid);
1326
 
        if (!subreq) {
1327
 
            tevent_req_error(req, ENOMEM);
1328
 
            return;
1329
 
        }
1330
 
        tevent_req_set_callback(subreq, get_gr_gid_remove_done, req);
1331
 
    }
1332
 
}
1333
 
 
1334
 
static void get_gr_gid_remove_done(struct tevent_req *subreq)
1335
 
{
1336
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1337
 
                                                      struct tevent_req);
1338
 
    struct proxy_state *state = tevent_req_data(req,
1339
 
                                                struct proxy_state);
1340
 
    int ret;
1341
 
 
1342
 
    ret = sysdb_delete_group_recv(subreq);
1343
 
    talloc_zfree(subreq);
1344
 
    if (ret && ret != ENOENT) {
1345
 
        tevent_req_error(req, ret);
1346
 
        return;
1347
 
    }
1348
 
 
1349
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1350
 
    if (!subreq) {
1351
 
        tevent_req_error(req, ENOMEM);
1352
 
        return;
1353
 
    }
1354
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
1355
 
}
1356
 
 
1357
 
/* =Getgrent-wrapper======================================================*/
1358
 
 
1359
 
struct enum_groups_state {
1360
 
    struct tevent_context *ev;
1361
 
    struct proxy_ctx *ctx;
1362
 
    struct sysdb_ctx *sysdb;
1363
 
    struct sss_domain_info *domain;
1364
 
    struct sysdb_handle *handle;
1365
 
 
1366
 
    struct group *grp;
1367
 
 
1368
 
    size_t buflen;
1369
 
    char *buffer;
1370
 
 
1371
 
    bool in_transaction;
1372
 
};
1373
 
 
1374
 
static void enum_groups_process(struct tevent_req *subreq);
1375
 
 
1376
 
static struct tevent_req *enum_groups_send(TALLOC_CTX *mem_ctx,
1377
 
                                          struct tevent_context *ev,
1378
 
                                          struct proxy_ctx *ctx,
1379
 
                                          struct sysdb_ctx *sysdb,
1380
 
                                          struct sss_domain_info *domain)
1381
 
{
1382
 
    struct tevent_req *req, *subreq;
1383
 
    struct enum_groups_state *state;
1384
 
    enum nss_status status;
1385
 
 
1386
 
    DEBUG(7, ("Enumerating groups\n"));
1387
 
 
1388
 
    req = tevent_req_create(mem_ctx, &state, struct enum_groups_state);
1389
 
    if (!req) return NULL;
1390
 
 
1391
 
    state->ev = ev;
1392
 
    state->ctx = ctx;
1393
 
    state->sysdb = sysdb;
1394
 
    state->domain = domain;
1395
 
    state->handle = NULL;
1396
 
 
1397
 
    state->grp = talloc(state, struct group);
1398
 
    if (!state->grp) {
1399
 
        tevent_req_error(req, ENOMEM);
1400
 
        goto fail;
1401
 
    }
1402
 
 
1403
 
    state->buflen = DEFAULT_BUFSIZE;
1404
 
    state->buffer = talloc_size(state, state->buflen);
1405
 
    if (!state->buffer) {
1406
 
        tevent_req_error(req, ENOMEM);
1407
 
        goto fail;
1408
 
    }
1409
 
 
1410
 
    state->in_transaction = false;
1411
 
 
1412
 
    status = ctx->ops.setgrent();
1413
 
    if (status != NSS_STATUS_SUCCESS) {
1414
 
        tevent_req_error(req, EIO);
1415
 
        goto fail;
1416
 
    }
1417
 
 
1418
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1419
 
    if (!subreq) {
1420
 
        tevent_req_error(req, ENOMEM);
1421
 
        goto fail;
1422
 
    }
1423
 
    tevent_req_set_callback(subreq, enum_groups_process, req);
1424
 
 
1425
 
    return req;
1426
 
 
1427
 
fail:
1428
 
    tevent_req_post(req, ev);
1429
 
    return req;
1430
 
}
1431
 
 
1432
 
static void enum_groups_process(struct tevent_req *subreq)
1433
 
{
1434
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1435
 
                                                      struct tevent_req);
1436
 
    struct enum_groups_state *state = tevent_req_data(req,
1437
 
                                                struct enum_groups_state);
1438
 
    struct proxy_ctx *ctx = state->ctx;
1439
 
    struct sss_domain_info *dom = ctx->be->domain;
1440
 
    enum nss_status status;
1441
 
    struct sysdb_attrs *members;
1442
 
    char *newbuf;
1443
 
    int ret;
1444
 
 
1445
 
    if (!state->in_transaction) {
1446
 
        ret = sysdb_transaction_recv(subreq, state, &state->handle);
1447
 
        if (ret) {
1448
 
            tevent_req_error(req, ret);
1449
 
            return;
1450
 
        }
1451
 
        talloc_zfree(subreq);
1452
 
 
1453
 
        state->in_transaction = true;
1454
 
    } else {
1455
 
        ret = sysdb_store_group_recv(subreq);
1456
 
        if (ret) {
1457
 
            /* Do not fail completely on errors.
1458
 
             * Just report the failure to save and go on */
1459
 
            DEBUG(2, ("Failed to store group. Ignoring.\n"));
1460
 
        }
1461
 
        talloc_zfree(subreq);
1462
 
    }
1463
 
 
1464
 
again:
1465
 
    /* always zero out the grp structure */
1466
 
    memset(state->grp, 0, sizeof(struct group));
1467
 
 
1468
 
    /* get entry */
1469
 
    status = ctx->ops.getgrent_r(state->grp,
1470
 
                                 state->buffer, state->buflen, &ret);
1471
 
 
1472
 
    switch (status) {
1473
 
    case NSS_STATUS_TRYAGAIN:
1474
 
        /* buffer too small ? */
1475
 
        if (state->buflen < MAX_BUF_SIZE) {
1476
 
            state->buflen *= 2;
1477
 
        }
1478
 
        if (state->buflen > MAX_BUF_SIZE) {
1479
 
            state->buflen = MAX_BUF_SIZE;
1480
 
        }
1481
 
        newbuf = talloc_realloc_size(state, state->buffer, state->buflen);
1482
 
        if (!newbuf) {
1483
 
            ret = ENOMEM;
1484
 
            goto fail;
1485
 
        }
1486
 
        state->buffer = newbuf;
1487
 
        goto again;
1488
 
 
1489
 
    case NSS_STATUS_NOTFOUND:
1490
 
 
1491
 
        /* we are done here */
1492
 
        DEBUG(7, ("Enumeration completed.\n"));
1493
 
 
1494
 
        ctx->ops.endgrent();
1495
 
        subreq = sysdb_transaction_commit_send(state, state->ev,
1496
 
                                               state->handle);
1497
 
        if (!subreq) {
1498
 
            tevent_req_error(req, ENOMEM);
1499
 
            return;
1500
 
        }
1501
 
        tevent_req_set_callback(subreq, proxy_default_done, req);
1502
 
        return;
1503
 
 
1504
 
    case NSS_STATUS_SUCCESS:
1505
 
 
1506
 
        DEBUG(7, ("Group found (%s, %d)\n",
1507
 
                  state->grp->gr_name, state->grp->gr_gid));
1508
 
 
1509
 
        /* gid=0 is an invalid value */
1510
 
        /* also check that the id is in the valid range for this domain */
1511
 
        if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1512
 
 
1513
 
                DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1514
 
                          state->grp->gr_name));
1515
 
 
1516
 
            goto again; /* skip */
1517
 
        }
1518
 
 
1519
 
        DEBUG_GR_MEM(7, state);
1520
 
 
1521
 
        if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1522
 
            members = sysdb_new_attrs(state);
1523
 
            if (!members) {
1524
 
                tevent_req_error(req, ENOMEM);
1525
 
                return;
1526
 
            }
1527
 
            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1528
 
                                                  state->domain->name,
1529
 
                                                  (const char **)state->grp->gr_mem);
1530
 
            if (ret) {
1531
 
                tevent_req_error(req, ret);
1532
 
                return;
1533
 
            }
1534
 
        } else {
1535
 
            members = NULL;
1536
 
        }
1537
 
 
1538
 
        subreq = sysdb_store_group_send(state, state->ev, state->handle,
1539
 
                                       state->domain,
1540
 
                                       state->grp->gr_name,
1541
 
                                       state->grp->gr_gid,
1542
 
                                       members,
1543
 
                                       ctx->entry_cache_timeout);
1544
 
        if (!subreq) {
1545
 
            tevent_req_error(req, ENOMEM);
1546
 
            return;
1547
 
        }
1548
 
        tevent_req_set_callback(subreq, enum_groups_process, req);
1549
 
        return;
1550
 
 
1551
 
    case NSS_STATUS_UNAVAIL:
1552
 
        /* "remote" backend unavailable. Enter offline mode */
1553
 
        ret = ENXIO;
1554
 
        goto fail;
1555
 
 
1556
 
    default:
1557
 
        DEBUG(2, ("proxy -> getgrent_r failed (%d)[%s]\n",
1558
 
                  ret, strerror(ret)));
1559
 
        goto fail;
1560
 
    }
1561
 
 
1562
 
fail:
1563
 
    ctx->ops.endgrent();
1564
 
    tevent_req_error(req, ret);
1565
 
}
1566
 
 
1567
 
 
1568
 
/* =Initgroups-wrapper====================================================*/
1569
 
 
1570
 
static void get_initgr_process(struct tevent_req *subreq);
1571
 
static void get_initgr_groups_process(struct tevent_req *subreq);
1572
 
static void get_initgr_groups_done(struct tevent_req *subreq);
1573
 
static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx,
1574
 
                                                 struct tevent_context *ev,
1575
 
                                                 struct sysdb_handle *handle,
1576
 
                                                 struct proxy_ctx *ctx,
1577
 
                                                 struct sss_domain_info *domain,
1578
 
                                                 gid_t *gids, int num_gids);
1579
 
static int get_groups_by_gid_recv(struct tevent_req *req);
1580
 
static void get_groups_by_gid_process(struct tevent_req *subreq);
1581
 
static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
1582
 
                                                  struct tevent_context *ev,
1583
 
                                                  struct sysdb_handle *handle,
1584
 
                                                  struct proxy_ctx *ctx,
1585
 
                                                  struct sss_domain_info *domain,
1586
 
                                                  gid_t gid);
1587
 
static int get_group_from_gid_recv(struct tevent_req *req);
1588
 
static void get_group_from_gid_send_del_done(struct tevent_req *subreq);
1589
 
static void get_group_from_gid_send_add_done(struct tevent_req *subreq);
1590
 
 
1591
 
 
1592
 
static struct tevent_req *get_initgr_send(TALLOC_CTX *mem_ctx,
1593
 
                                          struct tevent_context *ev,
1594
 
                                          struct proxy_ctx *ctx,
1595
 
                                          struct sysdb_ctx *sysdb,
1596
 
                                          struct sss_domain_info *domain,
1597
 
                                          const char *name)
1598
 
{
1599
 
    struct tevent_req *req, *subreq;
1600
 
    struct proxy_state *state;
1601
 
 
1602
 
    req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1603
 
    if (!req) return NULL;
1604
 
 
1605
 
    memset(state, 0, sizeof(struct proxy_state));
1606
 
 
1607
 
    state->ev = ev;
1608
 
    state->ctx = ctx;
1609
 
    state->sysdb = sysdb;
1610
 
    state->domain = domain;
1611
 
    state->name = name;
1612
 
 
1613
 
    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1614
 
    if (!subreq) {
1615
 
        talloc_zfree(req);
1616
 
        return NULL;
1617
 
    }
1618
 
    tevent_req_set_callback(subreq, get_initgr_process, req);
1619
 
 
1620
 
    return req;
1621
 
}
1622
 
 
1623
 
static void get_initgr_process(struct tevent_req *subreq)
1624
 
{
1625
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1626
 
                                                      struct tevent_req);
1627
 
    struct proxy_state *state = tevent_req_data(req,
1628
 
                                                struct proxy_state);
1629
 
    struct proxy_ctx *ctx = state->ctx;
1630
 
    struct sss_domain_info *dom = ctx->be->domain;
1631
 
    enum nss_status status;
1632
 
    char *buffer;
1633
 
    size_t buflen;
1634
 
    bool delete_user = false;
1635
 
    int ret;
1636
 
 
1637
 
    ret = sysdb_transaction_recv(subreq, state, &state->handle);
1638
 
    if (ret) {
1639
 
        tevent_req_error(req, ret);
1640
 
        return;
1641
 
    }
1642
 
    talloc_zfree(subreq);
1643
 
 
1644
 
    state->pwd = talloc(state, struct passwd);
1645
 
    if (!state->pwd) {
1646
 
        tevent_req_error(req, ENOMEM);
1647
 
        return;
1648
 
    }
1649
 
 
1650
 
    buflen = DEFAULT_BUFSIZE;
1651
 
    buffer = talloc_size(state, buflen);
1652
 
    if (!buffer) {
1653
 
        tevent_req_error(req, ENOMEM);
1654
 
        return;
1655
 
    }
1656
 
 
1657
 
    /* FIXME: should we move this call outside the transaction to keep the
1658
 
     * transaction as short as possible ? */
1659
 
    status = ctx->ops.getpwnam_r(state->name, state->pwd,
1660
 
                                 buffer, buflen, &ret);
1661
 
 
1662
 
    switch (status) {
1663
 
    case NSS_STATUS_NOTFOUND:
1664
 
 
1665
 
        delete_user = true;
1666
 
        break;
1667
 
 
1668
 
    case NSS_STATUS_SUCCESS:
1669
 
 
1670
 
        /* uid=0 or gid=0 are invalid values */
1671
 
        /* also check that the id is in the valid range for this domain */
1672
 
        if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
1673
 
            OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
1674
 
 
1675
 
                DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
1676
 
                          state->name));
1677
 
            delete_user = true;
1678
 
            break;
1679
 
        }
1680
 
 
1681
 
        subreq = sysdb_store_user_send(state, state->ev, state->handle,
1682
 
                                       state->domain,
1683
 
                                       state->pwd->pw_name,
1684
 
                                       state->pwd->pw_passwd,
1685
 
                                       state->pwd->pw_uid,
1686
 
                                       state->pwd->pw_gid,
1687
 
                                       state->pwd->pw_gecos,
1688
 
                                       state->pwd->pw_dir,
1689
 
                                       state->pwd->pw_shell,
1690
 
                                       NULL, ctx->entry_cache_timeout);
1691
 
        if (!subreq) {
1692
 
            tevent_req_error(req, ENOMEM);
1693
 
            return;
1694
 
        }
1695
 
        tevent_req_set_callback(subreq, get_initgr_groups_process, req);
1696
 
        return;
1697
 
 
1698
 
    case NSS_STATUS_UNAVAIL:
1699
 
        /* "remote" backend unavailable. Enter offline mode */
1700
 
        tevent_req_error(req, ENXIO);
1701
 
        return;
1702
 
 
1703
 
    default:
1704
 
        DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
1705
 
                  state->name, status));
1706
 
        tevent_req_error(req, EIO);
1707
 
        return;
1708
 
    }
1709
 
 
1710
 
    if (delete_user) {
1711
 
        struct ldb_dn *dn;
1712
 
 
1713
 
        dn = sysdb_user_dn(state->sysdb, state,
1714
 
                           state->domain->name, state->name);
1715
 
        if (!dn) {
1716
 
            tevent_req_error(req, ENOMEM);
1717
 
            return;
1718
 
        }
1719
 
 
1720
 
        subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
1721
 
        if (!subreq) {
1722
 
            tevent_req_error(req, ENOMEM);
1723
 
            return;
1724
 
        }
1725
 
        tevent_req_set_callback(subreq, get_pw_name_remove_done, req);
1726
 
    }
1727
 
}
1728
 
 
1729
 
static void get_initgr_groups_process(struct tevent_req *subreq)
1730
 
{
1731
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1732
 
                                                      struct tevent_req);
1733
 
    struct proxy_state *state = tevent_req_data(req,
1734
 
                                                struct proxy_state);
1735
 
    struct proxy_ctx *ctx = state->ctx;
1736
 
    enum nss_status status;
1737
 
    long int limit;
1738
 
    long int size;
1739
 
    long int num;
1740
 
    long int num_gids;
1741
 
    gid_t *gids;
1742
 
    int ret;
1743
 
 
1744
 
    ret = sysdb_store_user_recv(subreq);
1745
 
    if (ret) {
1746
 
        tevent_req_error(req, ret);
1747
 
        return;
1748
 
    }
1749
 
    talloc_zfree(subreq);
1750
 
 
1751
 
    num_gids = 0;
1752
 
    limit = 4096;
1753
 
    num = 4096;
1754
 
    size = num*sizeof(gid_t);
1755
 
    gids = talloc_size(state, size);
1756
 
    if (!gids) {
1757
 
        tevent_req_error(req, ENOMEM);
1758
 
        return;
1759
 
    }
1760
 
 
1761
 
    state->gid = state->pwd->pw_gid;
1762
 
 
1763
 
again:
1764
 
    /* FIXME: should we move this call outside the transaction to keep the
1765
 
     * transaction as short as possible ? */
1766
 
    status = ctx->ops.initgroups_dyn(state->name, state->gid, &num_gids,
1767
 
                                     &num, &gids, limit, &ret);
1768
 
    switch (status) {
1769
 
    case NSS_STATUS_TRYAGAIN:
1770
 
        /* buffer too small ? */
1771
 
        if (size < MAX_BUF_SIZE) {
1772
 
            num *= 2;
1773
 
            size = num*sizeof(gid_t);
1774
 
        }
1775
 
        if (size > MAX_BUF_SIZE) {
1776
 
            size = MAX_BUF_SIZE;
1777
 
            num = size/sizeof(gid_t);
1778
 
        }
1779
 
        limit = num;
1780
 
        gids = talloc_realloc_size(state, gids, size);
1781
 
        if (!gids) {
1782
 
            tevent_req_error(req, ENOMEM);
1783
 
            return;
1784
 
        }
1785
 
        goto again; /* retry with more memory */
1786
 
 
1787
 
    case NSS_STATUS_SUCCESS:
1788
 
        DEBUG(4, ("User [%s] appears to be member of %lu groups\n",
1789
 
                  state->name, num_gids));
1790
 
 
1791
 
        subreq = get_groups_by_gid_send(state, state->ev, state->handle,
1792
 
                                        state->ctx, state->domain,
1793
 
                                        gids, num_gids);
1794
 
        if (!subreq) {
1795
 
            tevent_req_error(req, ENOMEM);
1796
 
            return;
1797
 
        }
1798
 
        tevent_req_set_callback(subreq, get_initgr_groups_done, req);
1799
 
        break;
1800
 
 
1801
 
    default:
1802
 
        DEBUG(2, ("proxy -> initgroups_dyn failed (%d)[%s]\n",
1803
 
                  ret, strerror(ret)));
1804
 
        tevent_req_error(req, EIO);
1805
 
        return;
1806
 
    }
1807
 
}
1808
 
 
1809
 
static void get_initgr_groups_done(struct tevent_req *subreq)
1810
 
{
1811
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1812
 
                                                      struct tevent_req);
1813
 
    struct proxy_state *state = tevent_req_data(req,
1814
 
                                                struct proxy_state);
1815
 
    int ret;
1816
 
 
1817
 
    ret = get_groups_by_gid_recv(subreq);
1818
 
    talloc_zfree(subreq);
1819
 
    if (ret) {
1820
 
        tevent_req_error(req, ret);
1821
 
        return;
1822
 
    }
1823
 
 
1824
 
    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1825
 
    if (!subreq) {
1826
 
        tevent_req_error(req, ENOMEM);
1827
 
        return;
1828
 
    }
1829
 
    tevent_req_set_callback(subreq, proxy_default_done, req);
1830
 
}
1831
 
 
1832
 
struct get_groups_state {
1833
 
    struct tevent_context *ev;
1834
 
    struct sysdb_handle *handle;
1835
 
    struct proxy_ctx *ctx;
1836
 
    struct sss_domain_info *domain;
1837
 
 
1838
 
    gid_t *gids;
1839
 
    int num_gids;
1840
 
    int cur_gid;
1841
 
};
1842
 
 
1843
 
static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx,
1844
 
                                                 struct tevent_context *ev,
1845
 
                                                 struct sysdb_handle *handle,
1846
 
                                                 struct proxy_ctx *ctx,
1847
 
                                                 struct sss_domain_info *domain,
1848
 
                                                 gid_t *gids, int num_gids)
1849
 
{
1850
 
    struct tevent_req *req, *subreq;
1851
 
    struct get_groups_state *state;
1852
 
 
1853
 
    req = tevent_req_create(mem_ctx, &state, struct get_groups_state);
1854
 
    if (!req) return NULL;
1855
 
 
1856
 
    state->ev = ev;
1857
 
    state->handle = handle;
1858
 
    state->ctx = ctx;
1859
 
    state->domain = domain;
1860
 
    state->gids = gids;
1861
 
    state->num_gids = num_gids;
1862
 
    state->cur_gid = 0;
1863
 
 
1864
 
    subreq = get_group_from_gid_send(state, ev, handle, ctx, domain, gids[0]);
1865
 
    if (!subreq) {
1866
 
        talloc_zfree(req);
1867
 
        return NULL;
1868
 
    }
1869
 
    tevent_req_set_callback(subreq, get_groups_by_gid_process, req);
1870
 
 
1871
 
    return req;
1872
 
}
1873
 
 
1874
 
static void get_groups_by_gid_process(struct tevent_req *subreq)
1875
 
{
1876
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
1877
 
                                                      struct tevent_req);
1878
 
    struct get_groups_state *state = tevent_req_data(req,
1879
 
                                                struct get_groups_state);
1880
 
    int ret;
1881
 
 
1882
 
    ret = get_group_from_gid_recv(subreq);
1883
 
    talloc_zfree(subreq);
1884
 
    if (ret) {
1885
 
        tevent_req_error(req, ret);
1886
 
        return;
1887
 
    }
1888
 
 
1889
 
    state->cur_gid++;
1890
 
    if (state->cur_gid >= state->num_gids) {
1891
 
        tevent_req_done(req);
1892
 
        return;
1893
 
    }
1894
 
 
1895
 
    subreq = get_group_from_gid_send(state,
1896
 
                                     state->ev, state->handle,
1897
 
                                     state->ctx, state->domain,
1898
 
                                     state->gids[state->cur_gid]);
1899
 
    if (!subreq) {
1900
 
        tevent_req_error(req, ENOMEM);
1901
 
        return;
1902
 
    }
1903
 
    tevent_req_set_callback(subreq, get_groups_by_gid_process, req);
1904
 
}
1905
 
 
1906
 
static int get_groups_by_gid_recv(struct tevent_req *req)
1907
 
{
1908
 
    TEVENT_REQ_RETURN_ON_ERROR(req);
1909
 
 
1910
 
    return EOK;
1911
 
}
1912
 
 
1913
 
static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
1914
 
                                                  struct tevent_context *ev,
1915
 
                                                  struct sysdb_handle *handle,
1916
 
                                                  struct proxy_ctx *ctx,
1917
 
                                                  struct sss_domain_info *domain,
1918
 
                                                  gid_t gid)
1919
 
{
1920
 
    struct tevent_req *req, *subreq;
1921
 
    struct proxy_state *state;
1922
 
    struct sss_domain_info *dom = ctx->be->domain;
1923
 
    enum nss_status status;
1924
 
    char *buffer;
1925
 
    char *newbuf;
1926
 
    size_t buflen;
1927
 
    bool delete_group = false;
1928
 
    struct sysdb_attrs *members;
1929
 
    int ret;
1930
 
 
1931
 
    req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1932
 
    if (!req) return NULL;
1933
 
 
1934
 
    memset(state, 0, sizeof(struct proxy_state));
1935
 
 
1936
 
    state->ev = ev;
1937
 
    state->handle = handle;
1938
 
    state->ctx = ctx;
1939
 
    state->domain = domain;
1940
 
    state->gid = gid;
1941
 
 
1942
 
    state->grp = talloc(state, struct group);
1943
 
    if (!state->grp) {
1944
 
        ret = ENOMEM;
1945
 
        goto fail;
1946
 
    }
1947
 
 
1948
 
    buflen = DEFAULT_BUFSIZE;
1949
 
    buffer = talloc_size(state, buflen);
1950
 
    if (!buffer) {
1951
 
        ret = ENOMEM;
1952
 
        goto fail;
1953
 
    }
1954
 
 
1955
 
again:
1956
 
    /* always zero out the grp structure */
1957
 
    memset(state->grp, 0, sizeof(struct group));
1958
 
 
1959
 
    status = ctx->ops.getgrgid_r(state->gid, state->grp,
1960
 
                                 buffer, buflen, &ret);
1961
 
 
1962
 
    switch (status) {
1963
 
    case NSS_STATUS_TRYAGAIN:
1964
 
        /* buffer too small ? */
1965
 
        if (buflen < MAX_BUF_SIZE) {
1966
 
            buflen *= 2;
1967
 
        }
1968
 
        if (buflen > MAX_BUF_SIZE) {
1969
 
            buflen = MAX_BUF_SIZE;
1970
 
        }
1971
 
        newbuf = talloc_realloc_size(state, buffer, buflen);
1972
 
        if (!newbuf) {
1973
 
            ret = ENOMEM;
1974
 
            goto fail;
1975
 
        }
1976
 
        buffer = newbuf;
1977
 
        goto again;
1978
 
 
1979
 
    case NSS_STATUS_NOTFOUND:
1980
 
 
1981
 
        delete_group = true;
1982
 
        break;
1983
 
 
1984
 
    case NSS_STATUS_SUCCESS:
1985
 
 
1986
 
        /* gid=0 is an invalid value */
1987
 
        /* also check that the id is in the valid range for this domain */
1988
 
        if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1989
 
 
1990
 
                DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1991
 
                          state->grp->gr_name));
1992
 
            delete_group = true;
1993
 
            break;
1994
 
        }
1995
 
 
1996
 
        if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1997
 
            members = sysdb_new_attrs(state);
1998
 
            if (!members) {
1999
 
                ret = ENOMEM;
2000
 
                goto fail;
2001
 
            }
2002
 
            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
2003
 
                                                  state->domain->name,
2004
 
                                                  (const char **)state->grp->gr_mem);
2005
 
            if (ret) {
2006
 
                goto fail;
2007
 
            }
2008
 
        } else {
2009
 
            members = NULL;
2010
 
        }
2011
 
 
2012
 
        subreq = sysdb_store_group_send(state, state->ev, state->handle,
2013
 
                                        state->domain,
2014
 
                                        state->grp->gr_name,
2015
 
                                        state->grp->gr_gid,
2016
 
                                        members,
2017
 
                                        ctx->entry_cache_timeout);
2018
 
        if (!subreq) {
2019
 
            ret = ENOMEM;
2020
 
            goto fail;
2021
 
        }
2022
 
        tevent_req_set_callback(subreq, get_group_from_gid_send_add_done, req);
2023
 
        break;
2024
 
 
2025
 
    case NSS_STATUS_UNAVAIL:
2026
 
        /* "remote" backend unavailable. Enter offline mode */
2027
 
        ret = ENXIO;
2028
 
        goto fail;
2029
 
 
2030
 
    default:
2031
 
        DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n",
2032
 
                  state->gid, status));
2033
 
        ret = EIO;
2034
 
        goto fail;
2035
 
    }
2036
 
 
2037
 
    if (delete_group) {
2038
 
        subreq = sysdb_delete_group_send(state, state->ev,
2039
 
                                         NULL, state->handle,
2040
 
                                         state->domain,
2041
 
                                         NULL, state->gid);
2042
 
        if (!subreq) {
2043
 
            ret = ENOMEM;
2044
 
            goto fail;
2045
 
        }
2046
 
        tevent_req_set_callback(subreq, get_group_from_gid_send_del_done, req);
2047
 
    }
2048
 
 
2049
 
    return req;
2050
 
 
2051
 
fail:
2052
 
    tevent_req_error(req, ret);
2053
 
    tevent_req_post(req, ev);
2054
 
    return req;
2055
 
}
2056
 
 
2057
 
static void get_group_from_gid_send_add_done(struct tevent_req *subreq)
2058
 
{
2059
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
2060
 
                                                      struct tevent_req);
2061
 
    int ret;
2062
 
 
2063
 
    ret = sysdb_store_group_recv(subreq);
2064
 
    talloc_zfree(subreq);
2065
 
    if (ret) {
2066
 
        tevent_req_error(req, ret);
2067
 
        return;
2068
 
    }
2069
 
 
2070
 
    tevent_req_done(req);
2071
 
}
2072
 
 
2073
 
static void get_group_from_gid_send_del_done(struct tevent_req *subreq)
2074
 
{
2075
 
    struct tevent_req *req = tevent_req_callback_data(subreq,
2076
 
                                                      struct tevent_req);
2077
 
    int ret;
2078
 
 
2079
 
    ret = sysdb_delete_entry_recv(subreq);
2080
 
    talloc_zfree(subreq);
2081
 
    if (ret && ret != ENOENT) {
2082
 
        tevent_req_error(req, ret);
2083
 
        return;
2084
 
    }
2085
 
 
2086
 
    tevent_req_done(req);
2087
 
}
2088
 
 
2089
 
static int get_group_from_gid_recv(struct tevent_req *req)
2090
 
{
2091
 
    TEVENT_REQ_RETURN_ON_ERROR(req);
2092
 
 
2093
 
    return EOK;
2094
 
}
2095
 
 
2096
 
 
2097
 
/* =Proxy_Id-Functions====================================================*/
2098
 
 
2099
 
static void proxy_get_account_info_done(struct tevent_req *subreq);
2100
 
 
2101
 
/* TODO: See if we can use async_req code */
2102
 
static void proxy_get_account_info(struct be_req *breq)
2103
 
{
2104
 
    struct tevent_req *subreq;
2105
 
    struct be_acct_req *ar;
2106
 
    struct proxy_ctx *ctx;
2107
 
    struct tevent_context *ev;
2108
 
    struct sysdb_ctx *sysdb;
2109
 
    struct sss_domain_info *domain;
2110
 
    uid_t uid;
2111
 
    gid_t gid;
2112
 
 
2113
 
    ar = talloc_get_type(breq->req_data, struct be_acct_req);
2114
 
    ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct proxy_ctx);
2115
 
    ev = breq->be_ctx->ev;
2116
 
    sysdb = breq->be_ctx->sysdb;
2117
 
    domain = breq->be_ctx->domain;
2118
 
 
2119
 
    if (be_is_offline(breq->be_ctx)) {
2120
 
        return proxy_reply(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
2121
 
    }
2122
 
 
2123
 
    /* for now we support only core attrs */
2124
 
    if (ar->attr_type != BE_ATTR_CORE) {
2125
 
        return proxy_reply(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type");
2126
 
    }
2127
 
 
2128
 
    switch (ar->entry_type & 0xFFF) {
2129
 
    case BE_REQ_USER: /* user */
2130
 
        switch (ar->filter_type) {
2131
 
        case BE_FILTER_NAME:
2132
 
            if (strchr(ar->filter_value, '*')) {
2133
 
                subreq = enum_users_send(breq, ev, ctx,
2134
 
                                         sysdb, domain);
2135
 
                if (!subreq) {
2136
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2137
 
                                       ENOMEM, "Out of memory");
2138
 
                }
2139
 
                tevent_req_set_callback(subreq,
2140
 
                               proxy_get_account_info_done, breq);
2141
 
                return;
2142
 
            } else {
2143
 
                subreq = get_pw_name_send(breq, ev, ctx,
2144
 
                                          sysdb, domain,
2145
 
                                          ar->filter_value);
2146
 
                if (!subreq) {
2147
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2148
 
                                       ENOMEM, "Out of memory");
2149
 
                }
2150
 
                tevent_req_set_callback(subreq,
2151
 
                               proxy_get_account_info_done, breq);
2152
 
                return;
2153
 
            }
2154
 
            break;
2155
 
 
2156
 
        case BE_FILTER_IDNUM:
2157
 
            if (strchr(ar->filter_value, '*')) {
2158
 
                return proxy_reply(breq, DP_ERR_FATAL,
2159
 
                                   EINVAL, "Invalid attr type");
2160
 
            } else {
2161
 
                char *endptr;
2162
 
                errno = 0;
2163
 
                uid = (uid_t)strtol(ar->filter_value, &endptr, 0);
2164
 
                if (errno || *endptr || (ar->filter_value == endptr)) {
2165
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2166
 
                                       EINVAL, "Invalid attr type");
2167
 
                }
2168
 
                subreq = get_pw_uid_send(breq, ev, ctx,
2169
 
                                         sysdb, domain, uid);
2170
 
                if (!subreq) {
2171
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2172
 
                                       ENOMEM, "Out of memory");
2173
 
                }
2174
 
                tevent_req_set_callback(subreq,
2175
 
                               proxy_get_account_info_done, breq);
2176
 
                return;
2177
 
            }
2178
 
            break;
2179
 
        default:
2180
 
            return proxy_reply(breq, DP_ERR_FATAL,
2181
 
                               EINVAL, "Invalid filter type");
2182
 
        }
2183
 
        break;
2184
 
 
2185
 
    case BE_REQ_GROUP: /* group */
2186
 
        switch (ar->filter_type) {
2187
 
        case BE_FILTER_NAME:
2188
 
            if (strchr(ar->filter_value, '*')) {
2189
 
                subreq = enum_groups_send(breq, ev, ctx,
2190
 
                                          sysdb, domain);
2191
 
                if (!subreq) {
2192
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2193
 
                                       ENOMEM, "Out of memory");
2194
 
                }
2195
 
                tevent_req_set_callback(subreq,
2196
 
                               proxy_get_account_info_done, breq);
2197
 
                return;
2198
 
            } else {
2199
 
                subreq = get_gr_name_send(breq, ev, ctx,
2200
 
                                          sysdb, domain,
2201
 
                                          ar->filter_value);
2202
 
                if (!subreq) {
2203
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2204
 
                                       ENOMEM, "Out of memory");
2205
 
                }
2206
 
                tevent_req_set_callback(subreq,
2207
 
                               proxy_get_account_info_done, breq);
2208
 
                return;
2209
 
            }
2210
 
            break;
2211
 
        case BE_FILTER_IDNUM:
2212
 
            if (strchr(ar->filter_value, '*')) {
2213
 
                return proxy_reply(breq, DP_ERR_FATAL,
2214
 
                                   EINVAL, "Invalid attr type");
2215
 
            } else {
2216
 
                char *endptr;
2217
 
                errno = 0;
2218
 
                gid = (gid_t)strtol(ar->filter_value, &endptr, 0);
2219
 
                if (errno || *endptr || (ar->filter_value == endptr)) {
2220
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2221
 
                                       EINVAL, "Invalid attr type");
2222
 
                }
2223
 
                subreq = get_gr_gid_send(breq, ev, ctx,
2224
 
                                         sysdb, domain, gid);
2225
 
                if (!subreq) {
2226
 
                    return proxy_reply(breq, DP_ERR_FATAL,
2227
 
                                       ENOMEM, "Out of memory");
2228
 
                }
2229
 
                tevent_req_set_callback(subreq,
2230
 
                               proxy_get_account_info_done, breq);
2231
 
                return;
2232
 
            }
2233
 
            break;
2234
 
        default:
2235
 
            return proxy_reply(breq, DP_ERR_FATAL,
2236
 
                               EINVAL, "Invalid filter type");
2237
 
        }
2238
 
        break;
2239
 
 
2240
 
    case BE_REQ_INITGROUPS: /* init groups for user */
2241
 
        if (ar->filter_type != BE_FILTER_NAME) {
2242
 
            return proxy_reply(breq, DP_ERR_FATAL,
2243
 
                               EINVAL, "Invalid filter type");
2244
 
        }
2245
 
        if (strchr(ar->filter_value, '*')) {
2246
 
            return proxy_reply(breq, DP_ERR_FATAL,
2247
 
                               EINVAL, "Invalid filter value");
2248
 
        }
2249
 
        if (ctx->ops.initgroups_dyn == NULL) {
2250
 
            return proxy_reply(breq, DP_ERR_FATAL,
2251
 
                               ENODEV, "Initgroups call not supported");
2252
 
        }
2253
 
        subreq = get_initgr_send(breq, ev, ctx, sysdb,
2254
 
                                 domain, ar->filter_value);
2255
 
        if (!subreq) {
2256
 
            return proxy_reply(breq, DP_ERR_FATAL,
2257
 
                               ENOMEM, "Out of memory");
2258
 
        }
2259
 
        tevent_req_set_callback(subreq,
2260
 
                       proxy_get_account_info_done, breq);
2261
 
        return;
2262
 
 
2263
 
    default: /*fail*/
2264
 
        break;
2265
 
    }
2266
 
 
2267
 
    return proxy_reply(breq, DP_ERR_FATAL,
2268
 
                       EINVAL, "Invalid request type");
2269
 
}
2270
 
 
2271
 
static void proxy_get_account_info_done(struct tevent_req *subreq)
2272
 
{
2273
 
    struct be_req *breq = tevent_req_callback_data(subreq,
2274
 
                                                   struct be_req);
2275
 
    int ret;
2276
 
    ret = proxy_default_recv(subreq);
2277
 
    talloc_zfree(subreq);
2278
 
    if (ret) {
2279
 
        if (ret == ENXIO) {
2280
 
            DEBUG(2, ("proxy returned UNAVAIL error, going offline!\n"));
2281
 
            be_mark_offline(breq->be_ctx);
2282
 
        }
2283
 
        proxy_reply(breq, DP_ERR_FATAL, ret, NULL);
2284
 
        return;
2285
 
    }
2286
 
    proxy_reply(breq, DP_ERR_OK, EOK, NULL);
2287
 
}
2288
 
 
2289
 
static void proxy_shutdown(struct be_req *req)
2290
 
{
2291
 
    /* TODO: Clean up any internal data */
2292
 
    req->fn(req, DP_ERR_OK, EOK, NULL);
2293
 
}
2294
 
 
2295
 
static void proxy_auth_shutdown(struct be_req *req)
2296
 
{
2297
 
    talloc_free(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data);
2298
 
    req->fn(req, DP_ERR_OK, EOK, NULL);
2299
 
}
2300
 
 
2301
 
struct bet_ops proxy_id_ops = {
2302
 
    .handler = proxy_get_account_info,
2303
 
    .finalize = proxy_shutdown
2304
 
};
2305
 
 
2306
 
struct bet_ops proxy_auth_ops = {
2307
 
    .handler = proxy_pam_handler,
2308
 
    .finalize = proxy_auth_shutdown
2309
 
};
2310
 
 
2311
 
struct bet_ops proxy_access_ops = {
2312
 
    .handler = proxy_pam_handler,
2313
 
    .finalize = proxy_auth_shutdown
2314
 
};
2315
 
 
2316
 
struct bet_ops proxy_chpass_ops = {
2317
 
    .handler = proxy_pam_handler,
2318
 
    .finalize = proxy_auth_shutdown
2319
 
};
2320
 
 
2321
 
static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
2322
 
{
2323
 
    char *funcname;
2324
 
    void *funcptr;
2325
 
 
2326
 
    funcname = talloc_asprintf(NULL, functemp, libname);
2327
 
    if (funcname == NULL) return NULL;
2328
 
 
2329
 
    funcptr = dlsym(handle, funcname);
2330
 
    talloc_free(funcname);
2331
 
 
2332
 
    return funcptr;
2333
 
}
2334
 
 
2335
 
int sssm_proxy_init(struct be_ctx *bectx,
2336
 
                    struct bet_ops **ops, void **pvt_data)
2337
 
{
2338
 
    struct proxy_ctx *ctx;
2339
 
    char *libname;
2340
 
    char *libpath;
2341
 
    void *handle;
2342
 
    int ret;
2343
 
 
2344
 
    ctx = talloc_zero(bectx, struct proxy_ctx);
2345
 
    if (!ctx) {
2346
 
        return ENOMEM;
2347
 
    }
2348
 
    ctx->be = bectx;
2349
 
 
2350
 
    ret = confdb_get_int(bectx->cdb, ctx, bectx->conf_path,
2351
 
                         CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT, 600,
2352
 
                         &ctx->entry_cache_timeout);
2353
 
    if (ret != EOK) goto done;
2354
 
 
2355
 
    ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
2356
 
                            CONFDB_PROXY_LIBNAME, NULL, &libname);
2357
 
    if (ret != EOK) goto done;
2358
 
    if (libname == NULL) {
2359
 
        ret = ENOENT;
2360
 
        goto done;
2361
 
    }
2362
 
 
2363
 
    libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname);
2364
 
    if (!libpath) {
2365
 
        ret = ENOMEM;
2366
 
        goto done;
2367
 
    }
2368
 
 
2369
 
    handle = dlopen(libpath, RTLD_NOW);
2370
 
    if (!handle) {
2371
 
        DEBUG(0, ("Unable to load %s module with path, error: %s\n",
2372
 
                  libpath, dlerror()));
2373
 
        ret = ELIBACC;
2374
 
        goto done;
2375
 
    }
2376
 
 
2377
 
    ctx->ops.getpwnam_r = proxy_dlsym(handle, "_nss_%s_getpwnam_r", libname);
2378
 
    if (!ctx->ops.getpwnam_r) {
2379
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2380
 
        ret = ELIBBAD;
2381
 
        goto done;
2382
 
    }
2383
 
 
2384
 
    ctx->ops.getpwuid_r = proxy_dlsym(handle, "_nss_%s_getpwuid_r", libname);
2385
 
    if (!ctx->ops.getpwuid_r) {
2386
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2387
 
        ret = ELIBBAD;
2388
 
        goto done;
2389
 
    }
2390
 
 
2391
 
    ctx->ops.setpwent = proxy_dlsym(handle, "_nss_%s_setpwent", libname);
2392
 
    if (!ctx->ops.setpwent) {
2393
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2394
 
        ret = ELIBBAD;
2395
 
        goto done;
2396
 
    }
2397
 
 
2398
 
    ctx->ops.getpwent_r = proxy_dlsym(handle, "_nss_%s_getpwent_r", libname);
2399
 
    if (!ctx->ops.getpwent_r) {
2400
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2401
 
        ret = ELIBBAD;
2402
 
        goto done;
2403
 
    }
2404
 
 
2405
 
    ctx->ops.endpwent = proxy_dlsym(handle, "_nss_%s_endpwent", libname);
2406
 
    if (!ctx->ops.endpwent) {
2407
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2408
 
        ret = ELIBBAD;
2409
 
        goto done;
2410
 
    }
2411
 
 
2412
 
    ctx->ops.getgrnam_r = proxy_dlsym(handle, "_nss_%s_getgrnam_r", libname);
2413
 
    if (!ctx->ops.getgrnam_r) {
2414
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2415
 
        ret = ELIBBAD;
2416
 
        goto done;
2417
 
    }
2418
 
 
2419
 
    ctx->ops.getgrgid_r = proxy_dlsym(handle, "_nss_%s_getgrgid_r", libname);
2420
 
    if (!ctx->ops.getgrgid_r) {
2421
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2422
 
        ret = ELIBBAD;
2423
 
        goto done;
2424
 
    }
2425
 
 
2426
 
    ctx->ops.setgrent = proxy_dlsym(handle, "_nss_%s_setgrent", libname);
2427
 
    if (!ctx->ops.setgrent) {
2428
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2429
 
        ret = ELIBBAD;
2430
 
        goto done;
2431
 
    }
2432
 
 
2433
 
    ctx->ops.getgrent_r = proxy_dlsym(handle, "_nss_%s_getgrent_r", libname);
2434
 
    if (!ctx->ops.getgrent_r) {
2435
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2436
 
        ret = ELIBBAD;
2437
 
        goto done;
2438
 
    }
2439
 
 
2440
 
    ctx->ops.endgrent = proxy_dlsym(handle, "_nss_%s_endgrent", libname);
2441
 
    if (!ctx->ops.endgrent) {
2442
 
        DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2443
 
        ret = ELIBBAD;
2444
 
        goto done;
2445
 
    }
2446
 
 
2447
 
    ctx->ops.initgroups_dyn = proxy_dlsym(handle, "_nss_%s_initgroups_dyn",
2448
 
                                                  libname);
2449
 
    if (!ctx->ops.initgroups_dyn) {
2450
 
        DEBUG(1, ("The '%s' library does not provides the "
2451
 
                  "_nss_XXX_initgroups_dyn function!\n"
2452
 
                  "initgroups will be slow as it will require "
2453
 
                  "full groups enumeration!\n", libname));
2454
 
    }
2455
 
 
2456
 
    *ops = &proxy_id_ops;
2457
 
    *pvt_data = ctx;
2458
 
    ret = EOK;
2459
 
 
2460
 
done:
2461
 
    if (ret != EOK) {
2462
 
        talloc_free(ctx);
2463
 
    }
2464
 
    return ret;
2465
 
}
2466
 
 
2467
 
int sssm_proxy_auth_init(struct be_ctx *bectx,
2468
 
                         struct bet_ops **ops, void **pvt_data)
2469
 
{
2470
 
    struct proxy_auth_ctx *ctx;
2471
 
    int ret;
2472
 
 
2473
 
    ctx = talloc(bectx, struct proxy_auth_ctx);
2474
 
    if (!ctx) {
2475
 
        return ENOMEM;
2476
 
    }
2477
 
    ctx->be = bectx;
2478
 
 
2479
 
    ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
2480
 
                            CONFDB_PROXY_PAM_TARGET, NULL,
2481
 
                            &ctx->pam_target);
2482
 
    if (ret != EOK) goto done;
2483
 
    if (!ctx->pam_target) {
2484
 
        DEBUG(1, ("Missing option proxy_pam_target.\n"));
2485
 
        ret = EINVAL;
2486
 
        goto done;
2487
 
    }
2488
 
 
2489
 
    *ops = &proxy_auth_ops;
2490
 
    *pvt_data = ctx;
2491
 
 
2492
 
done:
2493
 
    if (ret != EOK) {
2494
 
        talloc_free(ctx);
2495
 
    }
2496
 
    return ret;
2497
 
}
2498
 
 
2499
 
int sssm_proxy_access_init(struct be_ctx *bectx,
2500
 
                           struct bet_ops **ops, void **pvt_data)
2501
 
{
2502
 
    int ret;
2503
 
    ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
2504
 
    *ops = &proxy_access_ops;
2505
 
    return ret;
2506
 
}
2507
 
 
2508
 
int sssm_proxy_chpass_init(struct be_ctx *bectx,
2509
 
                           struct bet_ops **ops, void **pvt_data)
2510
 
{
2511
 
    int ret;
2512
 
    ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
2513
 
    *ops = &proxy_chpass_ops;
2514
 
    return ret;
2515
 
}