source: trunk-3.0/source/nsswitch/winbindd_group.c@ 101

Last change on this file since 101 was 39, checked in by Paul Smedley, 18 years ago

Upgrade source to 3.0.25a

File size: 41.1 KB
Line 
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 2 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, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26#include "includes.h"
27#include "winbindd.h"
28
29extern BOOL opt_nocache;
30
31#undef DBGC_CLASS
32#define DBGC_CLASS DBGC_WINBIND
33
34static void add_member(const char *domain, const char *user,
35 char **pp_members, size_t *p_num_members)
36{
37 fstring name;
38
39 fill_domain_username(name, domain, user, True);
40 safe_strcat(name, ",", sizeof(name)-1);
41 string_append(pp_members, name);
42 *p_num_members += 1;
43}
44
45/**********************************************************************
46 Add member users resulting from sid. Expand if it is a domain group.
47**********************************************************************/
48
49static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
50{
51 DOM_SID dom_sid;
52 uint32 rid;
53 struct winbindd_domain *domain;
54 size_t i;
55
56 char *domain_name = NULL;
57 char *name = NULL;
58 enum lsa_SidType type;
59
60 uint32 num_names;
61 DOM_SID *sid_mem;
62 char **names;
63 uint32 *types;
64
65 NTSTATUS result;
66
67 TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
68
69 if (mem_ctx == NULL) {
70 DEBUG(1, ("talloc_init failed\n"));
71 return;
72 }
73
74 sid_copy(&dom_sid, sid);
75 sid_split_rid(&dom_sid, &rid);
76
77 domain = find_lookup_domain_from_sid(sid);
78
79 if (domain == NULL) {
80 DEBUG(3, ("Could not find domain for sid %s\n",
81 sid_string_static(sid)));
82 goto done;
83 }
84
85 result = domain->methods->sid_to_name(domain, mem_ctx, sid,
86 &domain_name, &name, &type);
87
88 if (!NT_STATUS_IS_OK(result)) {
89 DEBUG(3, ("sid_to_name failed for sid %s\n",
90 sid_string_static(sid)));
91 goto done;
92 }
93
94 DEBUG(10, ("Found name %s, type %d\n", name, type));
95
96 if (type == SID_NAME_USER) {
97 add_member(domain_name, name, pp_members, p_num_members);
98 goto done;
99 }
100
101 if (type != SID_NAME_DOM_GRP) {
102 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
103 name));
104 goto done;
105 }
106
107 /* Expand the domain group, this must be done via the target domain */
108
109 domain = find_domain_from_sid(sid);
110
111 if (domain == NULL) {
112 DEBUG(3, ("Could not find domain from SID %s\n",
113 sid_string_static(sid)));
114 goto done;
115 }
116
117 result = domain->methods->lookup_groupmem(domain, mem_ctx,
118 sid, &num_names,
119 &sid_mem, &names,
120 &types);
121
122 if (!NT_STATUS_IS_OK(result)) {
123 DEBUG(10, ("Could not lookup group members for %s: %s\n",
124 name, nt_errstr(result)));
125 goto done;
126 }
127
128 for (i=0; i<num_names; i++) {
129 DEBUG(10, ("Adding group member SID %s\n",
130 sid_string_static(&sid_mem[i])));
131
132 if (types[i] != SID_NAME_USER) {
133 DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
134 "Ignoring.\n", names[i], name));
135 continue;
136 }
137
138 add_member(domain->name, names[i], pp_members, p_num_members);
139 }
140
141 done:
142 talloc_destroy(mem_ctx);
143 return;
144}
145
146static BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain,
147 DOM_SID *group_sid,
148 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
149{
150 DOM_SID *members;
151 size_t i, num_members;
152
153 *num_gr_mem = 0;
154 *gr_mem = NULL;
155 *gr_mem_len = 0;
156
157 if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
158 &num_members)))
159 return True;
160
161 for (i=0; i<num_members; i++) {
162 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
163 }
164
165 TALLOC_FREE(members);
166
167 if (*gr_mem != NULL) {
168 size_t len;
169
170 /* We have at least one member, strip off the last "," */
171 len = strlen(*gr_mem);
172 (*gr_mem)[len-1] = '\0';
173 *gr_mem_len = len;
174 }
175
176 return True;
177}
178
179/* Fill a grent structure from various other information */
180
181static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
182 const char *gr_name, gid_t unix_gid)
183{
184 fstring full_group_name;
185
186 fill_domain_username( full_group_name, dom_name, gr_name, True );
187
188 gr->gr_gid = unix_gid;
189
190 /* Group name and password */
191
192 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
193 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
194
195 return True;
196}
197
198/* Fill in the group membership field of a NT group given by group_sid */
199
200static BOOL fill_grent_mem(struct winbindd_domain *domain,
201 struct winbindd_cli_state *state,
202 DOM_SID *group_sid,
203 enum lsa_SidType group_name_type,
204 size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
205{
206 DOM_SID *sid_mem = NULL;
207 uint32 num_names = 0;
208 uint32 *name_types = NULL;
209 unsigned int buf_len = 0, buf_ndx = 0, i;
210 char **names = NULL, *buf = NULL;
211 BOOL result = False;
212 TALLOC_CTX *mem_ctx;
213 NTSTATUS status;
214 uint32 group_rid;
215 fstring sid_string;
216
217 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
218 return False;
219
220 /* Initialise group membership information */
221
222 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
223
224 /* Initialize with no members */
225 *num_gr_mem = 0;
226
227 /* HACK ALERT!! This whole routine does not cope with group members
228 * from more than one domain, ie aliases. Thus we have to work it out
229 * ourselves in a special routine. */
230
231 if (domain->internal) {
232 result = fill_passdb_alias_grmem(domain, group_sid,
233 num_gr_mem,
234 gr_mem, gr_mem_len);
235 goto done;
236 }
237
238 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
239 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
240 {
241 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
242 sid_to_string(sid_string, group_sid), domain->name,
243 group_name_type));
244 goto done;
245 }
246
247 /* OPTIMIZATION / HACK. */
248 /* If "enum users" is set to false, and the group being looked
249 up is the Domain Users SID: S-1-5-domain-513, then for the
250 list of members check if the querying user is in that group,
251 and if so only return that user as the gr_mem array.
252 We can change this to a different parameter than "enum users"
253 if neccessaey, or parameterize the group list we do this for. */
254
255 sid_peek_rid( group_sid, &group_rid );
256 if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
257 DOM_SID querying_user_sid;
258 DOM_SID *pquerying_user_sid = NULL;
259 uint32 num_groups = 0;
260 DOM_SID *user_sids = NULL;
261 BOOL u_in_group = False;
262
263 DEBUG(10,("fill_grent_mem: optimized lookup for sid %s domain %s\n",
264 sid_to_string(sid_string, group_sid), domain->name ));
265
266 if (state) {
267 uid_t ret_uid = (uid_t)-1;
268 if (sys_getpeereid(state->sock, &ret_uid)==0) {
269 /* We know who's asking - look up their SID if
270 it's one we've mapped before. */
271 status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
272 if (NT_STATUS_IS_OK(status)) {
273 pquerying_user_sid = &querying_user_sid;
274 DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
275 (unsigned int)ret_uid,
276 sid_to_string(sid_string, pquerying_user_sid) ));
277 }
278 }
279 }
280
281 /* Only look up if it was a winbindd user in this domain. */
282 if (pquerying_user_sid &&
283 (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
284
285 DEBUG(10,("fill_grent_mem: querying user = %s\n",
286 sid_to_string(sid_string, pquerying_user_sid) ));
287
288 status = domain->methods->lookup_usergroups(domain,
289 mem_ctx,
290 pquerying_user_sid,
291 &num_groups,
292 &user_sids);
293 if (!NT_STATUS_IS_OK(status)) {
294 DEBUG(1, ("fill_grent_mem: lookup_usergroups failed "
295 "for sid %s in domain %s (error: %s)\n",
296 sid_to_string(sid_string, pquerying_user_sid),
297 domain->name,
298 nt_errstr(status)));
299 goto done;
300 }
301
302 for (i = 0; i < num_groups; i++) {
303 if (sid_equal(group_sid, &user_sids[i])) {
304 /* User is in Domain Users, add their name
305 as the only group member. */
306 u_in_group = True;
307 break;
308 }
309 }
310 }
311
312 if (u_in_group) {
313 size_t len = 0;
314 char *domainname = NULL;
315 char *username = NULL;
316 fstring name;
317 enum lsa_SidType type;
318
319 DEBUG(10,("fill_grent_mem: sid %s in 'Domain Users' in domain %s\n",
320 sid_to_string(sid_string, pquerying_user_sid), domain->name ));
321
322 status = domain->methods->sid_to_name(domain, mem_ctx,
323 pquerying_user_sid,
324 &domainname,
325 &username,
326 &type);
327 if (!NT_STATUS_IS_OK(status)) {
328 DEBUG(1, ("could not lookup username for user "
329 "sid %s in domain %s (error: %s)\n",
330 sid_to_string(sid_string, pquerying_user_sid),
331 domain->name,
332 nt_errstr(status)));
333 goto done;
334 }
335 fill_domain_username(name, domain->name, username, True);
336 len = strlen(name);
337 buf_len = len + 1;
338 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
339 DEBUG(1, ("out of memory\n"));
340 goto done;
341 }
342 memcpy(buf, name, buf_len);
343
344 DEBUG(10,("fill_grent_mem: user %s in 'Domain Users' in domain %s\n",
345 name, domain->name ));
346
347 /* user is the only member */
348 *num_gr_mem = 1;
349 }
350
351 *gr_mem = buf;
352 *gr_mem_len = buf_len;
353
354 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
355 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
356 result = True;
357 goto done;
358 }
359
360 /* Lookup group members */
361 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
362 &sid_mem, &names, &name_types);
363 if (!NT_STATUS_IS_OK(status)) {
364 DEBUG(1, ("could not lookup membership for group sid %s in domain %s (error: %s)\n",
365 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
366 goto done;
367 }
368
369 DEBUG(10, ("looked up %d names\n", num_names));
370
371 if (DEBUGLEVEL >= 10) {
372 for (i = 0; i < num_names; i++)
373 DEBUG(10, ("\t%20s %s %d\n", names[i],
374 sid_string_static(&sid_mem[i]),
375 name_types[i]));
376 }
377
378 /* Add members to list */
379
380 again:
381
382 for (i = 0; i < num_names; i++) {
383 char *the_name;
384 fstring name;
385 int len;
386
387 the_name = names[i];
388
389 DEBUG(10, ("processing name %s\n", the_name));
390
391 /* FIXME: need to cope with groups within groups. These
392 occur in Universal groups on a Windows 2000 native mode
393 server. */
394
395 /* make sure to allow machine accounts */
396
397 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
398 DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i])));
399 continue;
400 }
401
402 /* Append domain name */
403
404 fill_domain_username(name, domain->name, the_name, True);
405
406 len = strlen(name);
407
408 /* Add to list or calculate buffer length */
409
410 if (!buf) {
411 buf_len += len + 1; /* List is comma separated */
412 (*num_gr_mem)++;
413 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
414 } else {
415 DEBUG(10, ("appending %s at ndx %d\n", name, buf_ndx));
416 safe_strcpy(&buf[buf_ndx], name, len);
417 buf_ndx += len;
418 buf[buf_ndx] = ',';
419 buf_ndx++;
420 }
421 }
422
423 /* Allocate buffer */
424
425 if (!buf && buf_len != 0) {
426 if (!(buf = (char *)SMB_MALLOC(buf_len))) {
427 DEBUG(1, ("out of memory\n"));
428 result = False;
429 goto done;
430 }
431 memset(buf, 0, buf_len);
432 goto again;
433 }
434
435 if (buf && buf_ndx > 0) {
436 buf[buf_ndx - 1] = '\0';
437 }
438
439 *gr_mem = buf;
440 *gr_mem_len = buf_len;
441
442 DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n", (unsigned int)*num_gr_mem,
443 (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
444 result = True;
445
446done:
447
448 talloc_destroy(mem_ctx);
449
450 DEBUG(10, ("fill_grent_mem returning %d\n", result));
451
452 return result;
453}
454
455/* Return a group structure from a group name */
456
457void winbindd_getgrnam(struct winbindd_cli_state *state)
458{
459 DOM_SID group_sid, tmp_sid;
460 uint32 grp_rid;
461 struct winbindd_domain *domain;
462 enum lsa_SidType name_type;
463 fstring name_domain, name_group;
464 char *tmp, *gr_mem;
465 size_t gr_mem_len;
466 size_t num_gr_mem;
467 gid_t gid;
468 union unid_t id;
469 NTSTATUS status;
470
471 /* Ensure null termination */
472 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
473
474 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
475 state->request.data.groupname));
476
477 /* Parse domain and groupname */
478
479 memset(name_group, 0, sizeof(fstring));
480
481 tmp = state->request.data.groupname;
482
483 name_domain[0] = '\0';
484 name_group[0] = '\0';
485
486 parse_domain_user(tmp, name_domain, name_group);
487
488 /* if no domain or our local domain and no local tdb group, default to
489 * our local domain for aliases */
490
491 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
492 fstrcpy(name_domain, get_global_sam_name());
493 }
494
495 /* Get info for the domain */
496
497 if ((domain = find_domain_from_name(name_domain)) == NULL) {
498 DEBUG(3, ("could not get domain sid for domain %s\n",
499 name_domain));
500 request_error(state);
501 return;
502 }
503 /* should we deal with users for our domain? */
504
505 if ( lp_winbind_trusted_domains_only() && domain->primary) {
506 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
507 "getgrnam() for %s\\%s.\n", name_domain, name_group));
508 request_error(state);
509 return;
510 }
511
512 /* Get rid and name type from name */
513
514 ws_name_replace( name_group, WB_REPLACE_CHAR );
515
516 if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
517 name_group, &group_sid, &name_type)) {
518 DEBUG(1, ("group %s in domain %s does not exist\n",
519 name_group, name_domain));
520 request_error(state);
521 return;
522 }
523
524 if ( !((name_type==SID_NAME_DOM_GRP) ||
525 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
526 ((name_type==SID_NAME_ALIAS) && domain->internal) ||
527 ((name_type==SID_NAME_WKN_GRP) && domain->internal)) )
528 {
529 DEBUG(1, ("name '%s' is not a local, domain or builtin "
530 "group: %d\n", name_group, name_type));
531 request_error(state);
532 return;
533 }
534
535 /* Make sure that the group SID is within the domain of the
536 original domain */
537
538 sid_copy( &tmp_sid, &group_sid );
539 sid_split_rid( &tmp_sid, &grp_rid );
540 if ( !sid_equal( &tmp_sid, &domain->sid ) ) {
541 DEBUG(3,("winbindd_getgrnam: group %s resolves to a SID in the wrong domain [%s]\n",
542 state->request.data.groupname, sid_string_static(&group_sid)));
543 request_error(state);
544 return;
545 }
546
547
548
549 /* Try to get the GID */
550
551 status = idmap_sid_to_gid(&group_sid, &gid);
552
553 if (NT_STATUS_IS_OK(status)) {
554 goto got_gid;
555 }
556
557 /* Maybe it's one of our aliases in passdb */
558
559 if (pdb_sid_to_id(&group_sid, &id, &name_type) &&
560 ((name_type == SID_NAME_ALIAS) ||
561 (name_type == SID_NAME_WKN_GRP))) {
562 gid = id.gid;
563 goto got_gid;
564 }
565
566 DEBUG(1, ("error converting unix gid to sid\n"));
567 request_error(state);
568 return;
569
570 got_gid:
571
572 if (!fill_grent(&state->response.data.gr, name_domain,
573 name_group, gid) ||
574 !fill_grent_mem(domain, state, &group_sid, name_type,
575 &num_gr_mem,
576 &gr_mem, &gr_mem_len)) {
577 request_error(state);
578 return;
579 }
580
581 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
582
583 /* Group membership lives at start of extra data */
584
585 state->response.data.gr.gr_mem_ofs = 0;
586
587 state->response.length += gr_mem_len;
588 state->response.extra_data.data = gr_mem;
589 request_ok(state);
590}
591
592static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid)
593{
594 struct winbindd_domain *domain;
595 enum lsa_SidType name_type;
596 char *dom_name;
597 char *group_name;
598 size_t gr_mem_len;
599 size_t num_gr_mem;
600 char *gr_mem;
601
602 /* Get name from sid */
603
604 if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
605 &group_name, &name_type)) {
606 DEBUG(1, ("could not lookup sid\n"));
607 request_error(state);
608 TALLOC_FREE(group_name);
609 TALLOC_FREE(dom_name);
610 return;
611 }
612
613 /* Fill in group structure */
614
615 domain = find_domain_from_sid_noinit(&group_sid);
616
617 if (!domain) {
618 DEBUG(1,("Can't find domain from sid\n"));
619 request_error(state);
620 TALLOC_FREE(group_name);
621 TALLOC_FREE(dom_name);
622 return;
623 }
624
625 if ( !((name_type==SID_NAME_DOM_GRP) ||
626 ((name_type==SID_NAME_ALIAS) && domain->primary) ||
627 ((name_type==SID_NAME_ALIAS) && domain->internal)) )
628 {
629 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
630 group_name, name_type));
631 request_error(state);
632 TALLOC_FREE(group_name);
633 TALLOC_FREE(dom_name);
634 return;
635 }
636
637 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
638 state->request.data.gid) ||
639 !fill_grent_mem(domain, state, &group_sid, name_type,
640 &num_gr_mem,
641 &gr_mem, &gr_mem_len)) {
642 request_error(state);
643 TALLOC_FREE(group_name);
644 TALLOC_FREE(dom_name);
645 return;
646 }
647
648 state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
649
650 /* Group membership lives at start of extra data */
651
652 state->response.data.gr.gr_mem_ofs = 0;
653
654 state->response.length += gr_mem_len;
655 state->response.extra_data.data = gr_mem;
656
657 TALLOC_FREE(group_name);
658 TALLOC_FREE(dom_name);
659
660 request_ok(state);
661}
662
663static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
664{
665 struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
666 enum lsa_SidType name_type;
667 DOM_SID group_sid;
668
669 if (success) {
670 DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
671 (unsigned long)(state->request.data.gid), sid));
672
673 string_to_sid(&group_sid, sid);
674 getgrgid_got_sid(state, group_sid);
675 return;
676 }
677
678 /* Ok, this might be "ours", i.e. an alias */
679 if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
680 lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
681 (name_type == SID_NAME_ALIAS)) {
682 /* Hey, got an alias */
683 DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
684 (unsigned long)(state->request.data.gid), sid));
685 getgrgid_got_sid(state, group_sid);
686 return;
687 }
688
689 DEBUG(1, ("could not convert gid %lu to sid\n",
690 (unsigned long)state->request.data.gid));
691 request_error(state);
692}
693
694/* Return a group structure from a gid number */
695void winbindd_getgrgid(struct winbindd_cli_state *state)
696{
697 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
698 (unsigned long)state->request.data.gid));
699
700 /* always use the async interface */
701 winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
702}
703
704/*
705 * set/get/endgrent functions
706 */
707
708/* "Rewind" file pointer for group database enumeration */
709
710static BOOL winbindd_setgrent_internal(struct winbindd_cli_state *state)
711{
712 struct winbindd_domain *domain;
713
714 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
715
716 /* Check user has enabled this */
717
718 if (!lp_winbind_enum_groups()) {
719 return False;
720 }
721
722 /* Free old static data if it exists */
723
724 if (state->getgrent_state != NULL) {
725 free_getent_state(state->getgrent_state);
726 state->getgrent_state = NULL;
727 }
728
729 /* Create sam pipes for each domain we know about */
730
731 for (domain = domain_list(); domain != NULL; domain = domain->next) {
732 struct getent_state *domain_state;
733
734 /* Create a state record for this domain */
735
736 /* don't add our domaina if we are a PDC or if we
737 are a member of a Samba domain */
738
739 if ( lp_winbind_trusted_domains_only() && domain->primary )
740 {
741 continue;
742 }
743
744
745 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
746 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
747 return False;
748 }
749
750 ZERO_STRUCTP(domain_state);
751
752 fstrcpy(domain_state->domain_name, domain->name);
753
754 /* Add to list of open domains */
755
756 DLIST_ADD(state->getgrent_state, domain_state);
757 }
758
759 state->getgrent_initialized = True;
760 return True;
761}
762
763void winbindd_setgrent(struct winbindd_cli_state *state)
764{
765 if (winbindd_setgrent_internal(state)) {
766 request_ok(state);
767 } else {
768 request_error(state);
769 }
770}
771
772/* Close file pointer to ntdom group database */
773
774void winbindd_endgrent(struct winbindd_cli_state *state)
775{
776 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
777
778 free_getent_state(state->getgrent_state);
779 state->getgrent_initialized = False;
780 state->getgrent_state = NULL;
781 request_ok(state);
782}
783
784/* Get the list of domain groups and domain aliases for a domain. We fill in
785 the sam_entries and num_sam_entries fields with domain group information.
786 The dispinfo_ndx field is incremented to the index of the next group to
787 fetch. Return True if some groups were returned, False otherwise. */
788
789static BOOL get_sam_group_entries(struct getent_state *ent)
790{
791 NTSTATUS status;
792 uint32 num_entries;
793 struct acct_info *name_list = NULL;
794 TALLOC_CTX *mem_ctx;
795 BOOL result = False;
796 struct acct_info *sam_grp_entries = NULL;
797 struct winbindd_domain *domain;
798
799 if (ent->got_sam_entries)
800 return False;
801
802 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
803 ent->domain_name))) {
804 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
805 return False;
806 }
807
808 /* Free any existing group info */
809
810 SAFE_FREE(ent->sam_entries);
811 ent->num_sam_entries = 0;
812 ent->got_sam_entries = True;
813
814 /* Enumerate domain groups */
815
816 num_entries = 0;
817
818 if (!(domain = find_domain_from_name(ent->domain_name))) {
819 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
820 goto done;
821 }
822
823 /* always get the domain global groups */
824
825 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
826
827 if (!NT_STATUS_IS_OK(status)) {
828 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
829 result = False;
830 goto done;
831 }
832
833 /* Copy entries into return buffer */
834
835 if (num_entries) {
836 if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) {
837 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
838 num_entries));
839 result = False;
840 goto done;
841 }
842 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
843 }
844
845 ent->num_sam_entries = num_entries;
846
847 /* get the domain local groups if we are a member of a native win2k domain
848 and are not using LDAP to get the groups */
849
850 if ( ( lp_security() != SEC_ADS && domain->native_mode
851 && domain->primary) || domain->internal )
852 {
853 DEBUG(4,("get_sam_group_entries: %s domain; enumerating local groups as well\n",
854 domain->native_mode ? "Native Mode 2k":"BUILTIN or local"));
855
856 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
857
858 if ( !NT_STATUS_IS_OK(status) ) {
859 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
860 num_entries = 0;
861 }
862 else
863 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
864
865 /* Copy entries into return buffer */
866
867 if ( num_entries ) {
868 if ( !(name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) )
869 {
870 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
871 num_entries));
872 result = False;
873 goto done;
874 }
875
876 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
877 num_entries * sizeof(struct acct_info) );
878 }
879
880 ent->num_sam_entries += num_entries;
881 }
882
883
884 /* Fill in remaining fields */
885
886 ent->sam_entries = name_list;
887 ent->sam_entry_index = 0;
888
889 result = (ent->num_sam_entries > 0);
890
891 done:
892 talloc_destroy(mem_ctx);
893
894 return result;
895}
896
897/* Fetch next group entry from ntdom database */
898
899#define MAX_GETGRENT_GROUPS 500
900
901void winbindd_getgrent(struct winbindd_cli_state *state)
902{
903 struct getent_state *ent;
904 struct winbindd_gr *group_list = NULL;
905 int num_groups, group_list_ndx, gr_mem_list_len = 0;
906 char *gr_mem_list = NULL;
907
908 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
909
910 /* Check user has enabled this */
911
912 if (!lp_winbind_enum_groups()) {
913 request_error(state);
914 return;
915 }
916
917 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
918
919 if (num_groups == 0) {
920 request_error(state);
921 return;
922 }
923
924 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) {
925 request_error(state);
926 return;
927 }
928
929 memset(state->response.extra_data.data, '\0',
930 num_groups * sizeof(struct winbindd_gr) );
931
932 state->response.data.num_entries = 0;
933
934 group_list = (struct winbindd_gr *)state->response.extra_data.data;
935
936 if (!state->getgrent_initialized)
937 winbindd_setgrent_internal(state);
938
939 if (!(ent = state->getgrent_state)) {
940 request_error(state);
941 return;
942 }
943
944 /* Start sending back groups */
945
946 for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
947 struct acct_info *name_list = NULL;
948 fstring domain_group_name;
949 uint32 result;
950 gid_t group_gid;
951 size_t gr_mem_len;
952 char *gr_mem;
953 DOM_SID group_sid;
954 struct winbindd_domain *domain;
955
956 /* Do we need to fetch another chunk of groups? */
957
958 tryagain:
959
960 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
961 ent->sam_entry_index, ent->num_sam_entries));
962
963 if (ent->num_sam_entries == ent->sam_entry_index) {
964
965 while(ent && !get_sam_group_entries(ent)) {
966 struct getent_state *next_ent;
967
968 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
969
970 /* Free state information for this domain */
971
972 SAFE_FREE(ent->sam_entries);
973
974 next_ent = ent->next;
975 DLIST_REMOVE(state->getgrent_state, ent);
976
977 SAFE_FREE(ent);
978 ent = next_ent;
979 }
980
981 /* No more domains */
982
983 if (!ent)
984 break;
985 }
986
987 name_list = (struct acct_info *)ent->sam_entries;
988
989 if (!(domain =
990 find_domain_from_name(ent->domain_name))) {
991 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
992 result = False;
993 goto done;
994 }
995
996 /* Lookup group info */
997
998 sid_copy(&group_sid, &domain->sid);
999 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
1000
1001 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
1002 union unid_t id;
1003 enum lsa_SidType type;
1004
1005 DEBUG(10, ("SID %s not in idmap\n",
1006 sid_string_static(&group_sid)));
1007
1008 if (!pdb_sid_to_id(&group_sid, &id, &type)) {
1009 DEBUG(1, ("could not look up gid for group "
1010 "%s\n",
1011 name_list[ent->sam_entry_index].acct_name));
1012 ent->sam_entry_index++;
1013 goto tryagain;
1014 }
1015
1016 if ((type != SID_NAME_DOM_GRP) &&
1017 (type != SID_NAME_ALIAS) &&
1018 (type != SID_NAME_WKN_GRP)) {
1019 DEBUG(1, ("Group %s is a %s, not a group\n",
1020 sid_type_lookup(type),
1021 name_list[ent->sam_entry_index].acct_name));
1022 ent->sam_entry_index++;
1023 goto tryagain;
1024 }
1025 group_gid = id.gid;
1026 }
1027
1028 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
1029 (unsigned long)name_list[ent->sam_entry_index].rid));
1030
1031 /* Fill in group entry */
1032
1033 fill_domain_username(domain_group_name, ent->domain_name,
1034 name_list[ent->sam_entry_index].acct_name, True);
1035
1036 result = fill_grent(&group_list[group_list_ndx],
1037 ent->domain_name,
1038 name_list[ent->sam_entry_index].acct_name,
1039 group_gid);
1040
1041 /* Fill in group membership entry */
1042
1043 if (result) {
1044 size_t num_gr_mem = 0;
1045 DOM_SID member_sid;
1046 group_list[group_list_ndx].num_gr_mem = 0;
1047 gr_mem = NULL;
1048 gr_mem_len = 0;
1049
1050 /* Get group membership */
1051 if (state->request.cmd == WINBINDD_GETGRLST) {
1052 result = True;
1053 } else {
1054 sid_copy(&member_sid, &domain->sid);
1055 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
1056 result = fill_grent_mem(
1057 domain,
1058 NULL,
1059 &member_sid,
1060 SID_NAME_DOM_GRP,
1061 &num_gr_mem,
1062 &gr_mem, &gr_mem_len);
1063
1064 group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
1065 }
1066 }
1067
1068 if (result) {
1069 /* Append to group membership list */
1070 gr_mem_list = (char *)SMB_REALLOC(
1071 gr_mem_list, gr_mem_list_len + gr_mem_len);
1072
1073 if (!gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
1074 DEBUG(0, ("out of memory\n"));
1075 gr_mem_list_len = 0;
1076 break;
1077 }
1078
1079 DEBUG(10, ("list_len = %d, mem_len = %u\n",
1080 gr_mem_list_len, (unsigned int)gr_mem_len));
1081
1082 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
1083 gr_mem_len);
1084
1085 SAFE_FREE(gr_mem);
1086
1087 group_list[group_list_ndx].gr_mem_ofs =
1088 gr_mem_list_len;
1089
1090 gr_mem_list_len += gr_mem_len;
1091 }
1092
1093 ent->sam_entry_index++;
1094
1095 /* Add group to return list */
1096
1097 if (result) {
1098
1099 DEBUG(10, ("adding group num_entries = %d\n",
1100 state->response.data.num_entries));
1101
1102 group_list_ndx++;
1103 state->response.data.num_entries++;
1104
1105 state->response.length +=
1106 sizeof(struct winbindd_gr);
1107
1108 } else {
1109 DEBUG(0, ("could not lookup domain group %s\n",
1110 domain_group_name));
1111 }
1112 }
1113
1114 /* Copy the list of group memberships to the end of the extra data */
1115
1116 if (group_list_ndx == 0)
1117 goto done;
1118
1119 state->response.extra_data.data = SMB_REALLOC(
1120 state->response.extra_data.data,
1121 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
1122
1123 if (!state->response.extra_data.data) {
1124 DEBUG(0, ("out of memory\n"));
1125 group_list_ndx = 0;
1126 SAFE_FREE(gr_mem_list);
1127 request_error(state);
1128 return;
1129 }
1130
1131 memcpy(&((char *)state->response.extra_data.data)
1132 [group_list_ndx * sizeof(struct winbindd_gr)],
1133 gr_mem_list, gr_mem_list_len);
1134
1135 state->response.length += gr_mem_list_len;
1136
1137 DEBUG(10, ("returning %d groups, length = %d\n",
1138 group_list_ndx, gr_mem_list_len));
1139
1140 /* Out of domains */
1141
1142 done:
1143
1144 SAFE_FREE(gr_mem_list);
1145
1146 if (group_list_ndx > 0)
1147 request_ok(state);
1148 else
1149 request_error(state);
1150}
1151
1152/* List domain groups without mapping to unix ids */
1153
1154void winbindd_list_groups(struct winbindd_cli_state *state)
1155{
1156 uint32 total_entries = 0;
1157 struct winbindd_domain *domain;
1158 const char *which_domain;
1159 char *extra_data = NULL;
1160 unsigned int extra_data_len = 0, i;
1161
1162 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
1163
1164 /* Ensure null termination */
1165 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
1166 which_domain = state->request.domain_name;
1167
1168 /* Enumerate over trusted domains */
1169
1170 for (domain = domain_list(); domain; domain = domain->next) {
1171 struct getent_state groups;
1172
1173 /* if we have a domain name restricting the request and this
1174 one in the list doesn't match, then just bypass the remainder
1175 of the loop */
1176
1177 if ( *which_domain && !strequal(which_domain, domain->name) )
1178 continue;
1179
1180 ZERO_STRUCT(groups);
1181
1182 /* Get list of sam groups */
1183
1184 fstrcpy(groups.domain_name, domain->name);
1185
1186 get_sam_group_entries(&groups);
1187
1188 if (groups.num_sam_entries == 0) {
1189 /* this domain is empty or in an error state */
1190 continue;
1191 }
1192
1193 /* keep track the of the total number of groups seen so
1194 far over all domains */
1195 total_entries += groups.num_sam_entries;
1196
1197 /* Allocate some memory for extra data. Note that we limit
1198 account names to sizeof(fstring) = 128 characters. */
1199 extra_data = (char *)SMB_REALLOC(
1200 extra_data, sizeof(fstring) * total_entries);
1201
1202 if (!extra_data) {
1203 DEBUG(0,("failed to enlarge buffer!\n"));
1204 request_error(state);
1205 return;
1206 }
1207
1208 /* Pack group list into extra data fields */
1209 for (i = 0; i < groups.num_sam_entries; i++) {
1210 char *group_name = ((struct acct_info *)
1211 groups.sam_entries)[i].acct_name;
1212 fstring name;
1213
1214 fill_domain_username(name, domain->name, group_name, True);
1215 /* Append to extra data */
1216 memcpy(&extra_data[extra_data_len], name,
1217 strlen(name));
1218 extra_data_len += strlen(name);
1219 extra_data[extra_data_len++] = ',';
1220 }
1221
1222 SAFE_FREE(groups.sam_entries);
1223 }
1224
1225 /* Assign extra_data fields in response structure */
1226 if (extra_data) {
1227 extra_data[extra_data_len - 1] = '\0';
1228 state->response.extra_data.data = extra_data;
1229 state->response.length += extra_data_len;
1230 }
1231
1232 /* No domains may have responded but that's still OK so don't
1233 return an error. */
1234
1235 request_ok(state);
1236}
1237
1238/* Get user supplementary groups. This is much quicker than trying to
1239 invert the groups database. We merge the groups from the gids and
1240 other_sids info3 fields as trusted domain, universal group
1241 memberships, and nested groups (win2k native mode only) are not
1242 returned by the getgroups RPC call but are present in the info3. */
1243
1244struct getgroups_state {
1245 struct winbindd_cli_state *state;
1246 struct winbindd_domain *domain;
1247 char *domname;
1248 char *username;
1249 DOM_SID user_sid;
1250
1251 const DOM_SID *token_sids;
1252 size_t i, num_token_sids;
1253
1254 gid_t *token_gids;
1255 size_t num_token_gids;
1256};
1257
1258static void getgroups_usersid_recv(void *private_data, BOOL success,
1259 const DOM_SID *sid, enum lsa_SidType type);
1260static void getgroups_tokensids_recv(void *private_data, BOOL success,
1261 DOM_SID *token_sids, size_t num_token_sids);
1262static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
1263
1264void winbindd_getgroups(struct winbindd_cli_state *state)
1265{
1266 struct getgroups_state *s;
1267
1268 /* Ensure null termination */
1269 state->request.data.username
1270 [sizeof(state->request.data.username)-1]='\0';
1271
1272 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
1273 state->request.data.username));
1274
1275 /* Parse domain and username */
1276
1277 s = TALLOC_P(state->mem_ctx, struct getgroups_state);
1278 if (s == NULL) {
1279 DEBUG(0, ("talloc failed\n"));
1280 request_error(state);
1281 return;
1282 }
1283
1284 s->state = state;
1285
1286 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
1287
1288 if (!parse_domain_user_talloc(state->mem_ctx,
1289 state->request.data.username,
1290 &s->domname, &s->username)) {
1291 DEBUG(5, ("Could not parse domain user: %s\n",
1292 state->request.data.username));
1293
1294 /* error out if we do not have nested group support */
1295
1296 if ( !lp_winbind_nested_groups() ) {
1297 request_error(state);
1298 return;
1299 }
1300
1301 s->domname = talloc_strdup( state->mem_ctx, get_global_sam_name() );
1302 s->username = talloc_strdup( state->mem_ctx, state->request.data.username );
1303 }
1304
1305 /* Get info for the domain */
1306
1307 s->domain = find_domain_from_name_noinit(s->domname);
1308
1309 if (s->domain == NULL) {
1310 DEBUG(7, ("could not find domain entry for domain %s\n",
1311 s->domname));
1312 request_error(state);
1313 return;
1314 }
1315
1316 if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
1317 DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
1318 "getgroups() for %s\\%s.\n", s->domname,
1319 s->username));
1320 request_error(state);
1321 return;
1322 }
1323
1324 /* Get rid and name type from name. The following costs 1 packet */
1325
1326 winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
1327 getgroups_usersid_recv, s);
1328}
1329
1330static void getgroups_usersid_recv(void *private_data, BOOL success,
1331 const DOM_SID *sid, enum lsa_SidType type)
1332{
1333 struct getgroups_state *s =
1334 (struct getgroups_state *)private_data;
1335
1336 if ((!success) ||
1337 ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
1338 request_error(s->state);
1339 return;
1340 }
1341
1342 sid_copy(&s->user_sid, sid);
1343
1344 winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
1345 getgroups_tokensids_recv, s);
1346}
1347
1348static void getgroups_tokensids_recv(void *private_data, BOOL success,
1349 DOM_SID *token_sids, size_t num_token_sids)
1350{
1351 struct getgroups_state *s =
1352 (struct getgroups_state *)private_data;
1353
1354 /* We need at least the user sid and the primary group in the token,
1355 * otherwise it's an error */
1356
1357 if ((!success) || (num_token_sids < 2)) {
1358 request_error(s->state);
1359 return;
1360 }
1361
1362 s->token_sids = token_sids;
1363 s->num_token_sids = num_token_sids;
1364 s->i = 0;
1365
1366 s->token_gids = NULL;
1367 s->num_token_gids = 0;
1368
1369 getgroups_sid2gid_recv(s, False, 0);
1370}
1371
1372static void getgroups_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
1373{
1374 struct getgroups_state *s =
1375 (struct getgroups_state *)private_data;
1376
1377 if (success) {
1378 if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
1379 &s->token_gids,
1380 &s->num_token_gids)) {
1381 return;
1382 }
1383 }
1384
1385 if (s->i < s->num_token_sids) {
1386 const DOM_SID *sid = &s->token_sids[s->i];
1387 s->i += 1;
1388
1389 if (sid_equal(sid, &s->user_sid)) {
1390 getgroups_sid2gid_recv(s, False, 0);
1391 return;
1392 }
1393
1394 winbindd_sid2gid_async(s->state->mem_ctx, sid,
1395 getgroups_sid2gid_recv, s);
1396 return;
1397 }
1398
1399 s->state->response.data.num_entries = s->num_token_gids;
1400 /* s->token_gids are talloced */
1401 s->state->response.extra_data.data = smb_xmemdup(s->token_gids, s->num_token_gids * sizeof(gid_t));
1402 s->state->response.length += s->num_token_gids * sizeof(gid_t);
1403 request_ok(s->state);
1404}
1405
1406/* Get user supplementary sids. This is equivalent to the
1407 winbindd_getgroups() function but it involves a SID->SIDs mapping
1408 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1409 idmap. This call is designed to be used with applications that need
1410 to do ACL evaluation themselves. Note that the cached info3 data is
1411 not used
1412
1413 this function assumes that the SID that comes in is a user SID. If
1414 you pass in another type of SID then you may get unpredictable
1415 results.
1416*/
1417
1418static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1419 size_t num_sids);
1420
1421void winbindd_getusersids(struct winbindd_cli_state *state)
1422{
1423 DOM_SID *user_sid;
1424
1425 /* Ensure null termination */
1426 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1427
1428 user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
1429 if (user_sid == NULL) {
1430 DEBUG(1, ("talloc failed\n"));
1431 request_error(state);
1432 return;
1433 }
1434
1435 if (!string_to_sid(user_sid, state->request.data.sid)) {
1436 DEBUG(1, ("Could not get convert sid %s from string\n",
1437 state->request.data.sid));
1438 request_error(state);
1439 return;
1440 }
1441
1442 winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
1443 state);
1444}
1445
1446static void getusersids_recv(void *private_data, BOOL success, DOM_SID *sids,
1447 size_t num_sids)
1448{
1449 struct winbindd_cli_state *state =
1450 (struct winbindd_cli_state *)private_data;
1451 char *ret = NULL;
1452 unsigned ofs, ret_size = 0;
1453 size_t i;
1454
1455 if (!success) {
1456 request_error(state);
1457 return;
1458 }
1459
1460 /* work out the response size */
1461 for (i = 0; i < num_sids; i++) {
1462 const char *s = sid_string_static(&sids[i]);
1463 ret_size += strlen(s) + 1;
1464 }
1465
1466 /* build the reply */
1467 ret = (char *)SMB_MALLOC(ret_size);
1468 if (!ret) {
1469 DEBUG(0, ("malloc failed\n"));
1470 request_error(state);
1471 return;
1472 }
1473 ofs = 0;
1474 for (i = 0; i < num_sids; i++) {
1475 const char *s = sid_string_static(&sids[i]);
1476 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1477 ofs += strlen(ret+ofs) + 1;
1478 }
1479
1480 /* Send data back to client */
1481 state->response.data.num_entries = num_sids;
1482 state->response.extra_data.data = ret;
1483 state->response.length += ret_size;
1484 request_ok(state);
1485}
1486
1487void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
1488{
1489 DOM_SID user_sid;
1490 struct winbindd_domain *domain;
1491
1492 /* Ensure null termination */
1493 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1494
1495 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1496 DEBUG(1, ("Could not get convert sid %s from string\n",
1497 state->request.data.sid));
1498 request_error(state);
1499 return;
1500 }
1501
1502 /* Get info for the domain */
1503 if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
1504 DEBUG(0,("could not find domain entry for sid %s\n",
1505 sid_string_static(&user_sid)));
1506 request_error(state);
1507 return;
1508 }
1509
1510 sendto_domain(state, domain);
1511}
1512
1513enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
1514 struct winbindd_cli_state *state)
1515{
1516 DOM_SID user_sid;
1517 NTSTATUS status;
1518
1519 char *sidstring;
1520 ssize_t len;
1521 DOM_SID *groups;
1522 uint32 num_groups;
1523
1524 /* Ensure null termination */
1525 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1526
1527 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1528 DEBUG(1, ("Could not get convert sid %s from string\n",
1529 state->request.data.sid));
1530 return WINBINDD_ERROR;
1531 }
1532
1533 status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
1534 &user_sid, &num_groups,
1535 &groups);
1536 if (!NT_STATUS_IS_OK(status))
1537 return WINBINDD_ERROR;
1538
1539 if (num_groups == 0) {
1540 state->response.data.num_entries = 0;
1541 state->response.extra_data.data = NULL;
1542 return WINBINDD_OK;
1543 }
1544
1545 if (!print_sidlist(state->mem_ctx, groups, num_groups, &sidstring, &len)) {
1546 DEBUG(0, ("talloc failed\n"));
1547 return WINBINDD_ERROR;
1548 }
1549
1550 state->response.extra_data.data = SMB_STRDUP(sidstring);
1551 if (!state->response.extra_data.data) {
1552 return WINBINDD_ERROR;
1553 }
1554 state->response.length += len+1;
1555 state->response.data.num_entries = num_groups;
1556
1557 return WINBINDD_OK;
1558}
Note: See TracBrowser for help on using the repository browser.