~ubuntu-branches/ubuntu/karmic/sssd/karmic

« back to all changes in this revision

Viewing changes to server/responder/nss/nsssrv_cmd.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2009-08-24 16:35:11 UTC
  • Revision ID: james.westby@ubuntu.com-20090824163511-l20qd53jlb0bv56d
Tags: upstream-0.5.0
ImportĀ upstreamĀ versionĀ 0.5.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   SSSD
 
3
 
 
4
   NSS Responder
 
5
 
 
6
   Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
 
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 "util/util.h"
 
23
#include "responder/nss/nsssrv.h"
 
24
#include "confdb/confdb.h"
 
25
#include "db/sysdb.h"
 
26
#include <time.h>
 
27
 
 
28
struct nss_cmd_ctx {
 
29
    struct cli_ctx *cctx;
 
30
    char *name;
 
31
    uint32_t id;
 
32
 
 
33
    bool immediate;
 
34
    bool check_next;
 
35
    bool enum_cached;
 
36
};
 
37
 
 
38
struct dom_ctx {
 
39
    struct sss_domain_info *domain;
 
40
    struct ldb_result *res;
 
41
    int cur;
 
42
};
 
43
 
 
44
struct getent_ctx {
 
45
    struct dom_ctx *doms;
 
46
    int num;
 
47
    int cur;
 
48
};
 
49
 
 
50
struct nss_dom_ctx {
 
51
    struct nss_cmd_ctx *cmdctx;
 
52
    struct sss_domain_info *domain;
 
53
 
 
54
    bool check_provider;
 
55
 
 
56
    /* cache results */
 
57
    struct ldb_result *res;
 
58
};
 
59
 
 
60
static int nss_cmd_send_error(struct nss_cmd_ctx *cmdctx, int err)
 
61
{
 
62
    struct cli_ctx *cctx = cmdctx->cctx;
 
63
    int ret;
 
64
 
 
65
    /* create response packet */
 
66
    ret = sss_packet_new(cctx->creq, 0,
 
67
                         sss_packet_get_cmd(cctx->creq->in),
 
68
                         &cctx->creq->out);
 
69
    if (ret != EOK) {
 
70
        return ret;
 
71
    }
 
72
 
 
73
    sss_packet_set_error(cctx->creq->out, err);
 
74
    return EOK;
 
75
}
 
76
 
 
77
#define NSS_CMD_FATAL_ERROR(cctx) do { \
 
78
    DEBUG(1,("Fatal error, killing connection!")); \
 
79
    talloc_free(cctx); \
 
80
    return; \
 
81
} while(0)
 
82
 
 
83
static struct sss_domain_info *nss_get_dom(struct sss_domain_info *doms,
 
84
                                           const char *domain)
 
85
{
 
86
    struct sss_domain_info *dom;
 
87
 
 
88
    for (dom = doms; dom; dom = dom->next) {
 
89
        if (strcasecmp(dom->name, domain) == 0) break;
 
90
    }
 
91
    if (!dom) DEBUG(2, ("Unknown domain [%s]!\n", domain));
 
92
 
 
93
    return dom;
 
94
}
 
95
 
 
96
static int fill_empty(struct sss_packet *packet)
 
97
{
 
98
    uint8_t *body;
 
99
    size_t blen;
 
100
    int ret;
 
101
 
 
102
    ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
 
103
    if (ret != EOK) return ret;
 
104
 
 
105
    sss_packet_get_body(packet, &body, &blen);
 
106
    ((uint32_t *)body)[0] = 0; /* num results */
 
107
    ((uint32_t *)body)[1] = 0; /* reserved */
 
108
 
 
109
    return EOK;
 
110
}
 
111
 
 
112
/****************************************************************************
 
113
 * PASSWD db related functions
 
114
 ***************************************************************************/
 
115
 
 
116
static int fill_pwent(struct sss_packet *packet,
 
117
                      struct sss_domain_info *dom,
 
118
                      struct nss_ctx *nctx,
 
119
                      bool filter_users,
 
120
                      struct ldb_message **msgs,
 
121
                      int count)
 
122
{
 
123
    struct ldb_message *msg;
 
124
    uint8_t *body;
 
125
    const char *name;
 
126
    const char *gecos;
 
127
    const char *homedir;
 
128
    const char *shell;
 
129
    uint32_t uid;
 
130
    uint32_t gid;
 
131
    size_t rsize, rp, blen;
 
132
    size_t s1, s2, s3, s4;
 
133
    size_t dom_len = 0;
 
134
    int delim = 1;
 
135
    int i, ret, num, t;
 
136
    bool add_domain = dom->fqnames;
 
137
    const char *domain = dom->name;
 
138
    const char *namefmt = nctx->rctx->names->fq_fmt;
 
139
    bool packet_initialized = false;
 
140
    int ncret;
 
141
 
 
142
    if (add_domain) dom_len = strlen(domain);
 
143
 
 
144
    rp = 2*sizeof(uint32_t);
 
145
 
 
146
    num = 0;
 
147
    for (i = 0; i < count; i++) {
 
148
        msg = msgs[i];
 
149
 
 
150
        name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
 
151
        uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
 
152
        gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
 
153
 
 
154
        if (!name || !uid || !gid) {
 
155
            DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n",
 
156
                      name?name:"<NULL>", (unsigned long long int)uid));
 
157
            continue;
 
158
        }
 
159
 
 
160
        if (filter_users) {
 
161
            ncret = nss_ncache_check_user(nctx->ncache,
 
162
                                        nctx->neg_timeout,
 
163
                                        domain, name);
 
164
            if (ncret == EEXIST) {
 
165
                DEBUG(4, ("User [%s@%s] filtered out! (negative cache)\n",
 
166
                          name, domain));
 
167
                continue;
 
168
            }
 
169
        }
 
170
 
 
171
        /* check that the uid is valid for this domain */
 
172
        if ((dom->id_min && (uid < dom->id_min)) ||
 
173
            (dom->id_max && (uid > dom->id_max))) {
 
174
                DEBUG(4, ("User [%s@%s] filtered out! (id out of range)\n",
 
175
                          name, domain));
 
176
            continue;
 
177
        }
 
178
 
 
179
        if (!packet_initialized) {
 
180
            /* first 2 fields (len and reserved), filled up later */
 
181
            ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
 
182
            if (ret != EOK) return ret;
 
183
            packet_initialized = true;
 
184
        }
 
185
 
 
186
        gecos = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
 
187
        homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL);
 
188
        shell = ldb_msg_find_attr_as_string(msg, SYSDB_SHELL, NULL);
 
189
 
 
190
        if (!gecos) gecos = "";
 
191
        if (!homedir) homedir = "/";
 
192
        if (!shell) shell = "";
 
193
 
 
194
        s1 = strlen(name) + 1;
 
195
        s2 = strlen(gecos) + 1;
 
196
        s3 = strlen(homedir) + 1;
 
197
        s4 = strlen(shell) + 1;
 
198
        if (add_domain) s1 += delim + dom_len;
 
199
 
 
200
        rsize = 2*sizeof(uint32_t) +s1 + 2 + s2 + s3 +s4;
 
201
 
 
202
        ret = sss_packet_grow(packet, rsize);
 
203
        if (ret != EOK) {
 
204
            num = 0;
 
205
            goto done;
 
206
        }
 
207
        sss_packet_get_body(packet, &body, &blen);
 
208
 
 
209
        ((uint32_t *)(&body[rp]))[0] = uid;
 
210
        ((uint32_t *)(&body[rp]))[1] = gid;
 
211
        rp += 2*sizeof(uint32_t);
 
212
 
 
213
        if (add_domain) {
 
214
            ret = snprintf((char *)&body[rp], s1, namefmt, name, domain);
 
215
            if (ret >= s1) {
 
216
                /* need more space, got creative with the print format ? */
 
217
                t = ret - s1 + 1;
 
218
                ret = sss_packet_grow(packet, t);
 
219
                if (ret != EOK) {
 
220
                    num = 0;
 
221
                    goto done;
 
222
                }
 
223
                delim += t;
 
224
                s1 += t;
 
225
                sss_packet_get_body(packet, &body, &blen);
 
226
 
 
227
                /* retry */
 
228
                ret = snprintf((char *)&body[rp], s1, namefmt, name, domain);
 
229
            }
 
230
 
 
231
            if (ret != s1-1) {
 
232
                DEBUG(1, ("Failed to generate a fully qualified name for user "
 
233
                          "[%s] in [%s]! Skipping user.\n", name, domain));
 
234
                continue;
 
235
            }
 
236
        } else {
 
237
            memcpy(&body[rp], name, s1);
 
238
        }
 
239
        rp += s1;
 
240
 
 
241
        memcpy(&body[rp], "x", 2);
 
242
        rp += 2;
 
243
        memcpy(&body[rp], gecos, s2);
 
244
        rp += s2;
 
245
        memcpy(&body[rp], homedir, s3);
 
246
        rp += s3;
 
247
        memcpy(&body[rp], shell, s4);
 
248
        rp += s4;
 
249
 
 
250
        num++;
 
251
    }
 
252
 
 
253
done:
 
254
    /* if there are no results just return ENOENT,
 
255
     * let the caller decide if this is the last packet or not */
 
256
    if (!packet_initialized) return ENOENT;
 
257
 
 
258
    sss_packet_get_body(packet, &body, &blen);
 
259
    ((uint32_t *)body)[0] = num; /* num results */
 
260
    ((uint32_t *)body)[1] = 0; /* reserved */
 
261
 
 
262
    return EOK;
 
263
}
 
264
 
 
265
static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min,
 
266
                                         const char *err_msg, void *ptr);
 
267
 
 
268
static void nss_cmd_getpwnam_callback(void *ptr, int status,
 
269
                                   struct ldb_result *res)
 
270
{
 
271
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
272
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
273
    struct cli_ctx *cctx = cmdctx->cctx;
 
274
    struct sss_domain_info *dom;
 
275
    struct nss_ctx *nctx;
 
276
    int timeout;
 
277
    uint64_t lastUpdate;
 
278
    uint8_t *body;
 
279
    size_t blen;
 
280
    bool call_provider = false;
 
281
    bool neghit = false;
 
282
    int ncret;
 
283
    int ret;
 
284
 
 
285
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
286
 
 
287
    if (status != LDB_SUCCESS) {
 
288
        ret = nss_cmd_send_error(cmdctx, status);
 
289
        if (ret != EOK) {
 
290
            NSS_CMD_FATAL_ERROR(cctx);
 
291
        }
 
292
        sss_cmd_done(cctx, cmdctx);
 
293
        return;
 
294
    }
 
295
 
 
296
    if (dctx->check_provider) {
 
297
        switch (res->count) {
 
298
        case 0:
 
299
            call_provider = true;
 
300
            break;
 
301
 
 
302
        case 1:
 
303
            timeout = nctx->cache_timeout;
 
304
 
 
305
            lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
 
306
                                                     SYSDB_LAST_UPDATE, 0);
 
307
            if (lastUpdate + timeout < time(NULL)) {
 
308
                call_provider = true;
 
309
            }
 
310
            break;
 
311
 
 
312
        default:
 
313
            DEBUG(1, ("getpwnam call returned more than one result !?!\n"));
 
314
            ret = nss_cmd_send_error(cmdctx, ENOENT);
 
315
            if (ret != EOK) {
 
316
                NSS_CMD_FATAL_ERROR(cctx);
 
317
            }
 
318
            sss_cmd_done(cctx, cmdctx);
 
319
            return;
 
320
        }
 
321
    }
 
322
 
 
323
    if (call_provider) {
 
324
 
 
325
        /* dont loop forever :-) */
 
326
        dctx->check_provider = false;
 
327
        timeout = SSS_CLI_SOCKET_TIMEOUT/2;
 
328
 
 
329
        /* keep around current data in case backend is offline */
 
330
        if (res->count) {
 
331
            dctx->res = talloc_steal(dctx, res);
 
332
        }
 
333
 
 
334
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
335
                                   nss_cmd_getpwnam_dp_callback, dctx,
 
336
                                   timeout, dctx->domain->name, SSS_DP_USER,
 
337
                                   cmdctx->name, 0);
 
338
        if (ret != EOK) {
 
339
            DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
 
340
                      ret, strerror(ret)));
 
341
            ret = nss_cmd_send_error(cmdctx, ret);
 
342
            if (ret != EOK) {
 
343
                NSS_CMD_FATAL_ERROR(cctx);
 
344
            }
 
345
            sss_cmd_done(cctx, cmdctx);
 
346
        }
 
347
        return;
 
348
    }
 
349
 
 
350
    switch (res->count) {
 
351
    case 0:
 
352
        if (cmdctx->check_next) {
 
353
 
 
354
            ret = EOK;
 
355
 
 
356
            /* skip domains that require FQnames or have negative caches */
 
357
            for (dom = dctx->domain->next; dom; dom = dom->next) {
 
358
 
 
359
                if (dom->fqnames) continue;
 
360
 
 
361
                ncret = nss_ncache_check_user(nctx->ncache,
 
362
                                              nctx->neg_timeout,
 
363
                                              dom->name, cmdctx->name);
 
364
                if (ncret == ENOENT) break;
 
365
 
 
366
                neghit = true;
 
367
            }
 
368
            /* reset neghit if we still have a domain to check */
 
369
            if (dom) neghit = false;
 
370
 
 
371
           if (neghit) {
 
372
                DEBUG(2, ("User [%s] does not exist! (negative cache)\n",
 
373
                          cmdctx->name));
 
374
                ret = ENOENT;
 
375
            }
 
376
            if (dom == NULL) {
 
377
                DEBUG(2, ("No matching domain found for [%s], fail!\n",
 
378
                          cmdctx->name));
 
379
                ret = ENOENT;
 
380
            }
 
381
 
 
382
            if (ret == EOK) {
 
383
                dctx->domain = dom;
 
384
                dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
385
                if (dctx->res) talloc_free(res);
 
386
                dctx->res = NULL;
 
387
 
 
388
                DEBUG(4, ("Requesting info for [%s@%s]\n",
 
389
                          cmdctx->name, dctx->domain->name));
 
390
 
 
391
                ret = sysdb_getpwnam(cmdctx, cctx->rctx->sysdb,
 
392
                                     dctx->domain, cmdctx->name,
 
393
                                     nss_cmd_getpwnam_callback, dctx);
 
394
                if (ret != EOK) {
 
395
                    DEBUG(1, ("Failed to make request to our cache!\n"));
 
396
                }
 
397
            }
 
398
 
 
399
            /* we made another call, end here */
 
400
            if (ret == EOK) return;
 
401
        }
 
402
 
 
403
        DEBUG(2, ("No results for getpwnam call\n"));
 
404
 
 
405
        /* set negative cache only if not result of cache check */
 
406
        if (!neghit) {
 
407
            ret = nss_ncache_set_user(nctx->ncache, false,
 
408
                                      dctx->domain->name, cmdctx->name);
 
409
            if (ret != EOK) {
 
410
                NSS_CMD_FATAL_ERROR(cctx);
 
411
            }
 
412
        }
 
413
 
 
414
        ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
415
                             sss_packet_get_cmd(cctx->creq->in),
 
416
                             &cctx->creq->out);
 
417
        if (ret != EOK) {
 
418
            NSS_CMD_FATAL_ERROR(cctx);
 
419
        }
 
420
        sss_packet_get_body(cctx->creq->out, &body, &blen);
 
421
        ((uint32_t *)body)[0] = 0; /* 0 results */
 
422
        ((uint32_t *)body)[1] = 0; /* reserved */
 
423
        break;
 
424
 
 
425
    case 1:
 
426
        /* create response packet */
 
427
        ret = sss_packet_new(cctx->creq, 0,
 
428
                             sss_packet_get_cmd(cctx->creq->in),
 
429
                             &cctx->creq->out);
 
430
        if (ret != EOK) {
 
431
            NSS_CMD_FATAL_ERROR(cctx);
 
432
        }
 
433
        ret = fill_pwent(cctx->creq->out,
 
434
                         dctx->domain,
 
435
                         nctx, false,
 
436
                         res->msgs, res->count);
 
