~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/winbindd/winbindd_group.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
 
 
4
   Winbind daemon for ntdom nss module
 
5
 
 
6
   Copyright (C) Tim Potter 2000
 
7
   Copyright (C) Jeremy Allison 2001.
 
8
   Copyright (C) Gerald (Jerry) Carter 2003.
 
9
   Copyright (C) Volker Lendecke 2005
 
10
   
 
11
   This program is free software; you can redistribute it and/or modify
 
12
   it under the terms of the GNU General Public License as published by
 
13
   the Free Software Foundation; either version 3 of the License, or
 
14
   (at your option) any later version.
 
15
   
 
16
   This program is distributed in the hope that it will be useful,
 
17
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
   GNU General Public License for more details.
 
20
   
 
21
   You should have received a copy of the GNU General Public License
 
22
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
*/
 
24
 
 
25
#include "includes.h"
 
26
#include "winbindd.h"
 
27
 
 
28
#undef DBGC_CLASS
 
29
#define DBGC_CLASS DBGC_WINBIND
 
30
 
 
31
static void add_member(const char *domain, const char *user,
 
32
           char **pp_members, size_t *p_num_members)
 
33
{
 
34
        fstring name;
 
35
 
 
36
        if (domain != NULL) {
 
37
                fill_domain_username(name, domain, user, True);
 
38
        } else {
 
39
                fstrcpy(name, user);
 
40
        }
 
41
        safe_strcat(name, ",", sizeof(name)-1);
 
42
        string_append(pp_members, name);
 
43
        *p_num_members += 1;
 
44
}
 
45
 
 
46
/**********************************************************************
 
47
 Add member users resulting from sid. Expand if it is a domain group.
 
48
**********************************************************************/
 
49
 
 
50
static void add_expanded_sid(const DOM_SID *sid,
 
51
                             char **pp_members,
 
52
                             size_t *p_num_members)
 
53
{
 
54
        DOM_SID dom_sid;
 
55
        uint32 rid;
 
56
        struct winbindd_domain *domain;
 
57
        size_t i;
 
58
 
 
59
        char *domain_name = NULL;
 
60
        char *name = NULL;
 
61
        enum lsa_SidType type;
 
62
 
 
63
        uint32 num_names;
 
64
        DOM_SID *sid_mem;
 
65
        char **names;
 
66
        uint32 *types;
 
67
 
 
68
        NTSTATUS result;
 
69
 
 
70
        TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
 
71
 
 
72
        if (mem_ctx == NULL) {
 
73
                DEBUG(1, ("talloc_init failed\n"));
 
74
                return;
 
75
        }
 
76
 
 
77
        sid_copy(&dom_sid, sid);
 
78
        sid_split_rid(&dom_sid, &rid);
 
79
 
 
80
        domain = find_lookup_domain_from_sid(sid);
 
81
 
 
82
        if (domain == NULL) {
 
83
                DEBUG(3, ("Could not find domain for sid %s\n",
 
84
                          sid_string_dbg(sid)));
 
85
                goto done;
 
86
        }
 
87
 
 
88
        result = domain->methods->sid_to_name(domain, mem_ctx, sid,
 
89
                                              &domain_name, &name, &type);
 
90
 
 
91
        if (!NT_STATUS_IS_OK(result)) {
 
92
                DEBUG(3, ("sid_to_name failed for sid %s\n",
 
93
                          sid_string_dbg(sid)));
 
94
                goto done;
 
95
        }
 
96
 
 
97
        DEBUG(10, ("Found name %s, type %d\n", name, type));
 
98
 
 
99
        if (type == SID_NAME_USER) {
 
100
                add_member(domain_name, name, pp_members, p_num_members);
 
101
                goto done;
 
102
        }
 
103
 
 
104
        if (type != SID_NAME_DOM_GRP) {
 
105
                DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
 
106
                           name));
 
107
                goto done;
 
108
        }
 
109
 
 
110
        /* Expand the domain group, this must be done via the target domain */
 
111
 
 
112
        domain = find_domain_from_sid(sid);
 
113
 
 
114
        if (domain == NULL) {
 
115
                DEBUG(3, ("Could not find domain from SID %s\n",
 
116
                          sid_string_dbg(sid)));
 
117
                goto done;
 
118
        }
 
119
 
 
120
        result = domain->methods->lookup_groupmem(domain, mem_ctx,
 
121
                                                  sid, &num_names,
 
122
                                                  &sid_mem, &names,
 
123
                                                  &types);
 
124
 
 
125
        if (!NT_STATUS_IS_OK(result)) {
 
126
                DEBUG(10, ("Could not lookup group members for %s: %s\n",
 
127
                           name, nt_errstr(result)));
 
128
                goto done;
 
129
        }
 
130
 
 
131
        for (i=0; i<num_names; i++) {
 
132
                DEBUG(10, ("Adding group member SID %s\n",
 
133
                           sid_string_dbg(&sid_mem[i])));
 
134
 
 
135
                if (types[i] != SID_NAME_USER) {
 
136
                        DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
 
137
                                  "Ignoring.\n", names[i], name));
 
138
                        continue;
 
139
                }
 
140
 
 
141
                add_member(NULL, names[i], pp_members, p_num_members);
 
142
        }
 
143
 
 
144
 done:
 
145
        talloc_destroy(mem_ctx);
 
146
        return;
 
147
}
 
148
 
 
149
static bool fill_passdb_alias_grmem(struct winbindd_domain *domain,
 
150
                                    DOM_SID *group_sid, size_t *num_gr_mem,
 
151
                                    char **gr_mem, size_t *gr_mem_len)
 
152
{
 
153
        DOM_SID *members;
 
154
        size_t i, num_members;
 
155
 
 
156
        *num_gr_mem = 0;
 
157
        *gr_mem = NULL;
 
158
        *gr_mem_len = 0;
 
159
 
 
160
        if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
 
161
                                               &num_members)))
 
162
                return True;
 
163
 
 
164
        for (i=0; i<num_members; i++) {
 
165
                add_expanded_sid(&members[i], gr_mem, num_gr_mem);
 
166
        }
 
167
 
 
168
        TALLOC_FREE(members);
 
169
 
 
170
        if (*gr_mem != NULL) {
 
171
                size_t len;
 
172
 
 
173
                /* We have at least one member, strip off the last "," */
 
174
                len = strlen(*gr_mem);
 
175
                (*gr_mem)[len-1] = '\0';
 
176
                *gr_mem_len = len;
 
177
        }
 
178
 
 
179
        return True;
 
180
}
 
181
 
 
182
/* Fill a grent structure from various other information */
 
183
 
 
184
static bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr,
 
185
                       const char *dom_name,
 
186
                       char *gr_name, gid_t unix_gid)
 
187
{
 
188
        fstring full_group_name;
 
189
        char *mapped_name = NULL;
 
190
        struct winbindd_domain *domain = find_domain_from_name_noinit(dom_name);
 
191
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
192
 
 
193
        nt_status = normalize_name_map(mem_ctx, domain, gr_name,
 
194
                                       &mapped_name);
 
195
 
 
196
        /* Basic whitespace replacement */
 
197
        if (NT_STATUS_IS_OK(nt_status)) {
 
198
                fill_domain_username(full_group_name, dom_name,
 
199
                                     mapped_name, true);
 
200
        }
 
201
        /* Mapped to an aliase */
 
202
        else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
 
203
                fstrcpy(full_group_name, mapped_name);
 
204
        }
 
205
        /* no change */
 
206
        else {
 
207
                fill_domain_username( full_group_name, dom_name,
 
208
                                      gr_name, True );
 
209
        }
 
210
 
 
211
        gr->gr_gid = unix_gid;
 
212
 
 
213
        /* Group name and password */
 
214
 
 
215
        safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
 
216
        safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
 
217
 
 
218
        return True;
 
219
}
 
220
 
 
221
/***********************************************************************
 
222
 If "enum users" is set to false, and the group being looked
 
223
 up is the Domain Users SID: S-1-5-domain-513, then for the
 
224
 list of members check if the querying user is in that group,
 
225
 and if so only return that user as the gr_mem array.
 
226
 We can change this to a different parameter than "enum users"
 
227
 if neccessaey, or parameterize the group list we do this for.
 
228
***********************************************************************/
 
229
 
 
230
static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
 
231
                                     struct winbindd_domain *domain,
 
232
                                     struct winbindd_cli_state *state,
 
233
                                     DOM_SID *group_sid,
 
234
                                     enum lsa_SidType group_name_type,
 
235
                                     size_t *num_gr_mem, char **gr_mem,
 
236
                                     size_t *gr_mem_len)
 
237
{
 
238
        DOM_SID querying_user_sid;
 
239
        DOM_SID *pquerying_user_sid = NULL;
 
240
        uint32 num_groups = 0;
 
241
        DOM_SID *user_sids = NULL;
 
242
        bool u_in_group = False;
 
243
        NTSTATUS status;
 
244
        int i;
 
245
        unsigned int buf_len = 0;
 
246
        char *buf = NULL;
 
247
 
 
248
        DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
 
249
                  domain->name ));
 
