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