437
        if (ret == ENOENT) {
 
438
            ret = fill_empty(cctx->creq->out);
 
439
        }
 
440
        sss_packet_set_error(cctx->creq->out, ret);
 
441
 
 
442
        break;
 
443
 
 
444
    default:
 
445
        DEBUG(1, ("getpwnam call returned more than one result !?!\n"));
 
446
        ret = nss_cmd_send_error(cmdctx, ENOENT);
 
447
        if (ret != EOK) {
 
448
            NSS_CMD_FATAL_ERROR(cctx);
 
449
        }
 
450
    }
 
451
 
 
452
    sss_cmd_done(cctx, cmdctx);
 
453
}
 
454
 
 
455
static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min,
 
456
                                         const char *err_msg, void *ptr)
 
457
{
 
458
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
459
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
460
    struct cli_ctx *cctx = cmdctx->cctx;
 
461
    int ret;
 
462
 
 
463
    if (err_maj) {
 
464
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
465
                  "Error: %u, %u, %s\n"
 
466
                  "Will try to return what we have in cache\n",
 
467
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
468
 
 
469
        if (!dctx->res) {
 
470
            /* return 0 results */
 
471
            dctx->res = talloc_zero(dctx, struct ldb_result);
 
472
            if (!dctx->res) {
 
473
                ret = ENOMEM;
 
474
                goto done;
 
475
            }
 
476
        }
 
477
 
 
478
        nss_cmd_getpwnam_callback(dctx, LDB_SUCCESS, dctx->res);
 
479
        return;
 
480
    }
 
481
 
 
482
    ret = sysdb_getpwnam(cmdctx, cctx->rctx->sysdb,
 
483
                         dctx->domain, cmdctx->name,
 
484
                         nss_cmd_getpwnam_callback, dctx);
 
485
 
 
486
done:
 
487
    if (ret != EOK) {
 
488
        DEBUG(1, ("Failed to make request to our cache! (%d [%s])\n",
 
489
                  ret, strerror(ret)));
 
490
 
 
491
        ret = nss_cmd_send_error(cmdctx, ret);
 
492
        if (ret != EOK) {
 
493
            NSS_CMD_FATAL_ERROR(cctx);
 
494
        }
 
495
        sss_cmd_done(cctx, cmdctx);
 
496
    }
 
497
}
 
498
 
 
499
static int nss_cmd_getpwnam(struct cli_ctx *cctx)
 
500
{
 
501
    struct nss_cmd_ctx *cmdctx;
 
502
    struct nss_dom_ctx *dctx;
 
503
    struct sss_domain_info *dom;
 
504
    struct nss_ctx *nctx;
 
505
    const char *rawname;
 
506
    char *domname;
 
507
    uint8_t *body;
 
508
    size_t blen;
 
509
    int ret;
 
510
    int ncret;
 
511
    bool neghit = false;
 
512
 
 
513
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
514
 
 
515
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
516
    if (!cmdctx) {
 
517
        return ENOMEM;
 
518
    }
 
519
    cmdctx->cctx = cctx;
 
520
 
 
521
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
522
    if (!dctx) {
 
523
        ret = ENOMEM;
 
524
        goto done;
 
525
    }
 
526
    dctx->cmdctx = cmdctx;
 
527
 
 
528
    /* get user name to query */
 
529
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
530
 
 
531
    /* if not terminated fail */
 
532
    if (body[blen -1] != '\0') {
 
533
        ret = EINVAL;
 
534
        goto done;
 
535
    }
 
536
    rawname = (const char *)body;
 
537
 
 
538
    domname = NULL;
 
539
    ret = sss_parse_name(cmdctx, cctx->rctx->names, rawname,
 
540
                         &domname, &cmdctx->name);
 
541
    if (ret != EOK) {
 
542
        DEBUG(2, ("Invalid name received [%s]\n", rawname));
 
543
        ret = ENOENT;
 
544
        goto done;
 
545
    }
 
546
 
 
547
    DEBUG(4, ("Requesting info for [%s] from [%s]\n",
 
548
              cmdctx->name, domname?domname:"<ALL>"));
 
549
 
 
550
    if (domname) {
 
551
        dctx->domain = nss_get_dom(cctx->rctx->domains, domname);
 
552
        if (!dctx->domain) {
 
553
            ret = ENOENT;
 
554
            goto done;
 
555
        }
 
556
 
 
557
        /* verify this user has not yet been negatively cached,
 
558
         * or has been permanently filtered */
 
559
        ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
 
560
                                      dctx->domain->name, cmdctx->name);
 
561
        if (ncret == EEXIST) {
 
562
            neghit = true;
 
563
        }
 
564
    }
 
565
    else {
 
566
        /* skip domains that require FQnames or have negative caches */
 
567
        for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
568
 
 
569
            if (dom->fqnames) continue;
 
570
 
 
571
            /* verify this user has not yet been negatively cached,
 
572
            * or has been permanently filtered */
 
573
            ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
 
574
                                          dom->name, cmdctx->name);
 
575
            if (ncret == ENOENT) break;
 
576
 
 
577
            neghit = true;
 
578
        }
 
579
        /* reset neghit if we still have a domain to check */
 
580
        if (dom) neghit = false;
 
581
 
 
582
        dctx->domain = dom;
 
583
    }
 
584
    if (neghit) {
 
585
        DEBUG(2, ("User [%s] does not exist! (negative cache)\n", rawname));
 
586
        ret = ENOENT;
 
587
        goto done;
 
588
    }
 
589
    if (dctx->domain == NULL) {
 
590
        DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname));
 
591
        ret = ENOENT;
 
592
        goto done;
 
593
    }
 
594
 
 
595
    dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
596
 
 
597
    if (!domname) {
 
598
        /* this is a multidomain search */
 
599
        cmdctx->check_next = true;
 
600
    }
 
601
 
 
602
    DEBUG(4, ("Requesting info for [%s@%s]\n",
 
603
              cmdctx->name, dctx->domain->name));
 
604
 
 
605
    ret = sysdb_getpwnam(cmdctx, cctx->rctx->sysdb,
 
606
                         dctx->domain, cmdctx->name,
 
607
                         nss_cmd_getpwnam_callback, dctx);
 
608
    if (ret != EOK) {
 
609
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
610
    }
 
611
 
 
612
done:
 
613
    if (ret != EOK) {
 
614
        if (ret == ENOENT) {
 
615
            /* we do not have any entry to return */
 
616
            ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
617
                                 sss_packet_get_cmd(cctx->creq->in),
 
618
                                 &cctx->creq->out);
 
619
            if (ret == EOK) {
 
620
                sss_packet_get_body(cctx->creq->out, &body, &blen);
 
621
                ((uint32_t *)body)[0] = 0; /* 0 results */
 
622
                ((uint32_t *)body)[1] = 0; /* reserved */
 
623
            }
 
624
        }
 
625
        if (ret != EOK) {
 
626
            ret = nss_cmd_send_error(cmdctx, ret);
 
627
        }
 
628
        if (ret == EOK) {
 
629
            sss_cmd_done(cctx, cmdctx);
 
630
        }
 
631
        return ret;
 
632
    }
 
633
 
 
634
    return EOK;
 
635
}
 
636
 
 
637
static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min,
 
638
                                        const char *err_msg, void *ptr);
 
639
 
 
640
static void nss_cmd_getpwuid_callback(void *ptr, int status,
 
641
                                      struct ldb_result *res)
 
642
{
 
643
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
644
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
645
    struct cli_ctx *cctx = cmdctx->cctx;
 
646
    struct sss_domain_info *dom;
 
647
    struct nss_ctx *nctx;
 
648
    int timeout;
 
649
    uint64_t lastUpdate;
 
650
    uint8_t *body;
 
651
    size_t blen;
 
652
    bool call_provider = false;
 
653
    bool neghit = false;
 
654
    int ret;
 
655
    int ncret;
 
656
 
 
657
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
658
 
 
659
    if (status != LDB_SUCCESS) {
 
660
        ret = nss_cmd_send_error(cmdctx, status);
 
661
        if (ret != EOK) {
 
662
            NSS_CMD_FATAL_ERROR(cctx);
 
663
        }
 
664
        sss_cmd_done(cctx, cmdctx);
 
665
        return;
 
666
    }
 
667
 
 
668
    if (dctx->check_provider) {
 
669
        switch (res->count) {
 
670
        case 0:
 
671
            call_provider = true;
 
672
            break;
 
673
 
 
674
        case 1:
 
675
            timeout = nctx->cache_timeout;
 
676
 
 
677
            lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
 
678
                                                     SYSDB_LAST_UPDATE, 0);
 
679
            if (lastUpdate + timeout < time(NULL)) {
 
680
                call_provider = true;
 
681
            }
 
682
            break;
 
683
 
 
684
        default:
 
685
            DEBUG(1, ("getpwuid call returned more than one result !?!\n"));
 
686
            ret = nss_cmd_send_error(cmdctx, ENOENT);
 
687
            if (ret != EOK) {
 
688
                NSS_CMD_FATAL_ERROR(cctx);
 
689
            }
 
690
            sss_cmd_done(cctx, cmdctx);
 
691
            return;
 
692
        }
 
693
    }
 
694
 
 
695
    if (call_provider) {
 
696
 
 
697
        /* dont loop forever :-) */
 
698
        dctx->check_provider = false;
 
699
        timeout = SSS_CLI_SOCKET_TIMEOUT/2;
 
700
 
 
701
        /* keep around current data in case backend is offline */
 
702
        if (res->count) {
 
703
            dctx->res = talloc_steal(dctx, res);
 
704
        }
 
705
 
 
706
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
707
                                   nss_cmd_getpwuid_dp_callback, dctx,
 
708
                                   timeout, dctx->domain->name, SSS_DP_USER,
 
709
                                   NULL, cmdctx->id);
 
710
        if (ret != EOK) {
 
711
            DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
 
712
                      ret, strerror(ret)));
 
713
            ret = nss_cmd_send_error(cmdctx, ret);
 
714
            if (ret != EOK) {
 
715
                NSS_CMD_FATAL_ERROR(cctx);
 
716
            }
 
717
            sss_cmd_done(cctx, cmdctx);
 
718
        }
 
719
        return;
 
720
    }
 
721
 
 
722
    switch (res->count) {
 
723
    case 0:
 
724
        if (cmdctx->check_next) {
 
725
 
 
726
            ret = EOK;
 
727
 
 
728
            dom = dctx->domain->next;
 
729
            ncret = nss_ncache_check_uid(nctx->ncache, nctx->neg_timeout,
 
730
                                             cmdctx->id);
 
731
            if (ncret == EEXIST) {
 
732
                DEBUG(3, ("Uid [%lu] does not exist! (negative cache)\n",
 
733
                          (unsigned long)cmdctx->id));
 
734
                ret = ENOENT;
 
735
            }
 
736
            if (dom == NULL) {
 
737
                DEBUG(0, ("No matching domain found for [%lu], fail!\n",
 
738
                          (unsigned long)cmdctx->id));
 
739
                ret = ENOENT;
 
740
            }
 
741
 
 
742
            if (ret == EOK) {
 
743
                dctx->domain = dom;
 
744
                dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
745
                if (dctx->res) talloc_free(res);
 
746
                dctx->res = NULL;
 
747
 
 
748
                DEBUG(4, ("Requesting info for [%s@%s]\n",
 
749
                          cmdctx->name, dctx->domain->name));
 
750
 
 
751
                ret = sysdb_getpwuid(cmdctx, cctx->rctx->sysdb,
 
752
                                     dctx->domain, cmdctx->id,
 
753
                                     nss_cmd_getpwuid_callback, dctx);
 
754
                if (ret != EOK) {
 
755
                    DEBUG(1, ("Failed to make request to our cache!\n"));
 
756
                }
 
757
            }
 
758
 
 
759
            /* we made another call, end here */
 
760
            if (ret == EOK) return;
 
761
        }
 
762
 
 
763
        DEBUG(2, ("No results for getpwuid call\n"));
 
764
 
 
765
        /* set negative cache only if not result of cache check */
 
766
        if (!neghit) {
 
767
            ret = nss_ncache_set_uid(nctx->ncache, false, cmdctx->id);
 
768
            if (ret != EOK) {
 
769
                NSS_CMD_FATAL_ERROR(cctx);
 
770
            }
 
771
        }
 
772
 
 
773
        ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
774
                             sss_packet_get_cmd(cctx->creq->in),
 
775
                             &cctx->creq->out);
 
776
        if (ret != EOK) {
 
777
            NSS_CMD_FATAL_ERROR(cctx);
 
778
        }
 
779
        sss_packet_get_body(cctx->creq->out, &body, &blen);
 
780
        ((uint32_t *)body)[0] = 0; /* 0 results */
 
781
        ((uint32_t *)body)[1] = 0; /* reserved */
 
782
        break;
 
783
 
 
784
    case 1:
 
785
        /* create response packet */
 
786
        ret = sss_packet_new(cctx->creq, 0,
 
787
                             sss_packet_get_cmd(cctx->creq->in),
 
788
                             &cctx->creq->out);
 
789
        if (ret != EOK) {
 
790
            NSS_CMD_FATAL_ERROR(cctx);
 
791
        }
 
792
 
 
793
        ret = fill_pwent(cctx->creq->out,
 
794
                         dctx->domain,
 
795
                         nctx, true,
 
796
                         res->msgs, res->count);
 
797
        if (ret == ENOENT) {
 
798
            ret = fill_empty(cctx->creq->out);
 
799
        }
 
800
        sss_packet_set_error(cctx->creq->out, ret);
 
801
 
 
802
        break;
 
803
 
 
804
    default:
 
805
        DEBUG(1, ("getpwnam call returned more than one result !?!\n"));
 
806
        ret = nss_cmd_send_error(cmdctx, ENOENT);
 
807
        if (ret != EOK) {
 
808
            NSS_CMD_FATAL_ERROR(cctx);
 
809
        }
 
810
    }
 
811
 
 
812
    sss_cmd_done(cctx, cmdctx);
 
813
}
 
814
 
 
815
static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min,
 
816
                                      const char *err_msg, void *ptr)
 
817
{
 
818
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
819
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
820
    struct cli_ctx *cctx = cmdctx->cctx;
 
821
    int ret;
 
822
 
 
823
    if (err_maj) {
 
824
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
825
                  "Error: %u, %u, %s\n"
 
826
                  "Will try to return what we have in cache\n",
 
827
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
828
 
 
829
        if (!dctx->res) {
 
830
            /* return 0 results */
 
831
            dctx->res = talloc_zero(dctx, struct ldb_result);
 
832
            if (!dctx->res) {
 
833
                ret = ENOMEM;
 
834
                goto done;
 
835
            }
 
836
        }
 
837
 
 
838
        nss_cmd_getpwuid_callback(dctx, LDB_SUCCESS, dctx->res);
 
839
        return;
 
840
    }
 
841
 
 
842
    ret = sysdb_getpwuid(cmdctx, cctx->rctx->sysdb,
 
843
                         dctx->domain, cmdctx->id,
 
844
                         nss_cmd_getpwuid_callback, dctx);
 
845
 
 
846
done:
 
847
    if (ret != EOK) {
 
848
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
849
 
 
850
        ret = nss_cmd_send_error(cmdctx, ret);
 
851
        if (ret != EOK) {
 
852
            NSS_CMD_FATAL_ERROR(cctx);
 
853
        }
 
854
        sss_cmd_done(cctx, cmdctx);
 
855
    }
 
856
}
 
857
 
 
858
static int nss_cmd_getpwuid(struct cli_ctx *cctx)
 