250
 
 
251
        if (state) {
 
252
                uid_t ret_uid = (uid_t)-1;
 
253
                if (sys_getpeereid(state->sock, &ret_uid)==0) {
 
254
                        /* We know who's asking - look up their SID if
 
255
                           it's one we've mapped before. */
 
256
                        status = idmap_uid_to_sid(domain->name,
 
257
                                                  &querying_user_sid, ret_uid);
 
258
                        if (NT_STATUS_IS_OK(status)) {
 
259
                                pquerying_user_sid = &querying_user_sid;
 
260
                                DEBUG(10,("fill_grent_mem_domain_users: "
 
261
                                          "querying uid %u -> %s\n",
 
262
                                          (unsigned int)ret_uid,
 
263
                                          sid_string_dbg(pquerying_user_sid)));
 
264
                        }
 
265
                }
 
266
        }
 
267
 
 
268
        /* Only look up if it was a winbindd user in this domain. */
 
269
        if (pquerying_user_sid &&
 
270
            (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
 
271
 
 
272
                DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
 
273
                          sid_string_dbg(pquerying_user_sid) ));
 
274
 
 
275
                status = domain->methods->lookup_usergroups(domain,
 
276
                                                            mem_ctx,
 
277
                                                            pquerying_user_sid,
 
278
                                                            &num_groups,
 
279
                                                            &user_sids);
 
280
                if (!NT_STATUS_IS_OK(status)) {
 
281
                        DEBUG(1, ("fill_grent_mem_domain_users: "
 
282
                                  "lookup_usergroups failed "
 
283
                                  "for sid %s in domain %s (error: %s)\n",
 
284
                                  sid_string_dbg(pquerying_user_sid),
 
285
                                  domain->name,
 
286
                                  nt_errstr(status)));
 
287
                        return False;
 
288
                }
 
289
 
 
290
                for (i = 0; i < num_groups; i++) {
 
291
                        if (sid_equal(group_sid, &user_sids[i])) {
 
292
                                /* User is in Domain Users, add their name
 
293
                                   as the only group member. */
 
294
                                u_in_group = True;
 
295
                                break;
 
296
                        }
 
297
                }
 
298
        }
 
299
 
 
300
        if (u_in_group) {
 
301
                size_t len = 0;
 
302
                char *domainname = NULL;
 
303
                char *username = NULL;
 
304
                fstring name;
 
305
                char *mapped_name = NULL;
 
306
                enum lsa_SidType type;
 
307
                struct winbindd_domain *target_domain = NULL;
 
308
                NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 
309
 
 
310
                DEBUG(10,("fill_grent_mem_domain_users: "
 
311
                          "sid %s in 'Domain Users' in domain %s\n",
 
312
                          sid_string_dbg(pquerying_user_sid),
 
313
                          domain->name ));
 
314
 
 
315
                status = domain->methods->sid_to_name(domain, mem_ctx,
 
316
                                                      pquerying_user_sid,
 
317
                                                      &domainname,
 
318
                                                      &username,
 
319
                                                      &type);
 
320
                if (!NT_STATUS_IS_OK(status)) {
 
321
                        DEBUG(1, ("could not lookup username for user "
 
322
                                  "sid %s in domain %s (error: %s)\n",
 
323
                                  sid_string_dbg(pquerying_user_sid),
 
324
                                  domain->name,
 
325
                                  nt_errstr(status)));
 
326
                        return False;
 
327
                }
 
328
 
 
329
                target_domain = find_domain_from_name_noinit(domainname);
 
330
                name_map_status = normalize_name_map(mem_ctx, target_domain,
 
331
                                                     username, &mapped_name);
 
332
 
 
333
                /* Basic whitespace replacement */
 
334
                if (NT_STATUS_IS_OK(name_map_status)) {
 
335
                        fill_domain_username(name, domainname, mapped_name, true);
 
336
                }
 
337
                /* Mapped to an alias */
 
338
                else if (NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
 
339
                        fstrcpy(name, mapped_name);
 
340
                }
 
341
                /* no mapping done...use original name */
 
342
                else {
 
343
                        fill_domain_username(name, domainname, username, true);
 
344
                }
 
345
 
 
346
                len = strlen(name);
 
347
                buf_len = len + 1;
 
348
                if (!(buf = (char *)SMB_MALLOC(buf_len))) {
 
349
                        DEBUG(1, ("out of memory\n"));
 
350
                        return False;
 
351
                }
 
352
                memcpy(buf, name, buf_len);
 
353
 
 
354
                DEBUG(10,("fill_grent_mem_domain_users: user %s in "
 
355
                          "'Domain Users' in domain %s\n",
 
356
                          name, domain->name ));
 
357
 
 
358
                /* user is the only member */
 
359
                *num_gr_mem = 1;
 
360
        }
 
361
 
 
362
        *gr_mem = buf;
 
363
        *gr_mem_len = buf_len;
 
364
 
 
365
        DEBUG(10, ("fill_grent_mem_domain_users: "
 
366
                   "num_mem = %u, len = %u, mem = %s\n",
 
367
                   (unsigned int)*num_gr_mem,
 
368
                   (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
 
369
 
 
370
        return True;
 
371
}
 
372
 
 
373
/***********************************************************************
 
374
 Add names to a list.  Assumes  a canonical version of the string
 
375
 in DOMAIN\user
 
376
***********************************************************************/
 
377
 
 
378
static int namecmp( const void *a, const void *b )
 
379
{
 
380
        return StrCaseCmp( * (char * const *) a, * (char * const *) b);
 
381
}
 
382
 
 
383
static void sort_unique_list(char ***list, uint32 *n_list)
 
384
{
 
385
        uint32_t i;
 
386
 
 
387
        /* search for duplicates for sorting and looking for matching
 
388
           neighbors */
 
389
 
 
390
        qsort(*list, *n_list, sizeof(char*), QSORT_CAST namecmp);
 
391
 
 
392
        for (i=1; i < *n_list; i++) {
 
393
                if (strcmp((*list)[i-1], (*list)[i]) == 0) {
 
394
                        memmove(&((*list)[i-1]), &((*list)[i]),
 
395
                                 sizeof(char*)*((*n_list)-i));
 
396
                        (*n_list)--;
 
397
                }
 
398
        }
 
399
}
 
400
 
 
401
static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
 
402
                                   char ***list, uint32 *n_list,
 
403
                                   char **names, uint32 n_names )
 
404
{
 
405
        char **new_list = NULL;
 
406
        uint32 n_new_list = 0;
 
407
        int i, j;
 
408
 
 
409
        if ( !names || (n_names == 0) )
 
410
                return NT_STATUS_OK;
 
411
 
 
412
        /* Alloc the maximum size we'll need */
 
413
 
 
414
        if ( *list == NULL ) {
 
415
                if ((new_list = TALLOC_ARRAY(ctx, char *, n_names)) == NULL) {
 
416
                        return NT_STATUS_NO_MEMORY;
 
417
                }
 
418
                n_new_list = n_names;
 
419
        } else {
 
420
                new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
 
421
                                                 (*n_list) + n_names );
 
422
                if ( !new_list )
 
423
                        return NT_STATUS_NO_MEMORY;
 
424
                n_new_list = (*n_list) + n_names;
 
425
        }
 
426
 
 
427
        /* Add all names */
 
428
 
 
429
        for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
 
430
                new_list[i] = talloc_strdup( new_list, names[j] );
 
431
        }
 
432
 
 
433
        *list = new_list;
 
434
        *n_list = n_new_list;
 
435
 
 
436
        return NT_STATUS_OK;
 
437
}
 
438
 
 
439
/***********************************************************************
 
440
***********************************************************************/
 
441
 
 
442
static NTSTATUS expand_groups( TALLOC_CTX *ctx,
 
443
                               struct winbindd_domain *d,
 
444
                               DOM_SID *glist, uint32 n_glist,
 
445
                               DOM_SID **new_glist, uint32 *n_new_glist,
 
446
                               char ***members, uint32 *n_members )
 
447
{
 
448
        int i, j;
 
449
        NTSTATUS status = NT_STATUS_OK;
 
450
        uint32 num_names = 0;
 
451
        uint32 *name_types = NULL;
 
452
        char **names = NULL;
 
453
        DOM_SID *sid_mem = NULL;
 
454
        TALLOC_CTX *tmp_ctx = NULL;
 
455
        DOM_SID *new_groups = NULL;
 
456
        size_t new_groups_size = 0;
 
457
 
 
458
        *members = NULL;
 
459
        *n_members = 0;
 
460
        *new_glist = NULL;
 
461
        *n_new_glist = 0;
 
462
 
 
463
        for ( i=0; i<n_glist; i++ ) {
 
464
                tmp_ctx = talloc_new( ctx );
 
465
 
 
466
                /* Lookup the group membership */
 
467
 
 
468
                status = d->methods->lookup_groupmem(d, tmp_ctx,
 
469
                                                     &glist[i], &num_names,
 
470
                                                     &sid_mem, &names,
 
471
                                                     &name_types);
 
472
                if ( !NT_STATUS_IS_OK(status) )
 
473
                        goto out;
 
474
 
 
475
                /* Separate users and groups into two lists */
 
476
 
 
477
                for ( j=0; j<num_names; j++ ) {
 
478
 
 
479
                        /* Users */
 
480
                        if ( name_types[j] == SID_NAME_USER ||
 
481
                             name_types[j] == SID_NAME_COMPUTER )
 
482
                        {
 
483
                                status = add_names_to_list( ctx, members,
 
484
                                                            n_members,
 
485
                                                            names+j, 1 );
 
486
                                if ( !NT_STATUS_IS_OK(status) )
 
487
                                        goto out;
 
488
 
 
489
                                continue;
 
490
                        }
 
491
 
 
492
                        /* Groups */
 
493
                        if ( name_types[j] == SID_NAME_DOM_GRP ||
 
494
                             name_types[j] == SID_NAME_ALIAS )
 
495
                        {
 
496
                                status = add_sid_to_array_unique(ctx,
 
497
                                                                 &sid_mem[j],
 
498
                                                                 &new_groups,
 
499
                                                                 &new_groups_size);
 
500
                                if (!NT_STATUS_IS_OK(status)) {
 
501
                                        goto out;
 
502
                                }
 
503
 
 
504
                                continue;
 
505
                        }
 
506
                }
 
507
 
 
508
                TALLOC_FREE( tmp_ctx );
 
509
        }
 
510
 
 
511
        *new_glist = new_groups;
 
512
        *n_new_glist = (uint32)new_groups_size;
 
513
 
 
514
 out:
 
515
        TALLOC_FREE( tmp_ctx );
 
516
 
 
517
        return status;
 
518
}
 
