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