859
{
 
860
    struct nss_cmd_ctx *cmdctx;
 
861
    struct nss_dom_ctx *dctx;
 
862
    struct sss_domain_info *dom;
 
863
    struct nss_ctx *nctx;
 
864
    uint8_t *body;
 
865
    size_t blen;
 
866
    int ret;
 
867
    int ncret;
 
868
 
 
869
    ret = ENOENT;
 
870
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
871
 
 
872
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
873
    if (!cmdctx) {
 
874
        return ENOMEM;
 
875
    }
 
876
    cmdctx->cctx = cctx;
 
877
 
 
878
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
879
    if (!dctx) {
 
880
        ret = ENOMEM;
 
881
        goto done;
 
882
    }
 
883
    dctx->cmdctx = cmdctx;
 
884
 
 
885
    /* get uid to query */
 
886
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
887
 
 
888
    if (blen != sizeof(uint32_t)) {
 
889
        ret = EINVAL;
 
890
        goto done;
 
891
    }
 
892
    cmdctx->id = *((uint32_t *)body);
 
893
 
 
894
    /* this is a multidomain search */
 
895
    cmdctx->check_next = true;
 
896
 
 
897
    for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
898
        /* verify this user has not yet been negatively cached,
 
899
         * or has been permanently filtered */
 
900
        ncret = nss_ncache_check_uid(nctx->ncache, nctx->neg_timeout,
 
901
                                     cmdctx->id);
 
902
        if (ncret == EEXIST) {
 
903
            DEBUG(3, ("Uid [%lu] does not exist! (negative cache)\n",
 
904
                      (unsigned long)cmdctx->id));
 
905
            continue;
 
906
        }
 
907
 
 
908
        /* check that the uid is valid for this domain */
 
909
        if ((dom->id_min && (cmdctx->id < dom->id_min)) ||
 
910
            (dom->id_max && (cmdctx->id > dom->id_max))) {
 
911
            DEBUG(4, ("Uid [%lu] does not exist in domain [%s]! "
 
912
                      "(id out of range)\n",
 
913
                      (unsigned long)cmdctx->id, dom->name));
 
914
            continue;
 
915
        }
 
916
 
 
917
        dctx->domain = dom;
 
918
        dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
919
 
 
920
        DEBUG(4, ("Requesting info for [%lu@%s]\n",
 
921
                  cmdctx->id, dctx->domain->name));
 
922
 
 
923
        ret = sysdb_getpwuid(cmdctx, cctx->rctx->sysdb,
 
924
                             dctx->domain, cmdctx->id,
 
925
                             nss_cmd_getpwuid_callback, dctx);
 
926
        if (ret != EOK) {
 
927
            DEBUG(1, ("Failed to make request to our cache!\n"));
 
928
        }
 
929
 
 
930
        break;
 
931
    }
 
932
 
 
933
done:
 
934
    if (ret != EOK) {
 
935
        if (ret == ENOENT) {
 
936
            /* we do not have any entry to return */
 
937
            ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
938
                                 sss_packet_get_cmd(cctx->creq->in),
 
939
                                 &cctx->creq->out);
 
940
            if (ret == EOK) {
 
941
                sss_packet_get_body(cctx->creq->out, &body, &blen);
 
942
                ((uint32_t *)body)[0] = 0; /* 0 results */
 
943
                ((uint32_t *)body)[1] = 0; /* reserved */
 
944
            }
 
945
        }
 
946
        if (ret != EOK) {
 
947
            ret = nss_cmd_send_error(cmdctx, ret);
 
948
        }
 
949
        if (ret == EOK) {
 
950
            sss_cmd_done(cctx, cmdctx);
 
951
        }
 
952
        return ret;
 
953
    }
 
954
 
 
955
    return EOK;
 
956
}
 
957
 
 
958
/* to keep it simple at this stage we are retrieving the
 
959
 * full enumeration again for each request for each process
 
960
 * and we also block on setpwent() for the full time needed
 
961
 * to retrieve the data. And endpwent() frees all the data.
 
962
 * Next steps are:
 
963
 * - use an nsssrv wide cache with data already structured
 
964
 *   so that it can be immediately returned (see nscd way)
 
965
 * - use mutexes so that setpwent() can return immediately
 
966
 *   even if the data is still being fetched
 
967
 * - make getpwent() wait on the mutex
 
968
 */
 
969
static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx);
 
970
 
 
971
static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min,
 
972
                                      const char *err_msg, void *ptr);
 
973
 
 
974
static void nss_cmd_setpwent_callback(void *ptr, int status,
 
975
                                      struct ldb_result *res)
 
976
{
 
977
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
978
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
979
    struct cli_ctx *cctx = cmdctx->cctx;
 
980
    struct sss_domain_info *dom;
 
981
    struct getent_ctx *pctx;
 
982
    struct nss_ctx *nctx;
 
983
    int timeout;
 
984
    int ret;
 
985
 
 
986
    if (status != LDB_SUCCESS) {
 
987
        ret = nss_cmd_send_error(cmdctx, ENOENT);
 
988
        if (ret != EOK) {
 
989
            NSS_CMD_FATAL_ERROR(cctx);
 
990
        }
 
991
        sss_cmd_done(cctx, cmdctx);
 
992
        return;
 
993
    }
 
994
 
 
995
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
996
    pctx = nctx->pctx;
 
997
    if (pctx == NULL) {
 
998
        pctx = talloc_zero(nctx, struct getent_ctx);
 
999
        if (!pctx) {
 
1000
            ret = nss_cmd_send_error(cmdctx, ENOMEM);
 
1001
            if (ret != EOK) {
 
1002
                NSS_CMD_FATAL_ERROR(cctx);
 
1003
            }
 
1004
            sss_cmd_done(cctx, cmdctx);
 
1005
            return;
 
1006
        }
 
1007
        nctx->pctx = pctx;
 
1008
    }
 
1009
 
 
1010
    pctx->doms = talloc_realloc(pctx, pctx->doms, struct dom_ctx, pctx->num +1);
 
1011
    if (!pctx->doms) {
 
1012
        talloc_free(pctx);
 
1013
        nctx->pctx = NULL;
 
1014
        NSS_CMD_FATAL_ERROR(cctx);
 
1015
    }
 
1016
 
 
1017
    pctx->doms[pctx->num].domain = dctx->domain;
 
1018
    pctx->doms[pctx->num].res = talloc_steal(pctx->doms, res);
 
1019
    pctx->doms[pctx->num].cur = 0;
 
1020
 
 
1021
    pctx->num++;
 
1022
 
 
1023
    /* do not reply until all domain searches are done */
 
1024
    for (dom = dctx->domain->next; dom; dom = dom->next) {
 
1025
        if ((dom->enumerate & NSS_ENUM_USERS) != 0) break;
 
1026
    }
 
1027
    dctx->domain = dom;
 
1028
 
 
1029
    if (dctx->domain != NULL) {
 
1030
        if (cmdctx->enum_cached) {
 
1031
            dctx->check_provider = false;
 
1032
        } else {
 
1033
            dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
1034
        }
 
1035
 
 
1036
        if (dctx->check_provider) {
 
1037
            timeout = SSS_CLI_SOCKET_TIMEOUT;
 
1038
            ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
1039
                                       nss_cmd_setpw_dp_callback, dctx,
 
1040
                                       timeout, dom->name, SSS_DP_USER,
 
1041
                                       NULL, 0);
 
1042
        } else {
 
1043
            ret = sysdb_enumpwent(dctx, cctx->rctx->sysdb,
 
1044
                                  dctx->domain, NULL,
 
1045
                                  nss_cmd_setpwent_callback, dctx);
 
1046
        }
 
1047
        if (ret != EOK) {
 
1048
            /* FIXME: shutdown ? */
 
1049
            DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n",
 
1050
                      dom->name));
 
1051
 
 
1052
            ret = nss_cmd_send_error(cmdctx, ret);
 
1053
            if (ret != EOK) {
 
1054
                NSS_CMD_FATAL_ERROR(cctx);
 
1055
            }
 
1056
            sss_cmd_done(cctx, cmdctx);
 
1057
        }
 
1058
        return;
 
1059
    }
 
1060
 
 
1061
    /* set cache mark */
 
1062
    nctx->last_user_enum = time(NULL);
 
1063
 
 
1064
    if (cmdctx->immediate) {
 
1065
        /* this was a getpwent call w/o setpwent,
 
1066
         * return immediately one result */
 
1067
        ret = nss_cmd_getpwent_immediate(cmdctx);
 
1068
        if (ret != EOK) NSS_CMD_FATAL_ERROR(cctx);
 
1069
        return;
 
1070
    }
 
1071
 
 
1072
    /* create response packet */
 
1073
    ret = sss_packet_new(cctx->creq, 0,
 
1074
                         sss_packet_get_cmd(cctx->creq->in),
 
1075
                         &cctx->creq->out);
 
1076
    if (ret != EOK) {
 
1077
        NSS_CMD_FATAL_ERROR(cctx);
 
1078
    }
 
1079
    sss_cmd_done(cctx, cmdctx);
 
1080
}
 
1081
 
 
1082
static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min,
 
1083
                                      const char *err_msg, void *ptr)
 
1084
{
 
1085
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
1086
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
1087
    struct cli_ctx *cctx = cmdctx->cctx;
 
1088
    int ret;
 
1089
 
 
1090
    if (err_maj) {
 
1091
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
1092
                  "Error: %u, %u, %s\n"
 
1093
                  "Will try to return what we have in cache\n",
 
1094
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
1095
    }
 
1096
 
 
1097
    ret = sysdb_enumpwent(cmdctx, cctx->rctx->sysdb,
 
1098
                          dctx->domain, NULL,
 
1099
                          nss_cmd_setpwent_callback, dctx);
 
1100
    if (ret != EOK) {
 
1101
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
1102
 
 
1103
        ret = nss_cmd_send_error(cmdctx, ret);
 
1104
        if (ret != EOK) {
 
1105
            NSS_CMD_FATAL_ERROR(cctx);
 
1106
        }
 
1107
        sss_cmd_done(cctx, cmdctx);
 
1108
    }
 
1109
}
 
1110
 
 
1111
static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate)
 
1112
{
 
1113
    struct sss_domain_info *dom;
 
1114
    struct nss_cmd_ctx *cmdctx;
 
1115
    struct nss_dom_ctx *dctx;
 
1116
    struct nss_ctx *nctx;
 
1117
    time_t now = time(NULL);
 
1118
    int timeout;
 
1119
    uint8_t *body;
 
1120
    size_t blen;
 
1121
    int ret;
 
1122
 
 
1123
    DEBUG(4, ("Requesting info for all users\n"));
 
1124
 
 
1125
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
1126
    talloc_free(nctx->pctx);
 
1127
    nctx->pctx = NULL;
 
1128
 
 
1129
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
1130
    if (!cmdctx) {
 
1131
        return ENOMEM;
 
1132
    }
 
1133
    cmdctx->cctx = cctx;
 
1134
    cmdctx->immediate = immediate;
 
1135
 
 
1136
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
1137
    if (!dctx) {
 
1138
        ret = ENOMEM;
 
1139
        goto done;
 
1140
    }
 
1141
    dctx->cmdctx = cmdctx;
 
1142
 
 
1143
    /* do not query backends if we have a recent enumeration */
 
1144
    if (nctx->enum_cache_timeout) {
 
1145
        if (nctx->last_user_enum +
 
1146
            nctx->enum_cache_timeout > now) {
 
1147
            cmdctx->enum_cached = true;
 
1148
        }
 
1149
    }
 
1150
 
 
1151
    /* check if enumeration is enabled in any domain */
 
1152
    for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
1153
        if ((dom->enumerate & NSS_ENUM_USERS) != 0) break;
 
1154
    }
 
1155
    dctx->domain = dom;
 
1156
 
 
1157
    if (dctx->domain == NULL) {
 
1158
        DEBUG(2, ("Enumeration disabled on all domains!\n"));
 
1159
        ret = ENOENT;
 
1160
        goto done;
 
1161
    }
 
1162
 
 
1163
    if (cmdctx->enum_cached) {
 
1164
        dctx->check_provider = false;
 
1165
    } else {
 
1166
        dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
1167
    }
 
1168
 
 
1169
    if (dctx->check_provider) {
 
1170
        timeout = SSS_CLI_SOCKET_TIMEOUT;
 
1171
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
1172
                                   nss_cmd_setpw_dp_callback, dctx,
 
1173
                                   timeout, dom->name, SSS_DP_USER,
 
1174
                                   NULL, 0);
 
1175
    } else {
 
1176
        ret = sysdb_enumpwent(dctx, cctx->rctx->sysdb,
 
1177
                              dctx->domain, NULL,
 
1178
                              nss_cmd_setpwent_callback, dctx);
 
1179
    }
 
1180
    if (ret != EOK) {
 
1181
        /* FIXME: shutdown ? */
 
1182
        DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n",
 
1183
                  dom->name));
 
1184
    }
 
1185
 
 
1186
done:
 
1187
    if (ret != EOK) {
 
1188
        if (ret == ENOENT) {
 
1189
            if (cmdctx->immediate) {
 
1190
                /* we do not have any entry to return */
 
1191
                ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
1192
                                     sss_packet_get_cmd(cctx->creq->in),
 
1193
                                     &cctx->creq->out);
 
1194
                if (ret == EOK) {
 
1195
                    sss_packet_get_body(cctx->creq->out, &body, &blen);
 
1196
                    ((uint32_t *)body)[0] = 0; /* 0 results */
 
1197
                    ((uint32_t *)body)[1] = 0; /* reserved */
 
1198
                }
 
1199
            }
 
1200
            else {
 
1201
                /* create response packet */
 
1202
                ret = sss_packet_new(cctx->creq, 0,
 
1203
                                     sss_packet_get_cmd(cctx->creq->in),
 
1204
                                     &cctx->creq->out);
 
1205
            }
 
1206
        }
 
1207
        if (ret != EOK) {
 
1208
            ret = nss_cmd_send_error(cmdctx, ret);
 
1209
        }
 
1210
        if (ret == EOK) {
 
1211
            sss_cmd_done(cctx, cmdctx);
 
1212
        }
 
1213
        return ret;
 
1214
    }
 
1215
 
 
1216
    return EOK;
 
1217
}
 
1218
 
 
1219
static int nss_cmd_setpwent(struct cli_ctx *cctx)
 
1220
{
 
1221
    return nss_cmd_setpwent_ext(cctx, false);
 
1222
}
 
1223
 
 
1224
 
 
1225
static int nss_cmd_retpwent(struct cli_ctx *cctx, int num)
 
1226
{
 
1227
    struct nss_ctx *nctx;
 
1228
    struct getent_ctx *pctx;
 
1229
    struct ldb_message **msgs = NULL;
 
1230
    struct dom_ctx *pdom = NULL;
 
1231
    int n = 0;
 
1232
    int ret;
 
1233
 
 
1234
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
1235
    pctx = nctx->pctx;
 
1236
 
 
1237
retry:
 
1238
    if (pctx->cur >= pctx->num) goto none;
 
1239
 
 
1240
    pdom = &pctx->doms[pctx->cur];
 
1241
 
 
1242
    n = pdom->res->count - pdom->cur;
 
1243
    if (n == 0 && (pctx->cur+1 < pctx->num)) {
 
1244
        pctx->cur++;
 
1245
        pdom = &pctx->doms[pctx->cur];
 
1246
        n = pdom->res->count - pdom->cur;
 
1247
    }
 
1248
 
 
1249
    if (!n) goto none;
 
1250
 
 
1251
    if (n > num) n = num;
 
1252
 
 
1253
    msgs = &(pdom->res->msgs[pdom->cur]);
 
1254
    pdom->cur += n;
 
1255
 
 
1256
    ret = fill_pwent(cctx->creq->out, pdom->domain, nctx, true, msgs, n);
 
1257
    if (ret == ENOENT) goto retry;
 
1258
    return ret;
 
1259
 
 
1260
none:
 
1261
    return fill_empty(cctx->creq->out);
 
1262
}
 
1263
 
 
1264
/* used only if a process calls getpwent() without first calling setpwent()
 
1265
 */
 
1266
static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx)
 