519
 
 
520
/***********************************************************************
 
521
 Fill in the group membership field of a NT group given by group_sid
 
522
***********************************************************************/
 
523
 
 
524
static bool fill_grent_mem(struct winbindd_domain *domain,
 
525
                           struct winbindd_cli_state *state,
 
526
                           DOM_SID *group_sid,
 
527
                           enum lsa_SidType group_name_type,
 
528
                           size_t *num_gr_mem, char **gr_mem,
 
529
                           size_t *gr_mem_len)
 
530
{
 
531
        uint32 num_names = 0;
 
532
        unsigned int buf_len = 0, buf_ndx = 0, i;
 
533
        char **names = NULL, *buf = NULL;
 
534
        bool result = False;
 
535
        TALLOC_CTX *mem_ctx;
 
536
        uint32 group_rid;
 
537
        DOM_SID *glist = NULL;
 
538
        DOM_SID *new_glist = NULL;
 
539
        uint32 n_glist, n_new_glist;
 
540
        int max_depth = lp_winbind_expand_groups();
 
541
 
 
542
        if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
 
543
                return False;
 
544
 
 
545
        DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
 
546
 
 
547
        /* Initialize with no members */
 
548
 
 
549
        *num_gr_mem = 0;
 
550
 
 
551
        /* HACK ALERT!! This whole routine does not cope with group members
 
552
         * from more than one domain, ie aliases. Thus we have to work it out
 
553
         * ourselves in a special routine. */
 
554
 
 
555
        if (domain->internal) {
 
556
                result = fill_passdb_alias_grmem(domain, group_sid,
 
557
                                               num_gr_mem,
 
558
                                               gr_mem, gr_mem_len);
 
559
                goto done;
 
560
        }
 
561
 
 
562
        /* Verify name type */
 
563
 
 
564
        if ( !((group_name_type==SID_NAME_DOM_GRP) ||
 
565
               ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
 
566
        {
 
567
                DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
 
568
                          sid_string_dbg(group_sid),
 
569
                          domain->name, group_name_type));
 
570
                goto done;
 
571
        }
 
572
 
 
573
        /* OPTIMIZATION / HACK. See comment in
 
574
           fill_grent_mem_domusers() */
 
575
 
 
576
        sid_peek_rid( group_sid, &group_rid );
 
577
        if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
 
578
                result = fill_grent_mem_domusers( mem_ctx, domain, state,
 
579
                                                  group_sid, group_name_type,
 
580
                                                  num_gr_mem, gr_mem,
 
581
                                                  gr_mem_len );
 
582
                goto done;
 
583
        }
 
584
 
 
585
        /* Real work goes here.  Create a list of group names to
 
586
           expand starting with the initial one.  Pass that to
 
587
           expand_groups() which returns a list of more group names
 
588
           to expand.  Do this up to the max search depth. */
 
589
 
 
590
        if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
 
591
                result = False;
 
592
                DEBUG(0,("fill_grent_mem: talloc failure!\n"));
 
593
                goto done;
 
594
        }
 
595
        sid_copy( &glist[0], group_sid );
 
596
        n_glist = 1;
 
597
 
 
598
        for ( i=0; i<max_depth && glist; i++ ) {
 
599
                uint32 n_members = 0;
 
600
                char **members = NULL;
 
601
                NTSTATUS nt_status;
 
602
                int j;
 
603
 
 
604
                nt_status = expand_groups( mem_ctx, domain,
 
605
                                           glist, n_glist,
 
606
                                           &new_glist, &n_new_glist,
 
607
                                           &members, &n_members);
 
608
                if ( !NT_STATUS_IS_OK(nt_status) ) {
 
609
                        result = False;
 
610
                        goto done;
 
611
                }
 
612
 
 
613
                /* Add new group members to list.  Pass through the
 
614
                   alias mapping function */
 
615
 
 
616
                for (j=0; j<n_members; j++) {
 
617
                        fstring name_domain, name_acct;
 
618
                        fstring qualified_name;
 
619
                        char *mapped_name = NULL;
 
620
                        NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 
621
                        struct winbindd_domain *target_domain = NULL;
 
622
 
 
623
                        if (parse_domain_user(members[j], name_domain, name_acct)) {
 
624
                                target_domain = find_domain_from_name_noinit(name_domain);
 
625
                                /* NOW WHAT ? */
 
626
                        }
 
627
                        if (!target_domain) {
 
628
                                target_domain = domain;
 
629
                        }
 
630
 
 
631
                        name_map_status = normalize_name_map(members, target_domain,
 
632
                                                             name_acct, &mapped_name);
 
633
 
 
634
                        /* Basic whitespace replacement */
 
635
                        if (NT_STATUS_IS_OK(name_map_status)) {
 
636
                                fill_domain_username(qualified_name, name_domain,
 
637
                                                     mapped_name, true);
 
638
                                mapped_name = qualified_name;
 
639
                        }
 
640
                        /* no mapping at all */
 
641
                        else if (!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
 
642
                                mapped_name = members[j];
 
643
                        }
 
644
 
 
645
                        nt_status = add_names_to_list( mem_ctx, &names,
 
646
                                                       &num_names,
 
647
                                                       &mapped_name, 1);
 
648
                        if ( !NT_STATUS_IS_OK(nt_status) ) {
 
649
                                result = False;
 
650
                                goto done;
 
651
                        }
 
652
                }
 
653
 
 
654
                TALLOC_FREE( members );
 
655
 
 
656
                /* If we have no more groups to expand, break out
 
657
                   early */
 
658
 
 
659
                if (new_glist == NULL)
 
660
                        break;
 
661
 
 
662
                /* One more round */
 
663
                TALLOC_FREE(glist);
 
664
                glist = new_glist;
 
665
                n_glist = n_new_glist;
 
666
        }
 
667
        TALLOC_FREE( glist );
 
668
 
 
669
        sort_unique_list(&names, &num_names);
 
670
 
 
671
        DEBUG(10, ("looked up %d names\n", num_names));
 
672
 
 
673
 again:
 
674
        /* Add members to list */
 
675
 
 
676
        for (i = 0; i < num_names; i++) {
 
677
                int len;
 
678
 
 
679
                DEBUG(10, ("processing name %s\n", names[i]));
 
680
 
 
681
                len = strlen(names[i]);
 
682
 
 
683
                /* Add to list or calculate buffer length */
 
684
 
 
685
                if (!buf) {
 
686
                        buf_len += len + 1; /* List is comma separated */
 
687
                        (*num_gr_mem)++;
 
688
                        DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
 
689
                } else {
 
690
                        DEBUG(10, ("appending %s at ndx %d\n",
 
691
                                   names[i], buf_ndx));
 
692
                        parse_add_domuser(&buf[buf_ndx], names[i], &len);
 
693
                        buf_ndx += len;
 
694
                        buf[buf_ndx] = ',';
 
695
                        buf_ndx++;
 
696
                }
 
697
        }
 
698
 
 
699
        /* Allocate buffer */
 
700
 
 
701
        if (!buf && buf_len != 0) {
 
702
                if (!(buf = (char *)SMB_MALLOC(buf_len))) {
 
703
                        DEBUG(1, ("out of memory\n"));
 
704
                        result = False;
 
705
                        goto done;
 
706
                }
 
707
                memset(buf, 0, buf_len);
 
708
                goto again;
 
709
        }
 
710
 
 
711
        /* Now we're done */
 
712
 
 
713
        if (buf && buf_ndx > 0) {
 
714
                buf[buf_ndx - 1] = '\0';
 
715
        }
 
716
 
 
717
        *gr_mem = buf;
 
718
        *gr_mem_len = buf_len;
 
719
 
 
720
        DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
 
721
                   (unsigned int)*num_gr_mem,
 
722
                   (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
 
723
        result = True;
 
724
 
 
725
done:
 
726
 
 
727
        talloc_destroy(mem_ctx);
 
728
 
 
729
        DEBUG(10, ("fill_grent_mem returning %d\n", result));
 
730
 
 
731
        return result;
 
732
}
 
733
 
 
734
static void winbindd_getgrsid(struct winbindd_cli_state *state, DOM_SID group_sid);
 
735
 
 
736
static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
 
737
                           enum lsa_SidType type )
 
738
{
 
739
        struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
 
740
 
 
741
        if (!success) {
 
742
                DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
 
743
                request_error(state);
 
744
                return;
 
745
        }
 
746
 
 
747
        if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
 
748
                DEBUG(5,("getgrnam_recv: not a group!\n"));
 
749
                request_error(state);
 
750
                return;
 
751
        }
 
752
 
 
753
        winbindd_getgrsid( state, *sid );
 
754
}
 
755
 
 
756
 
 
757
/* Return a group structure from a group name */
 
758
 
 
759
void winbindd_getgrnam(struct winbindd_cli_state *state)
 
760
{
 
761
        struct winbindd_domain *domain;
 
762
        fstring name_domain, name_group;
 
763
        char *tmp;
 
764
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
765
 
 
766
        /* Ensure null termination */
 
767
        state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
 
768
 
 
769
        DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
 
770
                  state->request.data.groupname));
 
771
 
 
772
        nt_status = normalize_name_unmap(state->mem_ctx,
 
773
                                         state->request.data.groupname,
 
774
                                         &tmp);
 
775
        /* If we didn't map anything in the above call, just reset the
 
776
           tmp pointer to the original string */
 
777
        if (!NT_STATUS_IS_OK(nt_status) &&
 
778
            !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
 
779
        {
 
780
                tmp = state->request.data.groupname;
 
781
        }
 
782
 
 
783
        /* Parse domain and groupname */
 
784
 
 
785
        memset(name_group, 0, sizeof(name_group));
 
786
 
 
787
        name_domain[0] = '\0';
 
788
        name_group[0] = '\0';
 
789
 
 
790
        parse_domain_user(tmp, name_domain, name_group);
 
791
 
 
792
        /* if no domain or our local domain and no local tdb group, default to
 
793
         * our local domain for aliases */
 
794
 
 
795
        if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
 
796
                fstrcpy(name_domain, get_global_sam_name());
 
797
        }
 
798
 
 
799
        /* Get info for the domain */
 
800
 
 
801
        if ((domain = find_domain_from_name_noinit(name_domain)) == NULL) {
 
802
                DEBUG(3, ("could not get domain sid for domain %s\n",
 
803
                          name_domain));
 
804
                request_error(state);
 
805
                return;
 
806
        }
 
807
        /* should we deal with users for our domain? */
 
808
 
 
809
        if ( lp_winbind_trusted_domains_only() && domain->primary) {
 
810
                DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
 
811
                         "getgrnam() for %s\\%s.\n", name_domain, name_group));
 
812
                request_error(state);
 
813
                return;
 
814
        }
 
815
 
 
816
        /* Get rid and name type from name */
 
817
 
 
818
        fstrcpy( name_group, tmp );
 
819
 
 
820
        winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
 
821
                                   getgrnam_recv, WINBINDD_GETGRNAM, state );
 
822
}
 
823
 
 
824
struct getgrsid_state {
 
825
        struct winbindd_cli_state *state;
 
826
        struct winbindd_domain *domain;
 
827
        char *group_name;
 
828
        enum lsa_SidType group_type;
 
829
        uid_t gid;
 
830
        DOM_SID group_sid;
 
831
};
 
832
 
 
833
static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
 
834
{
 
835
        struct getgrsid_state *s =
 
836
                (struct getgrsid_state *)private_data;
 
837
        struct winbindd_domain *domain;
 
838
        size_t gr_mem_len;
 
839
        size_t num_gr_mem;
 
840
        char *gr_mem;
 
841
        fstring dom_name, group_name;
 
842
 
 
843
        if (!success) {
 
844
                DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
 
845
                request_error(s->state);
 
846
                return;
 
847
        }
 
848
 
 
849
        s->gid = gid;
 
850
 
 
851
        if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
 
852
                DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
 
853
                request_error(s->state);
 
854
                return;
 
855
        }
 
856
 
 
857
 
 
858
        /* Fill in group structure */
 
859
 
 
860
        if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
 
861
                DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
 
862
                request_error(s->state);
 
863
                return;
 
864
        }
 
865
 
 
866
        if (!fill_grent(s->state->mem_ctx, &s->state->response.data.gr,
 
867
                        dom_name, group_name, gid) ||
 
868
            !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
 
869
                            &num_gr_mem, &gr_mem, &gr_mem_len))
 
870
        {
 
871
                request_error(s->state);
 
872
                return;
 
873
        }
 
874
 
 
875
        s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
 
876
 
 
877
        /* Group membership lives at start of extra data */
 
878
 
 
879
        s->state->response.data.gr.gr_mem_ofs = 0;
 
880
 
 
881
        s->state->response.length += gr_mem_len;
 
882
        s->state->response.extra_data.data = gr_mem;
 
883
 
 
884
        request_ok(s->state);
 
885
}
 
886
 
 
887
static void getgrsid_lookupsid_recv( void *private_data, bool success,
 
888
                                     const char *dom_name, const char *name,
 
889
                                     enum lsa_SidType name_type )
 
890
{
 
891
        struct getgrsid_state *s = (struct getgrsid_state *)private_data;
 
892
        char *mapped_name = NULL;
 
893
        fstring raw_name;
 
894
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
895
 
 
896
        if (!success) {
 
897
                DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
 
898
                request_error(s->state);
 
899
                return;
 
900
        }
 
901
 
 
902
        /* either it's a domain group, a domain local group, or a
 
903
           local group in an internal domain */
 
904
 
 
905
        if ( !( (name_type==SID_NAME_DOM_GRP) ||
 
906
                ((name_type==SID_NAME_ALIAS) &&
 
907
                 (s->domain->primary || s->domain->internal)) ) )
 
908
        {
 
909
                DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
 
910
                          dom_name, name, name_type));
 
911
                request_error(s->state);
 
912
                return;
 
913
        }
 
914
 
 
915
        /* normalize the name and ensure that we have the DOM\name
 
916
          coming out of here */
 
917
 
 
918
        fstrcpy(raw_name, name);
 
919
 
 
920
        nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name,
 
921
                                         &mapped_name);
 
922
 
 
923
        /* basic whitespace reversal */
 
924
        if (NT_STATUS_IS_OK(nt_status)) {
 
925
                s->group_name = talloc_asprintf(s->state->mem_ctx,
 
926
                                                "%s%c%s",
 
927
                                                dom_name,
 
928
                                                *lp_winbind_separator(),
 
929
                                                mapped_name);
 
930
        }
 
931
        /* mapped from alias */
 
932
        else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
 
933
                s->group_name = mapped_name;
 
934
        }
 
935
        /* no mapping at all.  use original string */
 
936
        else {
 
937
                s->group_name = talloc_asprintf(s->state->mem_ctx,
 
938
                                                "%s%c%s",
 
939
                                                dom_name,
 
940
                                                *lp_winbind_separator(),
 
941
                                                raw_name);
 
942
        }
 
943
 
 
944
        if (s->group_name == NULL) {
 
945
                DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n"));
 
946
                request_error(s->state);
 
947
                return;
 
948
        }
 
949
 
 
950
        s->group_type = name_type;
 
951
 
 
952
        winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
 
953
                               getgrsid_sid2gid_recv, s);
 
954
}
 
955
 
 
956
static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
 
957
{
 
958
        struct getgrsid_state *s;
 
959
 
 
960
        if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
 
961
                DEBUG(0, ("talloc failed\n"));
 
962
                request_error(state);
 
963
                return;
 
964
        }
 
965
 
 
966
        s->state = state;
 
967
 
 
968
        if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
 
969
                DEBUG(3, ("Could not find domain for sid %s\n",
 
970
                          sid_string_dbg(&group_sid)));
 
971
                request_error(state);
 
972
                return;
 
973
        }
 
974
 
 
975
        sid_copy(&s->group_sid, &group_sid);
 
976
 
 
977
        winbindd_lookupsid_async( s->state->mem_ctx,  &group_sid,
 
978
                                  getgrsid_lookupsid_recv, s );
 
979
}
 
980
 
 
981
 
 
982
static void getgrgid_recv(void *private_data, bool success, const char *sid)
 
983
{
 
984
        struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
 
985
        enum lsa_SidType name_type;
 
986
        DOM_SID group_sid;
 
987
 
 
988
        if (success) {
 
989
                DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
 
990
                          (unsigned long)(state->request.data.gid), sid));
 
991
 
 
992
                if (!string_to_sid(&group_sid, sid)) {
 
993
                        DEBUG(1,("getgrgid_recv: Could not convert sid %s "
 
994
                                "from string\n", sid));
 
995
                        request_error(state);
 
996
                        return;
 
997
                }
 
998
 
 
999
                winbindd_getgrsid(state, group_sid);
 
1000
                return;
 
1001
        }
 
1002
 
 
1003
        /* Ok, this might be "ours", i.e. an alias */
 
1004
        if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
 
1005
            lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
 
1006
            (name_type == SID_NAME_ALIAS)) {
 
1007
                /* Hey, got an alias */
 
1008
                DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
 
1009
                          (unsigned long)(state->request.data.gid), sid));
 
1010
                winbindd_getgrsid(state, group_sid);
 
1011
                return;
 
1012
        }
 
1013
 
 
1014
        DEBUG(1, ("could not convert gid %lu to sid\n",
 
1015
                  (unsigned long)state->request.data.gid));
 
1016
        request_error(state);
 
1017
}
 
1018
 
 
1019
/* Return a group structure from a gid number */
 
1020
void winbindd_getgrgid(struct winbindd_cli_state *state)
 