1267
{
 
1268
    struct cli_ctx *cctx = cmdctx->cctx;
 
1269
    uint8_t *body;
 
1270
    size_t blen;
 
1271
    uint32_t num;
 
1272
    int ret;
 
1273
 
 
1274
    /* get max num of entries to return in one call */
 
1275
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
1276
    if (blen != sizeof(uint32_t)) {
 
1277
        return EINVAL;
 
1278
    }
 
1279
    num = *((uint32_t *)body);
 
1280
 
 
1281
    /* create response packet */
 
1282
    ret = sss_packet_new(cctx->creq, 0,
 
1283
                         sss_packet_get_cmd(cctx->creq->in),
 
1284
                         &cctx->creq->out);
 
1285
    if (ret != EOK) {
 
1286
        return ret;
 
1287
    }
 
1288
 
 
1289
    ret = nss_cmd_retpwent(cctx, num);
 
1290
 
 
1291
    sss_packet_set_error(cctx->creq->out, ret);
 
1292
    sss_cmd_done(cctx, cmdctx);
 
1293
 
 
1294
    return EOK;
 
1295
}
 
1296
 
 
1297
static int nss_cmd_getpwent(struct cli_ctx *cctx)
 
1298
{
 
1299
    struct nss_ctx *nctx;
 
1300
    struct nss_cmd_ctx *cmdctx;
 
1301
 
 
1302
    DEBUG(4, ("Requesting info for all accounts\n"));
 
1303
 
 
1304
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
1305
 
 
1306
    /* see if we need to trigger an implicit setpwent() */
 
1307
    if (nctx->pctx == NULL) {
 
1308
        nctx->pctx = talloc_zero(nctx, struct getent_ctx);
 
1309
        if (!nctx->pctx) return ENOMEM;
 
1310
 
 
1311
        return nss_cmd_setpwent_ext(cctx, true);
 
1312
    }
 
1313
 
 
1314
    cmdctx = talloc(cctx, struct nss_cmd_ctx);
 
1315
    if (!cmdctx) {
 
1316
        return ENOMEM;
 
1317
    }
 
1318
    cmdctx->cctx = cctx;
 
1319
 
 
1320
    return nss_cmd_getpwent_immediate(cmdctx);
 
1321
}
 
1322
 
 
1323
static int nss_cmd_endpwent(struct cli_ctx *cctx)
 
1324
{
 
1325
    struct nss_ctx *nctx;
 
1326
    int ret;
 
1327
 
 
1328
    DEBUG(4, ("Terminating request info for all accounts\n"));
 
1329
 
 
1330
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
1331
 
 
1332
    /* create response packet */
 
1333
    ret = sss_packet_new(cctx->creq, 0,
 
1334
                         sss_packet_get_cmd(cctx->creq->in),
 
1335
                         &cctx->creq->out);
 
1336
 
 
1337
    if (nctx->pctx == NULL) goto done;
 
1338
 
 
1339
    /* free results and reset */
 
1340
    talloc_free(nctx->pctx);
 
1341
    nctx->pctx = NULL;
 
1342
 
 
1343
done:
 
1344
    sss_cmd_done(cctx, NULL);
 
1345
    return EOK;
 
1346
}
 
1347
 
 
1348
/****************************************************************************
 
1349
 * GROUP db related functions
 
1350
 ***************************************************************************/
 
1351
 
 
1352
static int fill_grent(struct sss_packet *packet,
 
1353
                      struct sss_domain_info *dom,
 
1354
                      struct nss_ctx *nctx,
 
1355
                      bool filter_groups,
 
1356
                      struct ldb_message **msgs,
 
1357
                      int count)
 
1358
{
 
1359
    struct ldb_message_element *el;
 
1360
    struct ldb_message *msg;
 
1361
    uint8_t *body;
 
1362
    const char *name;
 
1363
    uint32_t gid, uid;
 
1364
    size_t rsize, rp, blen, mnump;
 
1365
    int i, j, n, t, ret, num, memnum;
 
1366
    bool get_members;
 
1367
    bool skip_members;
 
1368
    size_t dom_len = 0;
 
1369
    size_t name_len;
 
1370
    int delim = 1;
 
1371
    bool add_domain = dom->fqnames;
 
1372
    const char *domain = dom->name;
 
1373
    const char *namefmt = nctx->rctx->names->fq_fmt;
 
1374
    bool packet_initialized = false;
 
1375
    int ncret;
 
1376
    bool legacy = false;
 
1377
 
 
1378
    if (add_domain) dom_len = strlen(domain);
 
1379
 
 
1380
    rp = 2*sizeof(uint32_t);
 
1381
 
 
1382
    num = 0;
 
1383
    mnump = 0;
 
1384
    memnum = 0;
 
1385
    get_members = false;
 
1386
    skip_members = false;
 
1387
    for (i = 0; i < count; i++) {
 
1388
        msg = msgs[i];
 
1389
 
 
1390
        /* new group */
 
1391
        if (ldb_msg_check_string_attribute(msg, "objectClass",
 
1392
                                                SYSDB_GROUP_CLASS)) {
 
1393
            if (get_members) {
 
1394
                /* this marks the end of a previous group */
 
1395
                sss_packet_get_body(packet, &body, &blen);
 
1396
                ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */
 
1397
                get_members = false;
 
1398
            }
 
1399
 
 
1400
            /* find group name/gid */
 
1401
            name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
 
1402
            gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
 
1403
            if (!name || !gid) {
 
1404
                DEBUG(1, ("Incomplete group object for %s[%llu]! Aborting\n",
 
1405
                          name?name:"<NULL>", (unsigned long long int)gid));
 
1406
                num = 0;
 
1407
                goto done;
 
1408
            }
 
1409
 
 
1410
            skip_members = false;
 
1411
 
 
1412
            if (filter_groups) {
 
1413
                ncret = nss_ncache_check_group(nctx->ncache,
 
1414
                                             nctx->neg_timeout, domain, name);
 
1415
                if (ncret == EEXIST) {
 
1416
                    DEBUG(4, ("Group [%s@%s] filtered out! (negative cache)\n",
 
1417
                              name, domain));
 
1418
                    skip_members = true;
 
1419
                    continue;
 
1420
                }
 
1421
            }
 
1422
 
 
1423
            /* check that the gid is valid for this domain */
 
1424
            if ((dom->id_min && (gid < dom->id_min)) ||
 
1425
                (dom->id_max && (gid > dom->id_max))) {
 
1426
                    DEBUG(4, ("User [%s@%s] filtered out! (id out of range)\n",
 
1427
                              name, domain));
 
1428
                skip_members = true;
 
1429
                continue;
 
1430
            }
 
1431
 
 
1432
            if (!packet_initialized) {
 
1433
                /* first 2 fields (len and reserved), filled up later */
 
1434
                ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
 
1435
                if (ret != EOK) return ret;
 
1436
                packet_initialized = true;
 
1437
            }
 
1438
 
 
1439
            /* fill in gid and name and set pointer for number of members */
 
1440
            name_len = strlen(name) + 1;
 
1441
            if (add_domain) name_len += delim + dom_len;
 
1442
            rsize = 2 * sizeof(uint32_t) + name_len + 2;
 
1443
 
 
1444
            ret = sss_packet_grow(packet, rsize);
 
1445
            if (ret != EOK) {
 
1446
                num = 0;
 
1447
                goto done;
 
1448
            }
 
1449
            sss_packet_get_body(packet, &body, &blen);
 
1450
 
 
1451
            /*  0-3: 64bit number gid */
 
1452
            rp = blen - rsize;
 
1453
            ((uint32_t *)(&body[rp]))[0] = gid;
 
1454
            rp += sizeof(uint32_t);
 
1455
 
 
1456
            /*  4-7: 32bit unsigned number of members */
 
1457
            ((uint32_t *)(&body[rp]))[0] = 0; /* init members num to 0 */
 
1458
            mnump = rp; /* keep around members num pointer to set later */
 
1459
            rp += sizeof(uint32_t);
 
1460
 
 
1461
            /*  8-X: sequence of strings (name, passwd, mem..) */
 
1462
            if (add_domain) {
 
1463
                ret = snprintf((char *)&body[rp], name_len, namefmt, name, domain);
 
1464
                if (ret >= name_len) {
 
1465
                    /* need more space, got creative with the print format ? */
 
1466
                    t = ret - name_len + 1;
 
1467
                    ret = sss_packet_grow(packet, t);
 
1468
                    if (ret != EOK) {
 
1469
                        num = 0;
 
1470
                        goto done;
 
1471
                    }
 
1472
                    delim += t;
 
1473
                    name_len += t;
 
1474
                    sss_packet_get_body(packet, &body, &blen);
 
1475
 
 
1476
                    /* retry */
 
1477
                    ret = snprintf((char *)&body[rp], name_len, namefmt, name, domain);
 
1478
                }
 
1479
 
 
1480
                if (ret != name_len-1) {
 
1481
                    DEBUG(1, ("Failed to generate a fully qualified name for user "
 
1482
                              "[%s] in [%s]! Skipping user.\n", name, domain));
 
1483
                    continue;
 
1484
                }
 
1485
            } else {
 
1486
                memcpy(&body[rp], name, name_len);
 
1487
            }
 
1488
            rp += name_len;
 
1489
 
 
1490
            body[rp] = 'x'; /* group passwd field */
 
1491
            body[rp+1] = '\0';
 
1492
 
 
1493
            memnum = 0;
 
1494
            num++;
 
1495
 
 
1496
            /* legacy style group, members are in SYSDB_LEGACY_MEMBER */
 
1497
            el = ldb_msg_find_element(msg, SYSDB_LEGACY_MEMBER);
 
1498
            if (el) {
 
1499
                /* legacy */
 
1500
                legacy = true;
 
1501
                memnum = el->num_values;
 
1502
                n = 0;
 
1503
                for (j = 0; j < memnum; j++) {
 
1504
 
 
1505
                    name = (char *)el->values[j].data;
 
1506
 
 
1507
                    if (nctx->filter_users_in_groups) {
 
1508
                        ncret = nss_ncache_check_user(nctx->ncache,
 
1509
                                                      nctx->neg_timeout,
 
1510
                                                      domain, name);
 
1511
                        if (ncret == EEXIST) {
 
1512
                            DEBUG(4,("User [%s@%s] filtered out! (negative cache)\n",
 
1513
                                      name, domain));
 
1514
                            continue;
 
1515
                        }
 
1516
                    }
 
1517
 
 
1518
                    name_len = el->values[j].length + 1;
 
1519
                    if (add_domain) name_len += delim + dom_len;
 
1520
 
 
1521
                    rsize = name_len;
 
1522
                    ret = sss_packet_grow(packet, rsize);
 
1523
                    if (ret != EOK) {
 
1524
                        num = 0;
 
1525
                        goto done;
 
1526
                    }
 
1527
 
 
1528
                    sss_packet_get_body(packet, &body, &blen);
 
1529
                    rp = blen - rsize;
 
1530
 
 
1531
                    if (add_domain) {
 
1532
                        ret = snprintf((char *)&body[rp], name_len, namefmt, name, domain);
 
1533
                        if (ret >= name_len) {
 
1534
                            /* need more space, got creative with the print format ? */
 
1535
                            t = ret - name_len + 1;
 
1536
                            ret = sss_packet_grow(packet, t);
 
1537
                            if (ret != EOK) {
 
1538
                                num = 0;
 
1539
                                goto done;
 
1540
                            }
 
1541
                            delim += t;
 
1542
                            name_len += t;
 
1543
                            sss_packet_get_body(packet, &body, &blen);
 
1544
 
 
1545
                            /* retry */
 
1546
                            ret = snprintf((char *)&body[rp], name_len, namefmt, name, domain);
 
1547
                        }
 
1548
 
 
1549
                        if (ret != name_len-1) {
 
1550
                            DEBUG(1, ("Failed to generate a fully qualified name for user "
 
1551
                                      "[%s] in [%s]! Skipping user.\n", name, domain));
 
1552
                            continue;
 
1553
                        }
 
1554
                    } else {
 
1555
                        memcpy(&body[rp], name, name_len);
 
1556
                    }
 
1557
                    rp += name_len;
 
1558
                    body[blen-1] = '\0';
 
1559
 
 
1560
                    n++;
 
1561
                }
 
1562
 
 
1563
                sss_packet_get_body(packet, &body, &blen);
 
1564
                ((uint32_t *)(&body[mnump]))[0] = n; /* num members */
 
1565
 
 
1566
            }  else {
 
1567
                get_members = true;
 
1568
            }
 
1569
 
 
1570
            continue;
 
1571
        }
 
1572
 
 
1573
        if (skip_members) continue;
 
1574
 
 
1575
        if (!get_members) {
 
1576
            DEBUG(1, ("Wrong object found on stack! Aborting\n"));
 
1577
            num = 0;
 
1578
            goto done;
 
1579
        }
 
1580
 
 
1581
        /* member */
 
1582
        if (ldb_msg_check_string_attribute(msg, "objectClass",
 
1583
                                                SYSDB_USER_CLASS)) {
 
1584
 
 
1585
            name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
 
1586
            uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
 
1587
            if (!name || !uid) {
 
1588
                DEBUG(1, ("Incomplete user object! Aborting\n"));
 
1589
                num = 0;
 
1590
                goto done;
 
1591
            }
 
1592
 
 
1593
            if (nctx->filter_users_in_groups) {
 
1594
                ncret = nss_ncache_check_user(nctx->ncache,
 
1595
                                            nctx->neg_timeout, domain, name);
 
1596
                if (ncret == EEXIST) {
 
1597
                    DEBUG(4, ("User [%s@%s] filtered out! (negative cache)\n",
 
1598
                              name, domain));
 
1599
                    continue;
 
1600
                }
 
1601
            }
 
1602
 
 
1603
            /* check that the uid is valid for this domain */
 
1604
            if ((dom->id_min && (uid < dom->id_min)) ||
 
1605
                (dom->id_max && (uid > dom->id_max))) {
 
1606
                    DEBUG(4, ("User [%s@%s] filtered out! (id out of range)\n",
 
1607
                              name, domain));
 
1608
                continue;
 
1609
            }
 
1610
 
 
1611
            name_len = strlen(name) + 1;
 
1612
            if (add_domain) name_len += delim + dom_len;
 
1613
 
 
1614
            rsize = name_len;
 
1615
            ret = sss_packet_grow(packet, rsize);
 
1616
            if (ret != EOK) {
 
1617
                num = 0;
 
1618
                goto done;
 
1619
            }
 
1620
            sss_packet_get_body(packet, &body, &blen);
 
1621
            rp = blen - rsize;
 
1622
 
 
1623
            if (add_domain) {
 
1624
                ret = snprintf((char *)&body[rp], name_len, namefmt, name, domain);
 
1625
                if (ret >= name_len) {
 
1626
                    /* need more space, got creative with the print format ? */
 
1627
                    t = ret - name_len + 1;
 
1628
                    ret = sss_packet_grow(packet, t);
 
1629
                    if (ret != EOK) {
 
1630
                        num = 0;
 
1631
                        goto done;
 
1632
                    }
 
1633
                    delim += t;
 
1634
                    name_len += t;
 
1635
                    sss_packet_get_body(packet, &body, &blen);
 
1636
 
 
1637
                    /* retry */
 
1638
                    ret = snprintf((char *)&body[rp], name_len, namefmt, name, domain);
 
1639
                }
 
1640
 
 
1641
                if (ret != name_len-1) {
 
1642
                    DEBUG(1, ("Failed to generate a fully qualified name for user "
 
1643
                              "[%s] in [%s]! Skipping user.\n", name, domain));
 
1644
                    continue;
 
1645
                }
 
1646
            } else {
 
1647
                memcpy(&body[rp], name, name_len);
 
1648
            }
 
1649
            rp += name_len;
 
1650
            memnum++;
 
1651
 
 
1652
            continue;
 
1653
        }
 
1654
 
 
1655
        DEBUG(1, ("Wrong object found on stack! Aborting\n"));
 
1656
        num = 0;
 
1657
        goto done;
 
1658
    }
 
1659
 
 
1660
    if (mnump && !legacy) {
 
1661
        /* fill in the last group member count */
 
1662
        sss_packet_get_body(packet, &body, &blen);
 
1663
        ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */
 
1664
    }
 
1665
 
 
1666
done:
 
1667
    /* if there are no results just return ENOENT,
 
1668
     * let the caller decide if this is the last packet or not */
 
1669
    if (!packet_initialized) return ENOENT;
 
1670
 
 
1671
    sss_packet_get_body(packet, &body, &blen);
 
1672
    ((uint32_t *)body)[0] = num; /* num results */
 
1673
    ((uint32_t *)body)[1] = 0; /* reserved */
 
1674
 
 
1675
    return EOK;
 
1676
}
 
1677
 
 
1678
static void nss_cmd_getgrnam_dp_callback(uint16_t err_maj, uint32_t err_min,
 
1679
                                      const char *err_msg, void *ptr);
 
1680
 
 
1681
static void nss_cmd_getgrnam_callback(void *ptr, int status,
 
1682
                                   struct ldb_result *res)
 
1683
{
 
1684
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
1685
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
1686
    struct cli_ctx *cctx = cmdctx->cctx;
 
1687
    struct sss_domain_info *dom;
 
1688
    struct nss_ctx *nctx;
 
1689
    int timeout;
 
1690
    uint64_t lastUpdate;
 
1691
    uint8_t *body;
 
1692
    size_t blen;
 
1693
    bool call_provider = false;
 
1694
    bool neghit = false;
 
1695
    int ncret;
 
1696
    int ret;
 
1697
 
 
1698
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
1699
 
 
1700
    if (status != LDB_SUCCESS) {
 
1701
        ret = nss_cmd_send_error(cmdctx, status);
 
1702
        if (ret != EOK) {
 
1703
            NSS_CMD_FATAL_ERROR(cctx);
 
1704
        }
 
1705
        sss_cmd_done(cctx, cmdctx);
 
1706
        return;
 
1707
    }
 
1708
 
 
1709
    if (dctx->check_provider) {
 
1710
        switch (res->count) {
 
1711
        case 0:
 
1712
            call_provider = true;
 
1713
            break;
 
1714
 
 
1715
        default:
 
1716
            timeout = nctx->cache_timeout;
 
1717
 
 
1718
            lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
 
1719
                                                     SYSDB_LAST_UPDATE, 0);
 
1720
            if (lastUpdate + timeout < time(NULL)) {
 
1721
                call_provider = true;
 
1722
            }
 
1723
        }
 
1724
    }
 
1725
 
 
1726
    if (call_provider) {
 
1727
 
 
1728
        /* dont loop forever :-) */
 
1729
        dctx->check_provider = false;
 
1730
        timeout = SSS_CLI_SOCKET_TIMEOUT/2;
 
1731
 
 
1732
        /* keep around current data in case backend is offline */
 
1733
        if (res->count) {
 
1734
            dctx->res = talloc_steal(dctx, res);
 
1735
        }
 
1736
 
 
1737
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
1738
                                   nss_cmd_getgrnam_dp_callback, dctx,
 
1739
                                   timeout, dctx->domain->name, SSS_DP_GROUP,
 
1740
                                   cmdctx->name, 0);
 
1741
        if (ret != EOK) {
 
1742
            DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
 
1743
                      ret, strerror(ret)));
 
1744
            ret = nss_cmd_send_error(cmdctx, ret);
 
1745
            if (ret != EOK) {
 
1746
                NSS_CMD_FATAL_ERROR(cctx);
 
1747
            }
 
1748
            sss_cmd_done(cctx, cmdctx);
 
1749
        }
 
1750
        return;
 
1751
    }
 
1752
 
 
1753
    switch (res->count) {
 
1754
    case 0:
 
1755
        if (cmdctx->check_next) {
 
1756
 
 
1757
            ret = EOK;
 
1758
 
 
1759
            /* skip domains that require FQnames or have negative caches */
 
1760
            for (dom = dctx->domain->next; dom; dom = dom->next) {
 
1761
 
 
1762
                if (dom->fqnames) continue;
 
1763
 
 
1764
                ncret = nss_ncache_check_group(nctx->ncache,
 
1765
                                               nctx->neg_timeout,
 
1766
                                               dom->name, cmdctx->name);
 
1767
                if (ncret == ENOENT) break;
 
1768
 
 
1769
                neghit = true;
 
1770
            }
 
1771
            /* reset neghit if we still have a domain to check */
 
1772
            if (dom) neghit = false;
 
1773
 
 
1774
            if (neghit) {
 
1775
                DEBUG(2, ("Group [%s] does not exist! (negative cache)\n",
 
1776
                          cmdctx->name));
 
1777
                ret = ENOENT;
 
1778
            }
 
1779
            if (dom == NULL) {
 
1780
                DEBUG(2, ("No matching domain found for [%s], fail!\n",
 
1781
                          cmdctx->name));
 
1782
                ret = ENOENT;
 
1783
            }
 
1784
 
 
1785
            if (ret == EOK) {
 
1786
                dctx->domain = dom;
 
1787
                dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
1788
                if (dctx->res) talloc_free(res);
 
1789
                dctx->res = NULL;
 
1790
 
 
1791
                DEBUG(4, ("Requesting info for [%s@%s]\n",
 
1792
                          cmdctx->name, dctx->domain->name));
 
1793
 
 
1794
                ret = sysdb_getgrnam(cmdctx, cctx->rctx->sysdb,
 
1795
                                     dctx->domain, cmdctx->name,
 
1796
                                     nss_cmd_getgrnam_callback, dctx);
 
1797
                if (ret != EOK) {
 
1798
                    DEBUG(1, ("Failed to make request to our cache!\n"));
 
1799
                }
 
1800
            }
 
1801
 
 
1802
            /* we made another call, end here */
 
1803
            if (ret == EOK) return;
 
1804
        }
 
1805
 
 
1806
 
 
1807
        DEBUG(2, ("No results for getgrnam call\n"));
 
1808
 
 
1809
        /* set negative cache only if not result of cache check */
 
1810
        if (!neghit) {
 
1811
            ret = nss_ncache_set_group(nctx->ncache, false,
 
1812
                                       dctx->domain->name, cmdctx->name);
 
1813
            if (ret != EOK) {
 
1814
                NSS_CMD_FATAL_ERROR(cctx);
 
1815
            }
 
1816
        }
 
1817
 
 
1818
        ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
1819
                             sss_packet_get_cmd(cctx->creq->in),
 
1820
                             &cctx->creq->out);
 
1821
        if (ret != EOK) {
 
1822
            NSS_CMD_FATAL_ERROR(cctx);
 
1823
        }
 
1824
        sss_packet_get_body(cctx->creq->out, &body, &blen);
 
1825
        ((uint32_t *)body)[0] = 0; /* 0 results */
 
1826
        ((uint32_t *)body)[1] = 0; /* reserved */
 
1827
        break;
 
1828
 
 
1829
    default:
 
1830
 
 
1831
        DEBUG(6, ("Returning info for group [%s]\n", cmdctx->name));
 
1832
 
 
1833
        /* create response packet */
 
1834
        ret = sss_packet_new(cctx->creq, 0,
 
1835
                             sss_packet_get_cmd(cctx->creq->in),
 
1836
                             &cctx->creq->out);
 
1837
        if (ret != EOK) {
 
1838
            NSS_CMD_FATAL_ERROR(cctx);
 
1839
        }
 
1840
        ret = fill_grent(cctx->creq->out,
 
1841
                         dctx->domain,
 
1842
                         nctx, false,
 
1843
                         res->msgs, res->count);
 
1844
        if (ret == ENOENT) {
 
1845
            ret = fill_empty(cctx->creq->out);
 
1846
        }
 
1847
        sss_packet_set_error(cctx->creq->out, ret);
 
1848
    }
 
1849
 
 
1850
    sss_cmd_done(cctx, cmdctx);
 
1851
}
 
1852
 
 
1853
static void nss_cmd_getgrnam_dp_callback(uint16_t err_maj, uint32_t err_min,
 
1854
                                      const char *err_msg, void *ptr)
 
1855
{
 
1856
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
1857
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
1858
    struct cli_ctx *cctx = cmdctx->cctx;
 
1859
    int ret;
 
1860
 
 
1861
    if (err_maj) {
 
1862
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
1863
                  "Error: %u, %u, %s\n"
 
1864
                  "Will try to return what we have in cache\n",
 
1865
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
1866
 
 
1867
        if (!dctx->res) {
 
1868
            /* return 0 results */
 
1869
            dctx->res = talloc_zero(dctx, struct ldb_result);
 
1870
            if (!dctx->res) {
 
1871
                ret = ENOMEM;
 
1872
                goto done;
 
1873
            }
 
1874
        }
 
1875
 
 
1876
        nss_cmd_getgrnam_callback(dctx, LDB_SUCCESS, dctx->res);
 
1877
        return;
 
1878
    }
 
1879
 
 
1880
    ret = sysdb_getgrnam(cmdctx, cctx->rctx->sysdb,
 
1881
                         dctx->domain, cmdctx->name,
 
1882
                         nss_cmd_getgrnam_callback, dctx);
 
1883
 
 
1884
done:
 
1885
    if (ret != EOK) {
 
1886
        DEBUG(1, ("Failed to make request to our cache! (%d [%s])\n",
 
1887
                  ret, strerror(ret)));
 
1888
 
 
1889
        ret = nss_cmd_send_error(cmdctx, ret);
 
1890
        if (ret != EOK) {
 
1891
            NSS_CMD_FATAL_ERROR(cctx);
 
1892
        }
 
1893
        sss_cmd_done(cctx, cmdctx);
 
1894
    }
 
1895
}
 
1896
 
 
1897
static int nss_cmd_getgrnam(struct cli_ctx *cctx)
 
1898
{
 
1899
    struct nss_cmd_ctx *cmdctx;
 
1900
    struct nss_dom_ctx *dctx;
 
1901
    struct sss_domain_info *dom;
 
1902
    struct nss_ctx *nctx;
 
1903
    const char *rawname;
 
1904
    char *domname;
 
1905
    uint8_t *body;
 
1906
    size_t blen;
 
1907
    int ret;
 
1908
    int ncret;
 
1909
    bool neghit = false;
 
1910
 
 
1911
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
1912
 
 
1913
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
1914
    if (!cmdctx) {
 
1915
        return ENOMEM;
 
1916
    }
 
1917
    cmdctx->cctx = cctx;
 
1918
 
 
1919
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
1920
    if (!dctx) {
 
1921
        ret = ENOMEM;
 
1922
        goto done;
 
1923
    }
 
1924
    dctx->cmdctx = cmdctx;
 
1925
 
 
1926
    /* get user name to query */
 
1927
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
1928
 
 
1929
    /* if not terminated fail */
 
1930
    if (body[blen -1] != '\0') {
 
1931
        ret = EINVAL;
 
1932
        goto done;
 
1933
    }
 
1934
    rawname = (const char *)body;
 
1935
 
 
1936
    domname = NULL;
 
1937
    ret = sss_parse_name(cmdctx, cctx->rctx->names, rawname,
 
1938
                         &domname, &cmdctx->name);
 
1939
    if (ret != EOK) {
 
1940
        DEBUG(2, ("Invalid name received [%s]\n", rawname));
 
1941
        ret = ENOENT;
 
1942
        goto done;
 
1943
    }
 
1944
 
 
1945
    DEBUG(4, ("Requesting info for [%s] from [%s]\n",
 
1946
              cmdctx->name, domname?domname:"<ALL>"));
 
1947
 
 
1948
    if (domname) {
 
1949
        dctx->domain = nss_get_dom(cctx->rctx->domains, domname);
 
1950
        if (!dctx->domain) {
 
1951
            ret = ENOENT;
 
1952
            goto done;
 
1953
        }
 
1954
 
 
1955
        /* verify this user has not yet been negatively cached,
 
1956
         * or has been permanently filtered */
 
1957
        ncret = nss_ncache_check_group(nctx->ncache, nctx->neg_timeout,
 
1958
                                       dctx->domain->name, cmdctx->name);
 
1959
        if (ncret == EEXIST) {
 
1960
            neghit = true;
 
1961
        }
 
1962
    }
 
1963
    else {
 
1964
        /* skip domains that require FQnames or have negative caches */
 
1965
        for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
1966
 
 
1967
            if (dom->fqnames) continue;
 
1968
 
 
1969
            /* verify this user has not yet been negatively cached,
 
1970
             * or has been permanently filtered */
 
1971
            ncret = nss_ncache_check_group(nctx->ncache, nctx->neg_timeout,
 
1972
                                           dom->name, cmdctx->name);
 
1973
            if (ncret == ENOENT) break;
 
1974
 
 
1975
            neghit = true;
 
1976
        }
 
1977
        /* reset neghit if we still have a domain to check */
 
1978
        if (dom) neghit = false;
 
1979
 
 
1980
        dctx->domain = dom;
 
1981
    }
 
1982
    if (neghit) {
 
1983
        DEBUG(2, ("Group [%s] does not exist! (negative cache)\n", rawname));
 
1984
        ret = ENOENT;
 
1985
        goto done;
 
1986
    }
 
1987
    if (dctx->domain == NULL) {
 
1988
        DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname));
 
1989
        ret = ENOENT;
 
1990
        goto done;
 
1991
    }
 
1992
 
 
1993
    dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
1994
 
 
1995
    if (!domname) {
 
1996
        /* this is a multidomain search */
 
1997
        cmdctx->check_next = true;
 
1998
    }
 
1999
 
 
2000
    DEBUG(4, ("Requesting info for [%s@%s]\n",
 
2001
              cmdctx->name, dctx->domain->name));
 
2002
 
 
2003
    ret = sysdb_getgrnam(cmdctx, cctx->rctx->sysdb,
 
2004
                         dctx->domain, cmdctx->name,
 
2005
                         nss_cmd_getgrnam_callback, dctx);
 
2006
    if (ret != EOK) {
 
2007
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
2008
    }
 
2009
 
 
2010
done:
 
2011
    if (ret != EOK) {
 
2012
        if (ret == ENOENT) {
 
2013
            /* we do not have any entry to return */
 
2014
            ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
2015
                                 sss_packet_get_cmd(cctx->creq->in),
 
2016
                                 &cctx->creq->out);
 
2017
            if (ret == EOK) {
 
2018
                sss_packet_get_body(cctx->creq->out, &body, &blen);
 
2019
                ((uint32_t *)body)[0] = 0; /* 0 results */
 
2020
                ((uint32_t *)body)[1] = 0; /* reserved */
 
2021
            }
 
2022
        }
 
2023
        if (ret != EOK) {
 
2024
            ret = nss_cmd_send_error(cmdctx, ret);
 
2025
        }
 
2026
        if (ret == EOK) {
 
2027
            sss_cmd_done(cctx, cmdctx);
 
2028
        }
 
2029
        return ret;
 
2030
    }
 
2031
 
 
2032
    return EOK;
 
2033
}
 
2034
 
 
2035
static void nss_cmd_getgrgid_dp_callback(uint16_t err_maj, uint32_t err_min,
 
2036
                                      const char *err_msg, void *ptr);
 
2037
 
 
2038
static void nss_cmd_getgrgid_callback(void *ptr, int status,
 
2039
                                      struct ldb_result *res)
 
2040
{
 
2041
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2042
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2043
    struct cli_ctx *cctx = cmdctx->cctx;
 
2044
    struct sss_domain_info *dom;
 
2045
    struct nss_ctx *nctx;
 
2046
    int timeout;
 
2047
    uint64_t lastUpdate;
 
2048
    uint8_t *body;
 
2049
    size_t blen;
 
2050
    bool call_provider = false;
 
2051
    bool neghit = false;
 
2052
    int ret;
 
2053
    int ncret;
 
2054
 
 
2055
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2056
 
 
2057
    if (status != LDB_SUCCESS) {
 
2058
        ret = nss_cmd_send_error(cmdctx, status);
 
2059
        if (ret != EOK) {
 
2060
            NSS_CMD_FATAL_ERROR(cctx);
 
2061
        }
 
2062
        sss_cmd_done(cctx, cmdctx);
 
2063
        return;
 
2064
    }
 
2065
 
 
2066
    if (dctx->check_provider) {
 
2067
        switch (res->count) {
 
2068
        case 0:
 
2069
            call_provider = true;
 
2070
            break;
 
2071
 
 
2072
        default:
 
2073
            timeout = nctx->cache_timeout;
 
2074
 
 
2075
            lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
 
2076
                                                     SYSDB_LAST_UPDATE, 0);
 
2077
            if (lastUpdate + timeout < time(NULL)) {
 
2078
                call_provider = true;
 
2079
            }
 
2080
        }
 
2081
    }
 