1021
{
 
1022
        gid_t gid = state->request.data.gid;
 
1023
 
 
1024
        DEBUG(3, ("[%5lu]: getgrgid %lu\n",
 
1025
                  (unsigned long)state->pid,
 
1026
                  (unsigned long)gid));
 
1027
 
 
1028
        /* always use the async interface */
 
1029
        winbindd_gid2sid_async(state->mem_ctx, gid, getgrgid_recv, state);
 
1030
}
 
1031
 
 
1032
/*
 
1033
 * set/get/endgrent functions
 
1034
 */
 
1035
 
 
1036
/* "Rewind" file pointer for group database enumeration */
 
1037
 
 
1038
static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
 
1039
{
 
1040
        struct winbindd_domain *domain;
 
1041
 
 
1042
        DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
 
1043
 
 
1044
        /* Check user has enabled this */
 
1045
 
 
1046
        if (!lp_winbind_enum_groups()) {
 
1047
                return False;
 
1048
        }
 
1049
 
 
1050
        /* Free old static data if it exists */
 
1051
 
 
1052
        if (state->getgrent_state != NULL) {
 
1053
                free_getent_state(state->getgrent_state);
 
1054
                state->getgrent_state = NULL;
 
1055
        }
 
1056
 
 
1057
        /* Create sam pipes for each domain we know about */
 
1058
 
 
1059
        for (domain = domain_list(); domain != NULL; domain = domain->next) {
 
1060
                struct getent_state *domain_state;
 
1061
 
 
1062
                /* Create a state record for this domain */
 
1063
 
 
1064
                /* don't add our domaina if we are a PDC or if we
 
1065
                   are a member of a Samba domain */
 
1066
 
 
1067
                if ( lp_winbind_trusted_domains_only() && domain->primary )
 
1068
                {
 
1069
                        continue;
 
1070
                }
 
1071
 
 
1072
                domain_state = SMB_MALLOC_P(struct getent_state);
 
1073
                if (!domain_state) {
 
1074
                        DEBUG(1, ("winbindd_setgrent: "
 
1075
                                  "malloc failed for domain_state!\n"));
 
1076
                        return False;
 
1077
                }
 
1078
 
 
1079
                ZERO_STRUCTP(domain_state);
 
1080
 
 
1081
                fstrcpy(domain_state->domain_name, domain->name);
 
1082
 
 
1083
                /* Add to list of open domains */
 
1084
 
 
1085
                DLIST_ADD(state->getgrent_state, domain_state);
 
1086
        }
 
1087
 
 
1088
        state->getgrent_initialized = True;
 
1089
        return True;
 
1090
}
 
1091
 
 
1092
void winbindd_setgrent(struct winbindd_cli_state *state)
 
1093
{
 
1094
        if (winbindd_setgrent_internal(state)) {
 
1095
                request_ok(state);
 
1096
        } else {
 
1097
                request_error(state);
 
1098
        }
 
1099
}
 
1100
 
 
1101
/* Close file pointer to ntdom group database */
 
1102
 
 
1103
void winbindd_endgrent(struct winbindd_cli_state *state)
 
1104
{
 
1105
        DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
 
1106
 
 
1107
        free_getent_state(state->getgrent_state);
 
1108
        state->getgrent_initialized = False;
 
1109
        state->getgrent_state = NULL;
 
1110
        request_ok(state);
 
1111
}
 
1112
 
 
1113
/* Get the list of domain groups and domain aliases for a domain.  We fill in
 
1114
   the sam_entries and num_sam_entries fields with domain group information.
 
1115
   Return True if some groups were returned, False otherwise. */
 
1116
 
 
1117
bool get_sam_group_entries(struct getent_state *ent)
 
1118
{
 
1119
        NTSTATUS status;
 
1120
        uint32 num_entries;
 
1121
        struct acct_info *name_list = NULL;
 
1122
        TALLOC_CTX *mem_ctx;
 
1123
        bool result = False;
 
1124
        struct acct_info *sam_grp_entries = NULL;
 
1125
        struct winbindd_domain *domain;
 
1126
 
 
1127
        if (ent->got_sam_entries)
 
1128
                return False;
 
1129
 
 
1130
        if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
 
1131
                                          ent->domain_name))) {
 
1132
                DEBUG(1, ("get_sam_group_entries: "
 
1133
                          "could not create talloc context!\n"));
 
1134
                return False;
 
1135
        }
 
1136
 
 
1137
        /* Free any existing group info */
 
1138
 
 
1139
        SAFE_FREE(ent->sam_entries);
 
1140
        ent->num_sam_entries = 0;
 
1141
        ent->got_sam_entries = True;
 
1142
 
 
1143
        /* Enumerate domain groups */
 
1144
 
 
1145
        num_entries = 0;
 
1146
 
 
1147
        if (!(domain = find_domain_from_name(ent->domain_name))) {
 
1148
                DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
 
1149
                          ent->domain_name));
 
1150
                goto done;
 
1151
        }
 
1152
 
 
1153
        /* always get the domain global groups */
 
1154
 
 
1155
        status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
 
1156
                                                  &sam_grp_entries);
 
1157
 
 
1158
        if (!NT_STATUS_IS_OK(status)) {
 
1159
                DEBUG(3, ("get_sam_group_entries: "
 
1160
                          "could not enumerate domain groups! Error: %s\n",
 
1161
                          nt_errstr(status)));
 
1162
                result = False;
 
1163
                goto done;
 
1164
        }
 
1165
 
 
1166
        /* Copy entries into return buffer */
 
1167
 
 
1168
        if (num_entries) {
 
1169
                name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
 
1170
                if (!name_list) {
 
1171
                        DEBUG(0,("get_sam_group_entries: Failed to malloc "
 
1172
                                 "memory for %d domain groups!\n",
 
1173
                                 num_entries));
 
1174
                        result = False;
 
1175
                        goto done;
 
1176
                }
 
1177
                memcpy(name_list, sam_grp_entries,
 
1178
                        num_entries * sizeof(struct acct_info));
 
1179
        }
 
1180
 
 
1181
        ent->num_sam_entries = num_entries;
 
1182
 
 
1183
        /* get the domain local groups if we are a member of a native win2k
 
1184
         * domain and are not using LDAP to get the groups */
 
1185
 
 
1186
        if ( ( lp_security() != SEC_ADS && domain->native_mode
 
1187
                && domain->primary) || domain->internal )
 
1188
        {
 
1189
                DEBUG(4,("get_sam_group_entries: %s domain; "
 
1190
                         "enumerating local groups as well\n",
 
1191
                         domain->native_mode ? "Native Mode 2k":
 
1192
                                                "BUILTIN or local"));
 
1193
 
 
1194
                status = domain->methods->enum_local_groups(domain, mem_ctx,
 
1195
                                                            &num_entries,
 
1196
                                                            &sam_grp_entries);
 
1197
 
 
1198
                if ( !NT_STATUS_IS_OK(status) ) {
 
1199
                        DEBUG(3,("get_sam_group_entries: "
 
1200
                                "Failed to enumerate "
 
1201
                                "domain local groups with error %s!\n",
 
1202
                                nt_errstr(status)));
 
1203
                        num_entries = 0;
 
1204
                }
 
1205
                else
 
1206
                        DEBUG(4,("get_sam_group_entries: "
 
1207
                                 "Returned %d local groups\n",
 
1208
                                 num_entries));
 
1209
 
 
1210
                /* Copy entries into return buffer */
 
1211
 
 
1212
                if ( num_entries ) {
 
1213
                        name_list = SMB_REALLOC_ARRAY(name_list,
 
1214
                                                      struct acct_info,
 
1215
                                                      ent->num_sam_entries+
 
1216
                                                        num_entries);
 
1217
                        if (!name_list) {
 
1218
                                DEBUG(0,("get_sam_group_entries: "
 
1219
                                         "Failed to realloc more memory "
 
1220
                                         "for %d local groups!\n",
 
1221
                                         num_entries));
 
1222
                                result = False;
 
1223
                                goto done;
 
1224
                        }
 
1225
 
 
1226
                        memcpy(&name_list[ent->num_sam_entries],
 
1227
                                sam_grp_entries,
 
1228
                                num_entries * sizeof(struct acct_info));
 
1229
                }
 
1230
 
 
1231
                ent->num_sam_entries += num_entries;
 
1232
        }
 
1233
 
 
1234
 
 
1235
        /* Fill in remaining fields */
 
1236
 
 
1237
        ent->sam_entries = name_list;
 
1238
        ent->sam_entry_index = 0;
 
1239
 
 
1240
        result = (ent->num_sam_entries > 0);
 
1241
 
 
1242
 done:
 
1243
        talloc_destroy(mem_ctx);
 
1244
 
 
1245
        return result;
 
1246
}
 
1247
 
 
1248
/* Fetch next group entry from ntdom database */
 
1249
 
 
1250
#define MAX_GETGRENT_GROUPS 500
 
1251
 
 
1252
void winbindd_getgrent(struct winbindd_cli_state *state)
 