2082
 
 
2083
    if (call_provider) {
 
2084
 
 
2085
        /* dont loop forever :-) */
 
2086
        dctx->check_provider = false;
 
2087
        timeout = SSS_CLI_SOCKET_TIMEOUT/2;
 
2088
 
 
2089
        /* keep around current data in case backend is offline */
 
2090
        if (res->count) {
 
2091
            dctx->res = talloc_steal(dctx, res);
 
2092
        }
 
2093
 
 
2094
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
2095
                                   nss_cmd_getgrgid_dp_callback, dctx,
 
2096
                                   timeout, dctx->domain->name, SSS_DP_GROUP,
 
2097
                                   NULL, cmdctx->id);
 
2098
        if (ret != EOK) {
 
2099
            DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
 
2100
                      ret, strerror(ret)));
 
2101
            ret = nss_cmd_send_error(cmdctx, ret);
 
2102
            if (ret != EOK) {
 
2103
                NSS_CMD_FATAL_ERROR(cctx);
 
2104
            }
 
2105
            sss_cmd_done(cctx, cmdctx);
 
2106
        }
 
2107
        return;
 
2108
    }
 
2109
 
 
2110
    switch (res->count) {
 
2111
    case 0:
 
2112
        if (cmdctx->check_next) {
 
2113
 
 
2114
            ret = EOK;
 
2115
 
 
2116
            dom = dctx->domain->next;
 
2117
 
 
2118
            ncret = nss_ncache_check_gid(nctx->ncache, nctx->neg_timeout,
 
2119
                                         cmdctx->id);
 
2120
            if (ncret == EEXIST) {
 
2121
                DEBUG(3, ("Gid [%lu] does not exist! (negative cache)\n",
 
2122
                          (unsigned long)cmdctx->id));
 
2123
                ret = ENOENT;
 
2124
            }
 
2125
            if (dom == NULL) {
 
2126
                DEBUG(0, ("No matching domain found for [%lu], fail!\n",
 
2127
                          (unsigned long)cmdctx->id));
 
2128
                ret = ENOENT;
 
2129
            }
 
2130
 
 
2131
            if (ret == EOK) {
 
2132
                dctx->domain = dom;
 
2133
                dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
2134
                if (dctx->res) talloc_free(res);
 
2135
                dctx->res = NULL;
 
2136
 
 
2137
                DEBUG(4, ("Requesting info for [%s@%s]\n",
 
2138
                          cmdctx->name, dctx->domain->name));
 
2139
 
 
2140
                ret = sysdb_getgrgid(cmdctx, cctx->rctx->sysdb,
 
2141
                                     dctx->domain, cmdctx->id,
 
2142
                                     nss_cmd_getgrgid_callback, dctx);
 
2143
                if (ret != EOK) {
 
2144
                    DEBUG(1, ("Failed to make request to our cache!\n"));
 
2145
                }
 
2146
            }
 
2147
 
 
2148
            /* we made another call, end here */
 
2149
            if (ret == EOK) return;
 
2150
        }
 
2151
 
 
2152
        DEBUG(2, ("No results for getgrgid call\n"));
 
2153
 
 
2154
        /* set negative cache only if not result of cache check */
 
2155
        if (!neghit) {
 
2156
            ret = nss_ncache_set_gid(nctx->ncache, false, cmdctx->id);
 
2157
            if (ret != EOK) {
 
2158
                NSS_CMD_FATAL_ERROR(cctx);
 
2159
            }
 
2160
        }
 
2161
 
 
2162
        ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
2163
                             sss_packet_get_cmd(cctx->creq->in),
 
2164
                             &cctx->creq->out);
 
2165
        if (ret != EOK) {
 
2166
            NSS_CMD_FATAL_ERROR(cctx);
 
2167
        }
 
2168
        sss_packet_get_body(cctx->creq->out, &body, &blen);
 
2169
        ((uint32_t *)body)[0] = 0; /* 0 results */
 
2170
        ((uint32_t *)body)[1] = 0; /* reserved */
 
2171
        break;
 
2172
 
 
2173
    default:
 
2174
 
 
2175
        DEBUG(6, ("Returning info for group [%u]\n", (unsigned)cmdctx->id));
 
2176
 
 
2177
        /* create response packet */
 
2178
        ret = sss_packet_new(cctx->creq, 0,
 
2179
                             sss_packet_get_cmd(cctx->creq->in),
 
2180
                             &cctx->creq->out);
 
2181
        if (ret != EOK) {
 
2182
            NSS_CMD_FATAL_ERROR(cctx);
 
2183
        }
 
2184
 
 
2185
        ret = fill_grent(cctx->creq->out,
 
2186
                         dctx->domain,
 
2187
                         nctx, true,
 
2188
                         res->msgs, res->count);
 
2189
        if (ret == ENOENT) {
 
2190
            ret = fill_empty(cctx->creq->out);
 
2191
        }
 
2192
        sss_packet_set_error(cctx->creq->out, ret);
 
2193
    }
 
2194
 
 
2195
    sss_cmd_done(cctx, cmdctx);
 
2196
}
 
2197
 
 
2198
static void nss_cmd_getgrgid_dp_callback(uint16_t err_maj, uint32_t err_min,
 
2199
                                      const char *err_msg, void *ptr)
 
2200
{
 
2201
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2202
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2203
    struct cli_ctx *cctx = cmdctx->cctx;
 
2204
    int ret;
 
2205
 
 
2206
    if (err_maj) {
 
2207
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
2208
                  "Error: %u, %u, %s\n"
 
2209
                  "Will try to return what we have in cache\n",
 
2210
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
2211
 
 
2212
        if (!dctx->res) {
 
2213
            /* return 0 results */
 
2214
            dctx->res = talloc_zero(dctx, struct ldb_result);
 
2215
            if (!dctx->res) {
 
2216
                ret = ENOMEM;
 
2217
                goto done;
 
2218
            }
 
2219
        }
 
2220
 
 
2221
        nss_cmd_getgrgid_callback(dctx, LDB_SUCCESS, dctx->res);
 
2222
        return;
 
2223
    }
 
2224
 
 
2225
    ret = sysdb_getgrgid(cmdctx, cctx->rctx->sysdb,
 
2226
                         dctx->domain, cmdctx->id,
 
2227
                         nss_cmd_getgrgid_callback, dctx);
 
2228
 
 
2229
done:
 
2230
    if (ret != EOK) {
 
2231
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
2232
 
 
2233
        ret = nss_cmd_send_error(cmdctx, ret);
 
2234
        if (ret != EOK) {
 
2235
            NSS_CMD_FATAL_ERROR(cctx);
 
2236
        }
 
2237
        sss_cmd_done(cctx, cmdctx);
 
2238
    }
 
2239
}
 
2240
 
 
2241
static int nss_cmd_getgrgid(struct cli_ctx *cctx)
 
2242
{
 
2243
    struct nss_cmd_ctx *cmdctx;
 
2244
    struct nss_dom_ctx *dctx;
 
2245
    struct sss_domain_info *dom;
 
2246
    struct nss_ctx *nctx;
 
2247
    uint8_t *body;
 
2248
    size_t blen;
 
2249
    int ret;
 
2250
    int ncret;
 
2251
 
 
2252
    ret = ENOENT;
 
2253
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2254
 
 
2255
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
2256
    if (!cmdctx) {
 
2257
        return ENOMEM;
 
2258
    }
 
2259
    cmdctx->cctx = cctx;
 
2260
 
 
2261
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
2262
    if (!dctx) {
 
2263
        ret = ENOMEM;
 
2264
        goto done;
 
2265
    }
 
2266
    dctx->cmdctx = cmdctx;
 
2267
 
 
2268
    /* get uid to query */
 
2269
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
2270
 
 
2271
    if (blen != sizeof(uint32_t)) {
 
2272
        ret = EINVAL;
 
2273
        goto done;
 
2274
    }
 
2275
    cmdctx->id = *((uint32_t *)body);
 
2276
 
 
2277
    /* this is a multidomain search */
 
2278
    cmdctx->check_next = true;
 
2279
 
 
2280
    for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
2281
        /* verify this user has not yet been negatively cached,
 
2282
         * or has been permanently filtered */
 
2283
        ncret = nss_ncache_check_gid(nctx->ncache, nctx->neg_timeout,
 
2284
                                     cmdctx->id);
 
2285
        if (ncret == EEXIST) {
 
2286
            DEBUG(3, ("Gid [%lu] does not exist! (negative cache)\n",
 
2287
                      (unsigned long)cmdctx->id));
 
2288
            continue;
 
2289
        }
 
2290
 
 
2291
        /* check that the uid is valid for this domain */
 
2292
        if ((dom->id_min && (cmdctx->id < dom->id_min)) ||
 
2293
            (dom->id_max && (cmdctx->id > dom->id_max))) {
 
2294
            DEBUG(4, ("Gid [%lu] does not exist in domain [%s]! "
 
2295
                      "(id out of range)\n",
 
2296
                      (unsigned long)cmdctx->id, dom->name));
 
2297
            continue;
 
2298
        }
 
2299
 
 
2300
        dctx->domain = dom;
 
2301
        dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
2302
 
 
2303
        DEBUG(4, ("Requesting info for [%lu@%s]\n",
 
2304
                  cmdctx->id, dctx->domain->name));
 
2305
 
 
2306
        ret = sysdb_getgrgid(cmdctx, cctx->rctx->sysdb,
 
2307
                             dctx->domain, cmdctx->id,
 
2308
                             nss_cmd_getgrgid_callback, dctx);
 
2309
        if (ret != EOK) {
 
2310
            DEBUG(1, ("Failed to make request to our cache!\n"));
 
2311
        }
 
2312
 
 
2313
        break;
 
2314
    }
 
2315
 
 
2316
done:
 
2317
    if (ret != EOK) {
 
2318
        if (ret == ENOENT) {
 
2319
            /* we do not have any entry to return */
 
2320
            ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
2321
                                 sss_packet_get_cmd(cctx->creq->in),
 
2322
                                 &cctx->creq->out);
 
2323
            if (ret == EOK) {
 
2324
                sss_packet_get_body(cctx->creq->out, &body, &blen);
 
2325
                ((uint32_t *)body)[0] = 0; /* 0 results */
 
2326
                ((uint32_t *)body)[1] = 0; /* reserved */
 
2327
            }
 
2328
        }
 
2329
        if (ret != EOK) {
 
2330
            ret = nss_cmd_send_error(cmdctx, ret);
 
2331
        }
 
2332
        if (ret == EOK) {
 
2333
            sss_cmd_done(cctx, cmdctx);
 
2334
        }
 
2335
        return ret;
 
2336
    }
 
2337
 
 
2338
    return EOK;
 
2339
}
 
2340
 
 
2341
/* to keep it simple at this stage we are retrieving the
 
2342
 * full enumeration again for each request for each process
 
2343
 * and we also block on setgrent() for the full time needed
 
2344
 * to retrieve the data. And endgrent() frees all the data.
 
2345
 * Next steps are:
 
2346
 * - use and nsssrv wide cache with data already structured
 
2347
 *   so that it can be immediately returned (see nscd way)
 
2348
 * - use mutexes so that setgrent() can return immediately
 
2349
 *   even if the data is still being fetched
 
2350
 * - make getgrent() wait on the mutex
 
2351
 */
 
2352
static int nss_cmd_getgrent_immediate(struct nss_cmd_ctx *cmdctx);
 
2353
 
 
2354
static void nss_cmd_setgr_dp_callback(uint16_t err_maj, uint32_t err_min,
 
2355
                                      const char *err_msg, void *ptr);
 
2356
 
 
2357
static void nss_cmd_setgrent_callback(void *ptr, int status,
 
2358
                                     struct ldb_result *res)
 
2359
{
 
2360
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2361
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2362
    struct cli_ctx *cctx = cmdctx->cctx;
 
2363
    struct sss_domain_info *dom;
 
2364
    struct getent_ctx *gctx;
 
2365
    struct nss_ctx *nctx;
 
2366
    int timeout;
 
2367
    int ret;
 
2368
 
 
2369
    if (status != LDB_SUCCESS) {
 
2370
        ret = nss_cmd_send_error(cmdctx, ENOENT);
 
2371
        if (ret != EOK) {
 
2372
            NSS_CMD_FATAL_ERROR(cctx);
 
2373
        }
 
2374
        sss_cmd_done(cctx, cmdctx);
 
2375
        return;
 
2376
    }
 
2377
 
 
2378
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2379
    gctx = nctx->gctx;
 
2380
    if (gctx == NULL) {
 
2381
        gctx = talloc_zero(nctx, struct getent_ctx);
 
2382
        if (!gctx) {
 
2383
            ret = nss_cmd_send_error(cmdctx, ENOMEM);
 
2384
            if (ret != EOK) {
 
2385
                NSS_CMD_FATAL_ERROR(cctx);
 
2386
            }
 
2387
            sss_cmd_done(cctx, cmdctx);
 
2388
            return;
 
2389
        }
 
2390
        nctx->gctx = gctx;
 
2391
    }
 
2392
 
 
2393
    gctx->doms = talloc_realloc(gctx, gctx->doms, struct dom_ctx, gctx->num +1);
 
2394
    if (!gctx->doms) NSS_CMD_FATAL_ERROR(cctx);
 
2395
 
 
2396
    gctx->doms[gctx->num].domain = dctx->domain;
 
2397
    gctx->doms[gctx->num].res = talloc_steal(gctx->doms, res);
 
2398
    gctx->doms[gctx->num].cur = 0;
 
2399
 
 
2400
    gctx->num++;
 
2401
 
 
2402
    /* do not reply until all domain searches are done */
 
2403
    for (dom = dctx->domain->next; dom; dom = dom->next) {
 
2404
        if ((dom->enumerate & NSS_ENUM_GROUPS) != 0) break;
 
2405
    }
 
2406
    dctx->domain = dom;
 
2407
 
 
2408
    if (dctx->domain != NULL) {
 
2409
        if (cmdctx->enum_cached) {
 
2410
            dctx->check_provider = false;
 
2411
        } else {
 
2412
            dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
2413
        }
 
2414
 
 
2415
        if (dctx->check_provider) {
 
2416
            timeout = SSS_CLI_SOCKET_TIMEOUT;
 
2417
            ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
2418
                                       nss_cmd_setgr_dp_callback, dctx,
 
2419
                                       timeout, dom->name, SSS_DP_GROUP,
 
2420
                                       NULL, 0);
 
2421
        } else {
 
2422
            ret = sysdb_enumgrent(dctx, cctx->rctx->sysdb,
 
2423
                                  dctx->domain,
 
2424
                                  nss_cmd_setgrent_callback, dctx);
 
2425
        }
 
2426
        if (ret != EOK) {
 
2427
            /* FIXME: shutdown ? */
 
2428
            DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n",
 
2429
                      dom->name));
 
2430
 
 
2431
            ret = nss_cmd_send_error(cmdctx, ret);
 
2432
            if (ret != EOK) {
 
2433
                NSS_CMD_FATAL_ERROR(cctx);
 
2434
            }
 
2435
            sss_cmd_done(cctx, cmdctx);
 
2436
        }
 
2437
        return;
 
2438
    }
 
2439
 
 
2440
    /* set cache mark */
 
2441
    nctx->last_group_enum = time(NULL);
 
2442
 
 
2443
    if (cmdctx->immediate) {
 
2444
        /* this was a getgrent call w/o setgrent,
 
2445
         * return immediately one result */
 
2446
        ret = nss_cmd_getgrent_immediate(cmdctx);
 
2447
        if (ret != EOK) NSS_CMD_FATAL_ERROR(cctx);
 
2448
        return;
 
2449
    }
 
2450
 
 
2451
    /* create response packet */
 
2452
    ret = sss_packet_new(cctx->creq, 0,
 
2453
                         sss_packet_get_cmd(cctx->creq->in),
 
2454
                         &cctx->creq->out);
 
2455
    if (ret != EOK) {
 
2456
        NSS_CMD_FATAL_ERROR(cctx);
 
2457
    }
 
2458
    sss_cmd_done(cctx, cmdctx);
 
2459
}
 
2460
 
 
2461
static void nss_cmd_setgr_dp_callback(uint16_t err_maj, uint32_t err_min,
 
2462
                                      const char *err_msg, void *ptr)
 
2463
{
 
2464
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2465
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2466
    struct cli_ctx *cctx = cmdctx->cctx;
 
2467
    int ret;
 
2468
 
 
2469
    if (err_maj) {
 
2470
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
2471
                  "Error: %u, %u, %s\n"
 
2472
                  "Will try to return what we have in cache\n",
 
2473
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
2474
    }
 
2475
 
 
2476
    ret = sysdb_enumgrent(dctx, cctx->rctx->sysdb,
 
2477
                          dctx->domain,
 
2478
                          nss_cmd_setgrent_callback, dctx);
 
2479
    if (ret != EOK) {
 
2480
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
2481
 
 
2482
        ret = nss_cmd_send_error(cmdctx, ret);
 
2483
        if (ret != EOK) {
 
2484
            NSS_CMD_FATAL_ERROR(cctx);
 
2485
        }
 
2486
        sss_cmd_done(cctx, cmdctx);
 
2487
    }
 
2488
}
 
2489
 
 
2490
static int nss_cmd_setgrent_ext(struct cli_ctx *cctx, bool immediate)
 
2491
{
 
2492
    struct sss_domain_info *dom;
 
2493
    struct nss_cmd_ctx *cmdctx;
 
2494
    struct nss_dom_ctx *dctx;
 
2495
    struct nss_ctx *nctx;
 
2496
    time_t now = time(NULL);
 
2497
    int timeout;
 
2498
    uint8_t *body;
 
2499
    size_t blen;
 
2500
    int ret;
 
2501
 
 
2502
    DEBUG(4, ("Requesting info for all groups\n"));
 
2503
 
 
2504
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2505
    talloc_free(nctx->gctx);
 
2506
    nctx->gctx = NULL;
 
2507
 
 
2508
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
2509
    if (!cmdctx) {
 
2510
        return ENOMEM;
 
2511
    }
 
2512
    cmdctx->cctx = cctx;
 
2513
    cmdctx->immediate = immediate;
 
2514
 
 
2515
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
2516
    if (!dctx) {
 
2517
        ret = ENOMEM;
 
2518
        goto done;
 
2519
    }
 
2520
    dctx->cmdctx = cmdctx;
 
2521
 
 
2522
    /* do not query backends if we have a recent enumeration */
 
2523
    if (nctx->enum_cache_timeout) {
 
2524
        if (nctx->last_group_enum +
 
2525
            nctx->enum_cache_timeout > now) {
 
2526
            cmdctx->enum_cached = true;
 
2527
        }
 
2528
    }
 
2529
 
 
2530
    /* check if enumeration is enabled in any domain */
 
2531
    for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
2532
        if ((dom->enumerate & NSS_ENUM_GROUPS) != 0) break;
 
2533
    }
 
2534
    dctx->domain = dom;
 
2535
 
 
2536
    if (dctx->domain == NULL) {
 
2537
        DEBUG(2, ("Enumeration disabled on all domains!\n"));
 
2538
        ret = ENOENT;
 
2539
        goto done;
 
2540
    }
 
2541
 
 
2542
    if (cmdctx->enum_cached) {
 
2543
        dctx->check_provider = false;
 
2544
    } else {
 
2545
        dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
2546
    }
 
2547
 
 
2548
    if (dctx->check_provider) {
 
2549
        timeout = SSS_CLI_SOCKET_TIMEOUT;
 
2550
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
2551
                                   nss_cmd_setgr_dp_callback, dctx,
 
2552
                                   timeout, dom->name, SSS_DP_GROUP,
 
2553
                                   NULL, 0);
 
2554
    } else {
 
2555
        ret = sysdb_enumgrent(dctx, cctx->rctx->sysdb,
 
2556
                              dctx->domain,
 
2557
                              nss_cmd_setgrent_callback, dctx);
 
2558
    }
 
2559
    if (ret != EOK) {
 
2560
        /* FIXME: shutdown ? */
 
2561
        DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n",
 
2562
                  dom->name));
 
2563
    }
 
2564
 
 
2565
done:
 
2566
    if (ret != EOK) {
 
2567
        if (ret == ENOENT) {
 
2568
            if (cmdctx->immediate) {
 
2569
                /* we do not have any entry to return */
 
2570
                ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
2571
                                     sss_packet_get_cmd(cctx->creq->in),
 
2572
                                     &cctx->creq->out);
 
2573
                if (ret == EOK) {
 
2574
                    sss_packet_get_body(cctx->creq->out, &body, &blen);
 
2575
                    ((uint32_t *)body)[0] = 0; /* 0 results */
 
2576
                    ((uint32_t *)body)[1] = 0; /* reserved */
 
2577
                }
 
2578
            }
 
2579
            else {
 
2580
                /* create response packet */
 
2581
                ret = sss_packet_new(cctx->creq, 0,
 
2582
                                     sss_packet_get_cmd(cctx->creq->in),
 
2583
                                     &cctx->creq->out);
 
2584
            }
 
2585
        }
 
2586
        if (ret != EOK) {
 
2587
            ret = nss_cmd_send_error(cmdctx, ret);
 
2588
        }
 
2589
        if (ret == EOK) {
 
2590
            sss_cmd_done(cctx, cmdctx);
 
2591
        }
 
2592
        return ret;
 
2593
    }
 
2594
 
 
2595
    return EOK;
 
2596
}
 
2597
 
 
2598
static int nss_cmd_setgrent(struct cli_ctx *cctx)
 
2599
{
 
2600
    return nss_cmd_setgrent_ext(cctx, false);
 
2601
}
 
2602
 
 
2603
static int nss_cmd_retgrent(struct cli_ctx *cctx, int num)
 
2604
{
 
2605
    struct nss_ctx *nctx;
 
2606
    struct getent_ctx *gctx;
 
2607
    struct ldb_message **msgs = NULL;
 
2608
    struct dom_ctx *gdom = NULL;
 
2609
    int n = 0;
 
2610
    int ret;
 
2611
 
 
2612
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2613
    gctx = nctx->gctx;
 
2614
 
 
2615
retry:
 
2616
    if (gctx->cur >= gctx->num) goto none;
 
2617
 
 
2618
    gdom = &gctx->doms[gctx->cur];
 
2619
 
 
2620
    n = gdom->res->count - gdom->cur;
 
2621
    if (n == 0 && (gctx->cur+1 < gctx->num)) {
 
2622
        gctx->cur++;
 
2623
        gdom = &gctx->doms[gctx->cur];
 
2624
        n = gdom->res->count - gdom->cur;
 
2625
    }
 
2626
 
 
2627
    if (!n) goto none;
 
2628
 
 
2629
    if (n > num) n = num;
 
2630
 
 
2631
    msgs = &(gdom->res->msgs[gdom->cur]);
 
2632
    gdom->cur += n;
 
2633
 
 
2634
    ret = fill_grent(cctx->creq->out, gdom->domain, nctx, true, msgs, n);
 
2635
    if (ret == ENOENT) goto retry;
 
2636
    return ret;
 
2637
 
 
2638
none:
 
2639
    return fill_empty(cctx->creq->out);
 
2640
}
 
2641
 
 
2642
/* used only if a process calls getpwent() without first calling setpwent()
 
2643
 */
 
2644
static int nss_cmd_getgrent_immediate(struct nss_cmd_ctx *cmdctx)
 
2645
{
 
2646
    struct cli_ctx *cctx = cmdctx->cctx;
 
2647
    uint8_t *body;
 
2648
    size_t blen;
 
2649
    uint32_t num;
 
2650
    int ret;
 
2651
 
 
2652
    /* get max num of entries to return in one call */
 
2653
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
2654
    if (blen != sizeof(uint32_t)) {
 
2655
        return EINVAL;
 
2656
    }
 
2657
    num = *((uint32_t *)body);
 
2658
 
 
2659
    /* create response packet */
 
2660
    ret = sss_packet_new(cctx->creq, 0,
 
2661
                         sss_packet_get_cmd(cctx->creq->in),
 
2662
                         &cctx->creq->out);
 
2663
    if (ret != EOK) {
 
2664
        return ret;
 
2665
    }
 
2666
 
 
2667
    ret = nss_cmd_retgrent(cctx, num);
 
2668
 
 
2669
    sss_packet_set_error(cctx->creq->out, ret);
 
2670
    sss_cmd_done(cctx, cmdctx);
 
2671
 
 
2672
    return EOK;
 
2673
}
 
2674
 
 
2675
static int nss_cmd_getgrent(struct cli_ctx *cctx)
 
2676
{
 
2677
    struct nss_ctx *nctx;
 
2678
    struct nss_cmd_ctx *cmdctx;
 
2679
 
 
2680
    DEBUG(4, ("Requesting info for all groups\n"));
 
2681
 
 
2682
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2683
 
 
2684
    /* see if we need to trigger an implicit setpwent() */
 
2685
    if (nctx->gctx == NULL) {
 
2686
        nctx->gctx = talloc_zero(nctx, struct getent_ctx);
 
2687
        if (!nctx->gctx) return ENOMEM;
 
2688
 
 
2689
        return nss_cmd_setgrent_ext(cctx, true);
 
2690
    }
 
2691
 
 
2692
    cmdctx = talloc(cctx, struct nss_cmd_ctx);
 
2693
    if (!cmdctx) {
 
2694
        return ENOMEM;
 
2695
    }
 
2696
    cmdctx->cctx = cctx;
 
2697
 
 
2698
    return nss_cmd_getgrent_immediate(cmdctx);
 
2699
}
 
2700
 
 
2701
static int nss_cmd_endgrent(struct cli_ctx *cctx)
 
2702
{
 
2703
    struct nss_ctx *nctx;
 
2704
    int ret;
 
2705
 
 
2706
    DEBUG(4, ("Terminating request info for all groups\n"));
 
2707
 
 
2708
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2709
 
 
2710
    /* create response packet */
 
2711
    ret = sss_packet_new(cctx->creq, 0,
 
2712
                         sss_packet_get_cmd(cctx->creq->in),
 
2713
                         &cctx->creq->out);
 
2714
 
 
2715
    if (nctx->gctx == NULL) goto done;
 
2716
 
 
2717
    /* free results and reset */
 
2718
    talloc_free(nctx->gctx);
 
2719
    nctx->gctx = NULL;
 
2720
 
 
2721
done:
 
2722
    sss_cmd_done(cctx, NULL);
 
2723
    return EOK;
 
2724
}
 
2725
 
 
2726
static void nss_cmd_initgr_callback(void *ptr, int status,
 
2727
                                   struct ldb_result *res)
 
2728
{
 
2729
    struct nss_cmd_ctx *cmdctx = talloc_get_type(ptr, struct nss_cmd_ctx);
 
2730
    struct cli_ctx *cctx = cmdctx->cctx;
 
2731
    uint8_t *body;
 
2732
    size_t blen;
 
2733
    uint32_t gid;
 
2734
    uint32_t num;
 
2735
    int ret, i;
 
2736
 
 
2737
    /* create response packet */
 
2738
    ret = sss_packet_new(cctx->creq, 0,
 
2739
                         sss_packet_get_cmd(cctx->creq->in),
 
2740
                         &cctx->creq->out);
 
2741
    if (ret != EOK) {
 
2742
        NSS_CMD_FATAL_ERROR(cctx);
 
2743
    }
 
2744
 
 
2745
    if (status != LDB_SUCCESS) {
 
2746
        sss_packet_set_error(cctx->creq->out, status);
 
2747
        goto done;
 
2748
    }
 
2749
 
 
2750
    num = res->count;
 
2751
    ret = sss_packet_grow(cctx->creq->out, (2 + num) * sizeof(uint32_t));
 
2752
    if (ret != EOK) {
 
2753
        sss_packet_set_error(cctx->creq->out, ret);
 
2754
        goto done;
 
2755
    }
 
2756
    sss_packet_get_body(cctx->creq->out, &body, &blen);
 
2757
 
 
2758
    for (i = 0; i < num; i++) {
 
2759
        gid = ldb_msg_find_attr_as_uint64(res->msgs[i], SYSDB_GIDNUM, 0);
 
2760
        if (!gid) {
 
2761
            DEBUG(1, ("Incomplete group object for initgroups! Aborting\n"));
 
2762
            sss_packet_set_error(cctx->creq->out, EIO);
 
2763
            num = 0;
 
2764
            goto done;
 
2765
        }
 
2766
        ((uint32_t *)body)[2+i] = gid;
 
2767
    }
 
2768
 
 
2769
    ((uint32_t *)body)[0] = num; /* num results */
 
2770
    ((uint32_t *)body)[1] = 0; /* reserved */
 
2771
 
 
2772
done:
 
2773
    sss_cmd_done(cctx, cmdctx);
 
2774
}
 
2775
 
 
2776
static void nss_cmd_getinitgr_callback(uint16_t err_maj, uint32_t err_min,
 
2777
                                       const char *err_msg, void *ptr)
 
2778
{
 
2779
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2780
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2781
    struct cli_ctx *cctx = cmdctx->cctx;
 
2782
    int ret;
 
2783
 
 
2784
    if (err_maj) {
 
2785
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
2786
                  "Error: %u, %u, %s\n"
 
2787
                  "Will try to return what we have in cache\n",
 
2788
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
2789
    }
 
2790
 
 
2791
    ret = sysdb_initgroups(cmdctx, cctx->rctx->sysdb,
 
2792
                           dctx->domain, cmdctx->name,
 
2793
                           nss_cmd_initgr_callback, cmdctx);
 
2794
    if (ret != EOK) {
 
2795
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
2796
 
 
2797
        ret = nss_cmd_send_error(cmdctx, ret);
 
2798
        if (ret != EOK) {
 
2799
            NSS_CMD_FATAL_ERROR(cctx);
 
2800
        }
 
2801
        sss_cmd_done(cctx, cmdctx);
 
2802
    }
 
2803
}
 
2804
 
 
2805
static void nss_cmd_getinit_callback(void *ptr, int status,
 
2806
                                     struct ldb_result *res);
 
2807
 
 
2808
static void nss_cmd_getinitnam_dp_callback(uint16_t err_maj, uint32_t err_min,
 
2809
                                           const char *err_msg, void *ptr)
 