1253
{
 
1254
        struct getent_state *ent;
 
1255
        struct winbindd_gr *group_list = NULL;
 
1256
        int num_groups, group_list_ndx, gr_mem_list_len = 0;
 
1257
        char *gr_mem_list = NULL;
 
1258
 
 
1259
        DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
 
1260
 
 
1261
        /* Check user has enabled this */
 
1262
 
 
1263
        if (!lp_winbind_enum_groups()) {
 
1264
                request_error(state);
 
1265
                return;
 
1266
        }
 
1267
 
 
1268
        num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
 
1269
 
 
1270
        if (num_groups == 0) {
 
1271
                request_error(state);
 
1272
                return;
 
1273
        }
 
1274
 
 
1275
        group_list = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups);
 
1276
        if (!group_list) {
 
1277
                request_error(state);
 
1278
                return;
 
1279
        }
 
1280
        /* will be freed by process_request() */
 
1281
        state->response.extra_data.data = group_list;
 
1282
 
 
1283
        memset(state->response.extra_data.data, '\0',
 
1284
                num_groups * sizeof(struct winbindd_gr) );
 
1285
 
 
1286
        state->response.data.num_entries = 0;
 
1287
 
 
1288
        if (!state->getgrent_initialized)
 
1289
                winbindd_setgrent_internal(state);
 
1290
 
 
1291
        if (!(ent = state->getgrent_state)) {
 
1292
                request_error(state);
 
1293
                return;
 
1294
        }
 
1295
 
 
1296
        /* Start sending back groups */
 
1297
 
 
1298
        for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
 
1299
                struct acct_info *name_list = NULL;
 
1300
                fstring domain_group_name;
 
1301
                uint32 result;
 
1302
                gid_t group_gid;
 
1303
                size_t gr_mem_len;
 
1304
                char *gr_mem;
 
1305
                DOM_SID group_sid;
 
1306
                struct winbindd_domain *domain;
 
1307
 
 
1308
                /* Do we need to fetch another chunk of groups? */
 
1309
 
 
1310
        tryagain:
 
1311
 
 
1312
                DEBUG(10, ("entry_index = %d, num_entries = %d\n",
 
1313
                           ent->sam_entry_index, ent->num_sam_entries));
 
1314
 
 
1315
                if (ent->num_sam_entries == ent->sam_entry_index) {
 
1316
 
 
1317
                        while(ent && !get_sam_group_entries(ent)) {
 
1318
                                struct getent_state *next_ent;
 
1319
 
 
1320
                                DEBUG(10, ("freeing state info for domain %s\n",
 
1321
                                           ent->domain_name));
 
1322
 
 
1323
                                /* Free state information for this domain */
 
1324
 
 
1325
                                SAFE_FREE(ent->sam_entries);
 
1326
 
 
1327
                                next_ent = ent->next;
 
1328
                                DLIST_REMOVE(state->getgrent_state, ent);
 
1329
 
 
1330
                                SAFE_FREE(ent);
 
1331
                                ent = next_ent;
 
1332
                        }
 
1333
 
 
1334
                        /* No more domains */
 
1335
 
 
1336
                        if (!ent)
 
1337
                                break;
 
1338
                }
 
1339
 
 
1340
                name_list = (struct acct_info *)ent->sam_entries;
 
1341
 
 
1342
                if (!(domain = find_domain_from_name(ent->domain_name))) {
 
1343
                        DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
 
1344
                                  ent->domain_name));
 
1345
                        result = False;
 
1346
                        goto done;
 
1347
                }
 
1348
 
 
1349
                /* Lookup group info */
 
1350
 
 
1351
                sid_copy(&group_sid, &domain->sid);
 
1352
                sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
 
1353
 
 
1354
                if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config
 
1355
                                                      ? domain->name : "",
 
1356
                                                      &group_sid, &group_gid)))
 
1357
                {
 
1358
                        union unid_t id;
 
1359
                        enum lsa_SidType type;
 
1360
 
 
1361
                        DEBUG(10, ("SID %s not in idmap\n",
 
1362
                                   sid_string_dbg(&group_sid)));
 
1363
 
 
1364
                        if (!pdb_sid_to_id(&group_sid, &id, &type)) {
 
1365
                                DEBUG(1,("could not look up gid for group %s\n",
 
1366
                                         name_list[ent->sam_entry_index].acct_name));
 
1367
                                ent->sam_entry_index++;
 
1368
                                goto tryagain;
 
1369
                        }
 
1370
 
 
1371
                        if ((type != SID_NAME_DOM_GRP) &&
 
1372
                            (type != SID_NAME_ALIAS) &&
 
1373
                            (type != SID_NAME_WKN_GRP)) {
 
1374
                                DEBUG(1, ("Group %s is a %s, not a group\n",
 
1375
                                          sid_type_lookup(type),
 
1376
                                          name_list[ent->sam_entry_index].acct_name));
 
1377
                                ent->sam_entry_index++;
 
1378
                                goto tryagain;
 
1379
                        }
 
1380
                        group_gid = id.gid;
 
1381
                }
 
1382
 
 
1383
                DEBUG(10, ("got gid %lu for group %lu\n",
 
1384
                           (unsigned long)group_gid,
 
1385
                           (unsigned long)name_list[ent->sam_entry_index].rid));
 
1386
 
 
1387
                /* Fill in group entry */
 
1388
 
 
1389
                fill_domain_username(domain_group_name, ent->domain_name,
 
1390
                         name_list[ent->sam_entry_index].acct_name, True);
 
1391
 
 
1392
                result = fill_grent(state->mem_ctx, &group_list[group_list_ndx],
 
1393
                                    ent->domain_name,
 
1394
                                    name_list[ent->sam_entry_index].acct_name,
 
1395
                                    group_gid);
 
1396
 
 
1397
                /* Fill in group membership entry */
 
1398
 
 
1399
                if (result) {
 
1400
                        size_t num_gr_mem = 0;
 
1401
                        DOM_SID member_sid;
 
1402
                        group_list[group_list_ndx].num_gr_mem = 0;
 
1403
                        gr_mem = NULL;
 
1404
                        gr_mem_len = 0;
 
1405
 
 
1406
                        /* Get group membership */
 
1407
                        if (state->request.cmd == WINBINDD_GETGRLST) {
 
1408
                                result = True;
 
1409
                        } else {
 
1410
                                sid_copy(&member_sid, &domain->sid);
 
1411
                                sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
 
1412
                                result = fill_grent_mem(
 
1413
                                        domain,
 
1414
                                        NULL,
 
1415
                                        &member_sid,
 
1416
                                        SID_NAME_DOM_GRP,
 
1417
                                        &num_gr_mem,
 
1418
                                        &gr_mem, &gr_mem_len);
 
1419
 
 
1420
                                group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
 
1421
                        }
 
1422
                }
 
1423
 
 
1424
                if (result) {
 
1425
                        /* Append to group membership list */
 
1426
                        gr_mem_list = (char *)SMB_REALLOC(
 
1427
                                gr_mem_list, gr_mem_list_len + gr_mem_len);
 
1428
 
 
1429
                        if (!gr_mem_list &&
 
1430
                            (group_list[group_list_ndx].num_gr_mem != 0)) {
 
1431
                                DEBUG(0, ("out of memory\n"));
 
1432
                                gr_mem_list_len = 0;
 
1433
                                break;
 
1434
                        }
 
1435
 
 
1436
                        DEBUG(10, ("list_len = %d, mem_len = %u\n",
 
1437
                                   gr_mem_list_len, (unsigned int)gr_mem_len));
 
1438
 
 
1439
                        memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
 
1440
                               gr_mem_len);
 
1441
 
 
1442
                        SAFE_FREE(gr_mem);
 
1443
 
 
1444
                        group_list[group_list_ndx].gr_mem_ofs =
 
1445
                                gr_mem_list_len;
 
1446
 
 
1447
                        gr_mem_list_len += gr_mem_len;
 
1448
                }
 
1449
 
 
1450
                ent->sam_entry_index++;
 
1451
 
 
1452
                /* Add group to return list */
 
1453
 
 
1454
                if (result) {
 
1455
 
 
1456
                        DEBUG(10, ("adding group num_entries = %d\n",
 
1457
                                   state->response.data.num_entries));
 
1458
 
 
1459
                        group_list_ndx++;
 
1460
                        state->response.data.num_entries++;
 
1461
 
 
1462
                        state->response.length +=
 
1463
                                sizeof(struct winbindd_gr);
 
1464
 
 
1465
                } else {
 
1466
                        DEBUG(0, ("could not lookup domain group %s\n",
 
1467
                                  domain_group_name));
 
1468
                }
 
1469
        }
 
1470
 
 
1471
        /* Copy the list of group memberships to the end of the extra data */
 
1472
 
 
1473
        if (group_list_ndx == 0)
 
1474
                goto done;
 
1475
 
 
1476
        state->response.extra_data.data = SMB_REALLOC(
 
1477
                state->response.extra_data.data,
 
1478
                group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
 
1479
 
 
1480
        if (!state->response.extra_data.data) {
 
1481
                DEBUG(0, ("out of memory\n"));
 
1482
                group_list_ndx = 0;
 
1483
                SAFE_FREE(gr_mem_list);
 
1484
                request_error(state);
 
1485
                return;
 
1486
        }
 
1487
 
 
1488
        memcpy(&((char *)state->response.extra_data.data)
 
1489
               [group_list_ndx * sizeof(struct winbindd_gr)],
 
1490
               gr_mem_list, gr_mem_list_len);
 
1491
 
 
1492
        state->response.length += gr_mem_list_len;
 
1493
 
 
1494
        DEBUG(10, ("returning %d groups, length = %d\n",
 
1495
                   group_list_ndx, gr_mem_list_len));
 
1496
 
 
1497
        /* Out of domains */
 
1498
 
 
1499
 done:
 
1500
 
 
1501
        SAFE_FREE(gr_mem_list);
 
1502
 
 
1503
        if (group_list_ndx > 0)
 
1504
                request_ok(state);
 
1505
        else
 
1506
                request_error(state);
 
1507
}
 
1508
 
 
1509
/* List domain groups without mapping to unix ids */
 
1510
void winbindd_list_groups(struct winbindd_cli_state *state)
 
1511
{
 
1512
        winbindd_list_ent(state, LIST_GROUPS);
 
1513
}
 
1514
 
 
1515
/* Get user supplementary groups.  This is much quicker than trying to
 
1516
   invert the groups database.  We merge the groups from the gids and
 
1517
   other_sids info3 fields as trusted domain, universal group
 
1518
   memberships, and nested groups (win2k native mode only) are not
 
1519
   returned by the getgroups RPC call but are present in the info3. */
 
1520
 
 
1521
struct getgroups_state {
 
1522
        struct winbindd_cli_state *state;
 
1523
        struct winbindd_domain *domain;
 
1524
        char *domname;
 
1525
        char *username;
 
1526
        DOM_SID user_sid;
 
1527
 
 
1528
        const DOM_SID *token_sids;
 
1529
        size_t i, num_token_sids;
 
1530
 
 
1531
        gid_t *token_gids;
 
1532
        size_t num_token_gids;
 
1533
};
 
1534
 
 
1535
static void getgroups_usersid_recv(void *private_data, bool success,
 
1536
                                   const DOM_SID *sid, enum lsa_SidType type);
 
1537
static void getgroups_tokensids_recv(void *private_data, bool success,
 
1538
                                     DOM_SID *token_sids, size_t num_token_sids);
 
1539
static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
 
1540
 
 
1541
void winbindd_getgroups(struct winbindd_cli_state *state)
 
1542
{
 
1543
        struct getgroups_state *s;
 
1544
        char *real_name = NULL;
 
1545
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
1546
 
 
1547
        /* Ensure null termination */
 
1548
        state->request.data.username
 
1549
                [sizeof(state->request.data.username)-1]='\0';
 
1550
 
 
1551
        DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
 
1552
                  state->request.data.username));
 
1553
 
 
1554
        /* Parse domain and username */
 
1555
 
 
1556
        s = TALLOC_P(state->mem_ctx, struct getgroups_state);
 
1557
        if (s == NULL) {
 
1558
                DEBUG(0, ("talloc failed\n"));
 
1559
                request_error(state);
 
1560
                return;
 
1561
        }
 
1562
 
 
1563
        s->state = state;
 
1564
 
 
1565
        nt_status = normalize_name_unmap(state->mem_ctx,
 
1566
                                         state->request.data.username,
 
1567
                                         &real_name);
 
1568
 
 
1569
        /* Reset the real_name pointer if we didn't do anything
 
1570
           productive in the above call */
 
1571
        if (!NT_STATUS_IS_OK(nt_status) &&
 
1572
            !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
 
1573
        {
 
1574
                real_name = state->request.data.username;
 
1575
        }
 
1576
 
 
1577
        if (!parse_domain_user_talloc(state->mem_ctx, real_name,
 
1578
                                      &s->domname, &s->username)) {
 
1579
                DEBUG(5, ("Could not parse domain user: %s\n",
 
1580
                          real_name));
 
1581
 
 
1582
                /* error out if we do not have nested group support */
 
1583
 
 
1584
                if ( !lp_winbind_nested_groups() ) {
 
1585
                        request_error(state);
 
1586
                        return;
 
1587
                }
 
1588
 
 
1589
                s->domname = talloc_strdup(state->mem_ctx,
 
1590
                                           get_global_sam_name());
 
1591
                s->username = talloc_strdup(state->mem_ctx,
 
1592
                                            state->request.data.username);
 
1593
        }
 
1594
 
 
1595
        /* Get info for the domain (either by short domain name or
 
1596
           DNS name in the case of a UPN) */
 
1597
 
 
1598
        s->domain = find_domain_from_name_noinit(s->domname);
 
1599
        if (!s->domain) {
 
1600
                char *p = strchr(s->username, '@');
 
1601
 
 
1602
                if (p) {
 
1603
                        s->domain = find_domain_from_name_noinit(p+1);
 
1604
                }
 
1605
 
 
1606
        }
 
1607
 
 
1608
        if (s->domain == NULL) {
 
1609
                DEBUG(7, ("could not find domain entry for domain %s\n",
 
1610
                          s->domname));
 
1611
                request_error(state);
 
1612
                return;
 
1613
        }
 
1614
 
 
1615
        if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
 
1616
                DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
 
1617
                         "getgroups() for %s\\%s.\n", s->domname,
 
1618
                         s->username));
 
1619
                request_error(state);
 
1620
                return;
 
1621
        }
 
1622
 
 
1623
        /* Get rid and name type from name.  The following costs 1 packet */
 
1624
 
 
1625
        winbindd_lookupname_async(state->mem_ctx,
 
1626
                                  s->domname, s->username,
 
1627
                                  getgroups_usersid_recv,
 
1628
                                  WINBINDD_GETGROUPS, s);
 
1629
}
 
1630
 
 
1631
static void getgroups_usersid_recv(void *private_data, bool success,
 
1632
                                   const DOM_SID *sid, enum lsa_SidType type)
 
1633
{
 
1634
        struct getgroups_state *s =
 
1635
                (struct getgroups_state *)private_data;
 
1636
 
 
1637
        if ((!success) ||
 
1638
            ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
 
1639
                request_error(s->state);
 
1640
                return;
 
1641
        }
 
1642
 
 
1643
        sid_copy(&s->user_sid, sid);
 
1644
 
 
1645
        winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
 
1646
                                getgroups_tokensids_recv, s);
 
1647
}
 
1648
 
 
1649
static void getgroups_tokensids_recv(void *private_data, bool success,
 
1650
                                     DOM_SID *token_sids, size_t num_token_sids)
 
1651
{
 
1652
        struct getgroups_state *s =
 
1653
                (struct getgroups_state *)private_data;
 
1654
 
 
1655
        /* We need at least the user sid and the primary group in the token,
 
1656
         * otherwise it's an error */
 
1657
 
 
1658
        if ((!success) || (num_token_sids < 2)) {
 
1659
                request_error(s->state);
 
1660
                return;
 
1661
        }
 
1662
 
 
1663
        s->token_sids = token_sids;
 
1664
        s->num_token_sids = num_token_sids;
 
1665
        s->i = 0;
 
1666
 
 
1667
        s->token_gids = NULL;
 
1668
        s->num_token_gids = 0;
 
1669
 
 
1670
        getgroups_sid2gid_recv(s, False, 0);
 
1671
}
 
1672
 
 
1673
static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
 
1674
{
 
1675
        struct getgroups_state *s =
 
1676
                (struct getgroups_state *)private_data;
 
1677
 
 
1678
        if (success) {
 
1679
                if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
 
1680
                                        &s->token_gids,
 
1681
                                        &s->num_token_gids)) {
 
1682
                        return;
 
1683
                }
 
1684
        }
 
1685
 
 
1686
        if (s->i < s->num_token_sids) {
 
1687
                const DOM_SID *sid = &s->token_sids[s->i];
 
1688
                s->i += 1;
 
1689
 
 
1690
                if (sid_equal(sid, &s->user_sid)) {
 
1691
                        getgroups_sid2gid_recv(s, False, 0);
 
1692
                        return;
 
1693
                }
 
1694
 
 
1695
                winbindd_sid2gid_async(s->state->mem_ctx, sid,
 
1696
                                       getgroups_sid2gid_recv, s);
 
1697
                return;
 
1698
        }
 
1699
 
 
1700
        s->state->response.data.num_entries = s->num_token_gids;
 
1701
        if (s->num_token_gids) {
 
1702
                /* s->token_gids are talloced */
 
1703
                s->state->response.extra_data.data =
 
1704
                        smb_xmemdup(s->token_gids,
 
1705
                                        s->num_token_gids * sizeof(gid_t));
 
1706
                s->state->response.length += s->num_token_gids * sizeof(gid_t);
 
1707
        }
 
1708
        request_ok(s->state);
 
1709
}
 
1710
 
 
1711
/* Get user supplementary sids. This is equivalent to the
 
1712
   winbindd_getgroups() function but it involves a SID->SIDs mapping
 
1713
   rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
 
1714
   idmap. This call is designed to be used with applications that need
 
1715
   to do ACL evaluation themselves. Note that the cached info3 data is
 
1716
   not used
 
1717
 
 
1718
   this function assumes that the SID that comes in is a user SID. If
 
1719
   you pass in another type of SID then you may get unpredictable
 
1720
   results.
 
1721
*/
 
1722
 
 
1723
static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
 
1724
                             size_t num_sids);
 
1725
 
 
1726
void winbindd_getusersids(struct winbindd_cli_state *state)
 