2810
{
 
2811
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2812
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2813
    struct cli_ctx *cctx = cmdctx->cctx;
 
2814
    int ret;
 
2815
 
 
2816
    if (err_maj) {
 
2817
        DEBUG(2, ("Unable to get information from Data Provider\n"
 
2818
                  "Error: %u, %u, %s\n"
 
2819
                  "Will try to return what we have in cache\n",
 
2820
                  (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
2821
 
 
2822
        if (!dctx->res) {
 
2823
            /* return 0 results */
 
2824
            dctx->res = talloc_zero(dctx, struct ldb_result);
 
2825
            if (!dctx->res) {
 
2826
                ret = ENOMEM;
 
2827
                goto done;
 
2828
            }
 
2829
        }
 
2830
 
 
2831
        nss_cmd_getinit_callback(dctx, LDB_SUCCESS, dctx->res);
 
2832
        return;
 
2833
    }
 
2834
 
 
2835
    ret = sysdb_getpwnam(cmdctx, cctx->rctx->sysdb,
 
2836
                         dctx->domain, cmdctx->name,
 
2837
                         nss_cmd_getinit_callback, dctx);
 
2838
 
 
2839
done:
 
2840
    if (ret != EOK) {
 
2841
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
2842
 
 
2843
        ret = nss_cmd_send_error(cmdctx, ret);
 
2844
        if (ret != EOK) {
 
2845
            NSS_CMD_FATAL_ERROR(cctx);
 
2846
        }
 
2847
        sss_cmd_done(cctx, cmdctx);
 
2848
    }
 
2849
}
 
2850
 
 
2851
static void nss_cmd_getinit_callback(void *ptr, int status,
 
2852
                                     struct ldb_result *res)
 
2853
{
 
2854
    struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
 
2855
    struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
 
2856
    struct cli_ctx *cctx = cmdctx->cctx;
 
2857
    struct sss_domain_info *dom;
 
2858
    struct nss_ctx *nctx;
 
2859
    int timeout;
 
2860
    uint64_t lastUpdate;
 
2861
    uint8_t *body;
 
2862
    size_t blen;
 
2863
    bool call_provider = false;
 
2864
    bool neghit = false;
 
2865
    int ncret;
 
2866
    int ret;
 
2867
 
 
2868
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
2869
 
 
2870
    if (status != LDB_SUCCESS) {
 
2871
        ret = nss_cmd_send_error(cmdctx, status);
 
2872
        if (ret != EOK) {
 
2873
            NSS_CMD_FATAL_ERROR(cctx);
 
2874
        }
 
2875
        sss_cmd_done(cctx, cmdctx);
 
2876
        return;
 
2877
    }
 
2878
 
 
2879
    if (dctx->check_provider) {
 
2880
        switch (res->count) {
 
2881
        case 0:
 
2882
            call_provider = true;
 
2883
            break;
 
2884
 
 
2885
        case 1:
 
2886
            timeout = nctx->cache_timeout;
 
2887
 
 
2888
            lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
 
2889
                                                     SYSDB_LAST_UPDATE, 0);
 
2890
            if (lastUpdate + timeout < time(NULL)) {
 
2891
                call_provider = true;
 
2892
            }
 
2893
            break;
 
2894
 
 
2895
        default:
 
2896
            DEBUG(1, ("getpwnam call returned more than one result !?!\n"));
 
2897
            ret = nss_cmd_send_error(cmdctx, ENOENT);
 
2898
            if (ret != EOK) {
 
2899
                NSS_CMD_FATAL_ERROR(cctx);
 
2900
            }
 
2901
            sss_cmd_done(cctx, cmdctx);
 
2902
            return;
 
2903
        }
 
2904
    }
 
2905
 
 
2906
    if (call_provider) {
 
2907
 
 
2908
        /* dont loop forever :-) */
 
2909
        dctx->check_provider = false;
 
2910
        timeout = SSS_CLI_SOCKET_TIMEOUT/2;
 
2911
 
 
2912
        /* keep around current data in case backend is offline */
 
2913
        if (res->count) {
 
2914
            dctx->res = talloc_steal(dctx, res);
 
2915
        }
 
2916
 
 
2917
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
2918
                                   nss_cmd_getinitnam_dp_callback, dctx,
 
2919
                                   timeout, dctx->domain->name, SSS_DP_USER,
 
2920
                                   cmdctx->name, 0);
 
2921
        if (ret != EOK) {
 
2922
            DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
 
2923
                      ret, strerror(ret)));
 
2924
            ret = nss_cmd_send_error(cmdctx, ret);
 
2925
            if (ret != EOK) {
 
2926
                NSS_CMD_FATAL_ERROR(cctx);
 
2927
            }
 
2928
            sss_cmd_done(cctx, cmdctx);
 
2929
        }
 
2930
        return;
 
2931
    }
 
2932
 
 
2933
    switch (res->count) {
 
2934
    case 0:
 
2935
        if (cmdctx->check_next) {
 
2936
 
 
2937
            ret = EOK;
 
2938
 
 
2939
            /* skip domains that require FQnames or have negative caches */
 
2940
            for (dom = dctx->domain->next; dom; dom = dom->next) {
 
2941
 
 
2942
                if (dom->fqnames) continue;
 
2943
 
 
2944
                ncret = nss_ncache_check_user(nctx->ncache,
 
2945
                                              nctx->neg_timeout,
 
2946
                                              dom->name, cmdctx->name);
 
2947
                if (ncret == ENOENT) break;
 
2948
 
 
2949
                neghit = true;
 
2950
            }
 
2951
            /* reset neghit if we still have a domain to check */
 
2952
            if (dom) neghit = false;
 
2953
 
 
2954
            if (neghit) {
 
2955
                DEBUG(2, ("User [%s] does not exist! (negative cache)\n",
 
2956
                          cmdctx->name));
 
2957
                ret = ENOENT;
 
2958
            }
 
2959
            if (dom == NULL) {
 
2960
                DEBUG(2, ("No matching domain found for [%s], fail!\n",
 
2961
                          cmdctx->name));
 
2962
                ret = ENOENT;
 
2963
            }
 
2964
 
 
2965
            if (ret == EOK) {
 
2966
                dctx->domain = dom;
 
2967
                dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
2968
                if (dctx->res) talloc_free(res);
 
2969
                dctx->res = NULL;
 
2970
 
 
2971
                DEBUG(4, ("Requesting info for [%s@%s]\n",
 
2972
                          cmdctx->name, dctx->domain->name));
 
2973
 
 
2974
                ret = sysdb_getpwnam(cmdctx, cctx->rctx->sysdb,
 
2975
                                     dctx->domain, cmdctx->name,
 
2976
                                     nss_cmd_getinit_callback, dctx);
 
2977
                if (ret != EOK) {
 
2978
                    DEBUG(1, ("Failed to make request to our cache!\n"));
 
2979
                }
 
2980
            }
 
2981
 
 
2982
            /* we made another call, end here */
 
2983
            if (ret == EOK) return;
 
2984
        }
 
2985
 
 
2986
        DEBUG(2, ("No results for initgroups call\n"));
 
2987
 
 
2988
        /* set negative cache only if not result of cache check */
 
2989
        if (!neghit) {
 
2990
            ret = nss_ncache_set_user(nctx->ncache, false,
 
2991
                                      dctx->domain->name, cmdctx->name);
 
2992
            if (ret != EOK) {
 
2993
                NSS_CMD_FATAL_ERROR(cctx);
 
2994
            }
 
2995
        }
 
2996
 
 
2997
        ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
2998
                             sss_packet_get_cmd(cctx->creq->in),
 
2999
                             &cctx->creq->out);
 
3000
        if (ret != EOK) {
 
3001
            NSS_CMD_FATAL_ERROR(cctx);
 
3002
        }
 
3003
        sss_packet_get_body(cctx->creq->out, &body, &blen);
 
3004
        ((uint32_t *)body)[0] = 0; /* 0 results */
 
3005
        ((uint32_t *)body)[1] = 0; /* reserved */
 
3006
        break;
 
3007
 
 
3008
    case 1:
 
3009
 
 
3010
        timeout = SSS_CLI_SOCKET_TIMEOUT/2;
 
3011
        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
 
3012
                                   nss_cmd_getinitgr_callback, dctx,
 
3013
                                   timeout, dctx->domain->name,
 
3014
                                   SSS_DP_INITGROUPS,
 
3015
                                   cmdctx->name, 0);
 
3016
        if (ret != EOK) {
 
3017
            DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
 
3018
                      ret, strerror(ret)));
 
3019
            ret = nss_cmd_send_error(cmdctx, ret);
 
3020
            if (ret != EOK) {
 
3021
                NSS_CMD_FATAL_ERROR(cctx);
 
3022
            }
 
3023
            sss_cmd_done(cctx, cmdctx);
 
3024
        }
 
3025
 
 
3026
        return;
 
3027
 
 
3028
    default:
 
3029
        DEBUG(1, ("getpwnam call returned more than one result !?!\n"));
 
3030
        ret = nss_cmd_send_error(cmdctx, ENOENT);
 
3031
        if (ret != EOK) {
 
3032
            NSS_CMD_FATAL_ERROR(cctx);
 
3033
        }
 
3034
    }
 
3035
 
 
3036
    sss_cmd_done(cctx, cmdctx);
 
3037
}
 
3038
 
 
3039
/* for now, if we are online, try to always query the backend */
 
3040
static int nss_cmd_initgroups(struct cli_ctx *cctx)
 
3041
{
 
3042
    struct nss_cmd_ctx *cmdctx;
 
3043
    struct nss_dom_ctx *dctx;
 
3044
    struct sss_domain_info *dom;
 
3045
    struct nss_ctx *nctx;
 
3046
    const char *rawname;
 
3047
    char *domname;
 
3048
    uint8_t *body;
 
3049
    size_t blen;
 
3050
    int ret;
 
3051
    int ncret;
 
3052
    bool neghit = false;
 
3053
 
 
3054
    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
 
3055
 
 
3056
    cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
 
3057
    if (!cmdctx) {
 
3058
        return ENOMEM;
 
3059
    }
 
3060
    cmdctx->cctx = cctx;
 
3061
 
 
3062
    dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
 
3063
    if (!dctx) {
 
3064
        ret = ENOMEM;
 
3065
        goto done;
 
3066
    }
 
3067
    dctx->cmdctx = cmdctx;
 
3068
 
 
3069
    /* get user name to query */
 
3070
    sss_packet_get_body(cctx->creq->in, &body, &blen);
 
3071
 
 
3072
    /* if not terminated fail */
 
3073
    if (body[blen -1] != '\0') {
 
3074
        ret = EINVAL;
 
3075
        goto done;
 
3076
    }
 
3077
    rawname = (const char *)body;
 
3078
 
 
3079
    domname = NULL;
 
3080
    ret = sss_parse_name(cmdctx, cctx->rctx->names, rawname,
 
3081
                         &domname, &cmdctx->name);
 
3082
    if (ret != EOK) {
 
3083
        DEBUG(2, ("Invalid name received [%s]\n", rawname));
 
3084
        ret = ENOENT;
 
3085
        goto done;
 
3086
    }
 
3087
 
 
3088
    DEBUG(4, ("Requesting info for [%s] from [%s]\n",
 
3089
              cmdctx->name, domname  ? : "<ALL>"));
 
3090
 
 
3091
    if (domname) {
 
3092
        dctx->domain = nss_get_dom(cctx->rctx->domains, domname);
 
3093
        if (!dctx->domain) {
 
3094
            ret = ENOENT;
 
3095
            goto done;
 
3096
        }
 
3097
 
 
3098
        /* verify this user has not yet been negatively cached,
 
3099
         * or has been permanently filtered */
 
3100
        ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
 
3101
                                    domname, cmdctx->name);
 
3102
        if (ncret == EEXIST) {
 
3103
            neghit = true;
 
3104
        }
 
3105
    }
 
3106
    else {
 
3107
        /* skip domains that require FQnames or have negative caches */
 
3108
        for (dom = cctx->rctx->domains; dom; dom = dom->next) {
 
3109
 
 
3110
            if (dom->fqnames) continue;
 
3111
 
 
3112
            /* verify this user has not yet been negatively cached,
 
3113
            * or has been permanently filtered */
 
3114
            ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
 
3115
                                          dom->name, cmdctx->name);
 
3116
            if (ncret == ENOENT) break;
 
3117
 
 
3118
            neghit = true;
 
3119
        }
 
3120
        /* reset neghit if we still have a domain to check */
 
3121
        if (dom) neghit = false;
 
3122
 
 
3123
        dctx->domain = dom;
 
3124
    }
 
3125
    if (neghit) {
 
3126
        DEBUG(2, ("User [%s] does not exist! (negative cache)\n", rawname));
 
3127
        ret = ENOENT;
 
3128
        goto done;
 
3129
    }
 
3130
    if (dctx->domain == NULL) {
 
3131
        DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname));
 
3132
        ret = ENOENT;
 
3133
        goto done;
 
3134
    }
 
3135
 
 
3136
    dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
 
3137
 
 
3138
    if (!domname) {
 
3139
        /* this is a multidomain search */
 
3140
        cmdctx->check_next = true;
 
3141
    }
 
3142
 
 
3143
    DEBUG(4, ("Requesting info for [%s@%s]\n",
 
3144
              cmdctx->name, dctx->domain->name));
 
3145
 
 
3146
    ret = sysdb_getpwnam(cmdctx, cctx->rctx->sysdb,
 
3147
                         dctx->domain, cmdctx->name,
 
3148
                         nss_cmd_getinit_callback, dctx);
 
3149
    if (ret != EOK) {
 
3150
        DEBUG(1, ("Failed to make request to our cache!\n"));
 
3151
    }
 
3152
 
 
3153
done:
 
3154
    if (ret != EOK) {
 
3155
        if (ret == ENOENT) {
 
3156
            /* we do not have any entry to return */
 
3157
            ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t),
 
3158
                                 sss_packet_get_cmd(cctx->creq->in),
 
3159
                                 &cctx->creq->out);
 
3160
            if (ret == EOK) {
 
3161
                sss_packet_get_body(cctx->creq->out, &body, &blen);
 
3162
                ((uint32_t *)body)[0] = 0; /* 0 results */
 
3163
                ((uint32_t *)body)[1] = 0; /* reserved */
 
3164
            }
 
3165
        }
 
3166
        if (ret != EOK) {
 
3167
            ret = nss_cmd_send_error(cmdctx, ret);
 
3168
        }
 
3169
        if (ret == EOK) {
 
3170
            sss_cmd_done(cctx, cmdctx);
 
3171
        }
 
3172
        return ret;
 
3173
    }
 
3174
 
 
3175
    return EOK;
 
3176
}
 
3177
 
 
3178
struct cli_protocol_version *register_cli_protocol_version(void)
 
3179
{
 
3180
    static struct cli_protocol_version nss_cli_protocol_version[] = {
 
3181
        {1, "2008-09-05", "initial version, \\0 terminated strings"},
 
3182
        {0, NULL, NULL}
 
3183
    };
 
3184
 
 
3185
    return nss_cli_protocol_version;
 
3186
}
 
3187
 
 
3188
static struct sss_cmd_table nss_cmds[] = {
 
3189
    {SSS_GET_VERSION, sss_cmd_get_version},
 
3190
    {SSS_NSS_GETPWNAM, nss_cmd_getpwnam},
 
3191
    {SSS_NSS_GETPWUID, nss_cmd_getpwuid},
 
3192
    {SSS_NSS_SETPWENT, nss_cmd_setpwent},
 
3193
    {SSS_NSS_GETPWENT, nss_cmd_getpwent},
 
3194
    {SSS_NSS_ENDPWENT, nss_cmd_endpwent},
 
3195
    {SSS_NSS_GETGRNAM, nss_cmd_getgrnam},
 
3196
    {SSS_NSS_GETGRGID, nss_cmd_getgrgid},
 
3197
    {SSS_NSS_SETGRENT, nss_cmd_setgrent},
 
3198
    {SSS_NSS_GETGRENT, nss_cmd_getgrent},
 
3199
    {SSS_NSS_ENDGRENT, nss_cmd_endgrent},
 
3200
    {SSS_NSS_INITGR, nss_cmd_initgroups},
 
3201
    {SSS_CLI_NULL, NULL}
 
3202
};
 
3203
 
 
3204
struct sss_cmd_table *get_nss_cmds(void) {
 
3205
    return nss_cmds;
 
3206
}
 
3207
 
 
3208
int nss_cmd_execute(struct cli_ctx *cctx)
 
3209
{
 
3210
    enum sss_cli_command cmd;
 
3211
    int i;
 
3212
 
 
3213
    cmd = sss_packet_get_cmd(cctx->creq->in);
 
3214
 
 
3215
    for (i = 0; nss_cmds[i].cmd != SSS_CLI_NULL; i++) {
 
3216
        if (cmd == nss_cmds[i].cmd) {
 
3217
            return nss_cmds[i].fn(cctx);
 
3218
        }
 
3219
    }
 
3220
 
 
3221
    return EINVAL;
 
3222
}
 
3223