1727
{
 
1728
        DOM_SID *user_sid;
 
1729
 
 
1730
        /* Ensure null termination */
 
1731
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
1732
 
 
1733
        user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
 
1734
        if (user_sid == NULL) {
 
1735
                DEBUG(1, ("talloc failed\n"));
 
1736
                request_error(state);
 
1737
                return;
 
1738
        }
 
1739
 
 
1740
        if (!string_to_sid(user_sid, state->request.data.sid)) {
 
1741
                DEBUG(1, ("Could not get convert sid %s from string\n",
 
1742
                          state->request.data.sid));
 
1743
                request_error(state);
 
1744
                return;
 
1745
        }
 
1746
 
 
1747
        winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
 
1748
                                state);
 
1749
}
 
1750
 
 
1751
static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
 
1752
                             size_t num_sids)
 
1753
{
 
1754
        struct winbindd_cli_state *state =
 
1755
                (struct winbindd_cli_state *)private_data;
 
1756
        char *ret = NULL;
 
1757
        unsigned ofs, ret_size = 0;
 
1758
        size_t i;
 
1759
 
 
1760
        if (!success) {
 
1761
                request_error(state);
 
1762
                return;
 
1763
        }
 
1764
 
 
1765
        /* work out the response size */
 
1766
        for (i = 0; i < num_sids; i++) {
 
1767
                fstring s;
 
1768
                sid_to_fstring(s, &sids[i]);
 
1769
                ret_size += strlen(s) + 1;
 
1770
        }
 
1771
 
 
1772
        /* build the reply */
 
1773
        ret = (char *)SMB_MALLOC(ret_size);
 
1774
        if (!ret) {
 
1775
                DEBUG(0, ("malloc failed\n"));
 
1776
                request_error(state);
 
1777
                return;
 
1778
        }
 
1779
        ofs = 0;
 
1780
        for (i = 0; i < num_sids; i++) {
 
1781
                fstring s;
 
1782
                sid_to_fstring(s, &sids[i]);
 
1783
                safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
 
1784
                ofs += strlen(ret+ofs) + 1;
 
1785
        }
 
1786
 
 
1787
        /* Send data back to client */
 
1788
        state->response.data.num_entries = num_sids;
 
1789
        state->response.extra_data.data = ret;
 
1790
        state->response.length += ret_size;
 
1791
        request_ok(state);
 
1792
}
 
1793
 
 
1794
void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
 
1795
{
 
1796
        DOM_SID user_sid;
 
1797
        struct winbindd_domain *domain;
 
1798
 
 
1799
        /* Ensure null termination */
 
1800
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
1801
 
 
1802
        if (!string_to_sid(&user_sid, state->request.data.sid)) {
 
1803
                DEBUG(1, ("Could not get convert sid %s from string\n",
 
1804
                          state->request.data.sid));
 
1805
                request_error(state);
 
1806
                return;
 
1807
        }
 
1808
 
 
1809
        /* Get info for the domain */
 
1810
        if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
 
1811
                DEBUG(0,("could not find domain entry for sid %s\n",
 
1812
                         sid_string_dbg(&user_sid)));
 
1813
                request_error(state);
 
1814
                return;
 
1815
        }
 
1816
 
 
1817
        sendto_domain(state, domain);
 
1818
}
 
1819
 
 
1820
enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
 
1821
                                                    struct winbindd_cli_state *state)
 
1822
{
 
1823
        DOM_SID user_sid;
 
1824
        NTSTATUS status;
 
1825
 
 
1826
        char *sidstring;
 
1827
        ssize_t len;
 
1828
        DOM_SID *groups;
 
1829
        uint32 num_groups;
 
1830
 
 
1831
        /* Ensure null termination */
 
1832
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
1833
 
 
1834
        if (!string_to_sid(&user_sid, state->request.data.sid)) {
 
1835
                DEBUG(1, ("Could not get convert sid %s from string\n",
 
1836
                          state->request.data.sid));
 
1837
                return WINBINDD_ERROR;
 
1838
        }
 
1839
 
 
1840
        status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
 
1841
                                                    &user_sid, &num_groups,
 
1842
                                                    &groups);
 
1843
        if (!NT_STATUS_IS_OK(status))
 
1844
                return WINBINDD_ERROR;
 
1845
 
 
1846
        if (num_groups == 0) {
 
1847
                state->response.data.num_entries = 0;
 
1848
                state->response.extra_data.data = NULL;
 
1849
                return WINBINDD_OK;
 
1850
        }
 
1851
 
 
1852
        if (!print_sidlist(state->mem_ctx,
 
1853
                           groups, num_groups,
 
1854
                           &sidstring, &len)) {
 
1855
                DEBUG(0, ("talloc failed\n"));
 
1856
                return WINBINDD_ERROR;
 
1857
        }
 
1858
 
 
1859
        state->response.extra_data.data = SMB_STRDUP(sidstring);
 
1860
        if (!state->response.extra_data.data) {
 
1861
                return WINBINDD_ERROR;
 
1862
        }
 
1863
        state->response.length += len+1;
 
1864
        state->response.data.num_entries = num_groups;
 
1865
 
 
1866
        return WINBINDD_OK;
 
1867
}
 
1868
 
 
1869
void winbindd_getsidaliases(struct winbindd_cli_state *state)
 
1870
{
 
1871
        DOM_SID domain_sid;
 
1872
        struct winbindd_domain *domain;
 
1873
 
 
1874
        /* Ensure null termination */
 
1875
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
1876
 
 
1877
        if (!string_to_sid(&domain_sid, state->request.data.sid)) {
 
1878
                DEBUG(1, ("Could not get convert sid %s from string\n",
 
1879
                          state->request.data.sid));
 
1880
                request_error(state);
 
1881
                return;
 
1882
        }
 
1883
 
 
1884
        /* Get info for the domain */
 
1885
        if ((domain = find_domain_from_sid_noinit(&domain_sid)) == NULL) {
 
1886
                DEBUG(0,("could not find domain entry for sid %s\n",
 
1887
                         sid_string_dbg(&domain_sid)));
 
1888
                request_error(state);
 
1889
                return;
 
1890
        }
 
1891
 
 
1892
        sendto_domain(state, domain);
 
1893
}
 
1894
 
 
1895
enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
 
1896
                                                 struct winbindd_cli_state *state)
 
1897
{
 
1898
        DOM_SID *sids = NULL;
 
1899
        size_t num_sids = 0;
 
1900
        char *sidstr = NULL;
 
1901
        ssize_t len;
 
1902
        size_t i;
 
1903
        uint32 num_aliases;
 
1904
        uint32 *alias_rids;
 
1905
        NTSTATUS result;
 
1906
 
 
1907
        DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
 
1908
 
 
1909
        sidstr = state->request.extra_data.data;
 
1910
        if (sidstr == NULL) {
 
1911
                sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
 
1912
                if (!sidstr) {
 
1913
                        DEBUG(0, ("Out of memory\n"));
 
1914
                        return WINBINDD_ERROR;
 
1915
                }
 
1916
        }
 
1917
 
 
1918
        DEBUG(10, ("Sidlist: %s\n", sidstr));
 
1919
 
 
1920
        if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
 
1921
                DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
 
1922
                return WINBINDD_ERROR;
 
1923
        }
 
1924
 
 
1925
        num_aliases = 0;
 
1926
        alias_rids = NULL;
 
1927
 
 
1928
        result = domain->methods->lookup_useraliases(domain,
 
1929
                                                     state->mem_ctx,
 
1930
                                                     num_sids, sids,
 
1931
                                                     &num_aliases,
 
1932
                                                     &alias_rids);
 
1933
 
 
1934
        if (!NT_STATUS_IS_OK(result)) {
 
1935
                DEBUG(3, ("Could not lookup_useraliases: %s\n",
 
1936
                          nt_errstr(result)));
 
1937
                return WINBINDD_ERROR;
 
1938
        }
 
1939
 
 
1940
        num_sids = 0;
 
1941
        sids = NULL;
 
1942
        sidstr = NULL;
 
1943
 
 
1944
        DEBUG(10, ("Got %d aliases\n", num_aliases));
 
1945
 
 
1946
        for (i=0; i<num_aliases; i++) {
 
1947
                DOM_SID sid;
 
1948
                DEBUGADD(10, (" rid %d\n", alias_rids[i]));
 
1949
                sid_copy(&sid, &domain->sid);
 
1950
                sid_append_rid(&sid, alias_rids[i]);
 
1951
                result = add_sid_to_array(state->mem_ctx, &sid, &sids,
 
1952
                                          &num_sids);
 
1953
                if (!NT_STATUS_IS_OK(result)) {
 
1954
                        return WINBINDD_ERROR;
 
1955
                }
 
1956
        }
 
1957
 
 
1958
 
 
1959
        if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
 
1960
                DEBUG(0, ("Could not print_sidlist\n"));
 
1961
                state->response.extra_data.data = NULL;
 
1962
                return WINBINDD_ERROR;
 
1963
        }
 
1964
 
 
1965
        state->response.extra_data.data = NULL;
 
1966
 
 
1967
        if (sidstr) {
 
1968
                state->response.extra_data.data = SMB_STRDUP(sidstr);
 
1969
                if (!state->response.extra_data.data) {
 
1970
                        DEBUG(0, ("Out of memory\n"));
 
1971
                        return WINBINDD_ERROR;
 
1972
                }
 
1973
                DEBUG(10, ("aliases_list: %s\n",
 
1974
                           (char *)state->response.extra_data.data));
 
1975
                state->response.length += len+1;
 
1976
                state->response.data.num_entries = num_sids;
 
1977
        }
 
1978
 
 
1979
        return WINBINDD_OK;
 
1980
}
 
1981
 
 
1982