2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2001.
8 Copyright (C) Gerald (Jerry) Carter 2003.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 extern BOOL opt_nocache;
31 #define DBGC_CLASS DBGC_WINBIND
33 /*********************************************************************
34 *********************************************************************/
36 static int gr_mem_buffer( char **buffer, char **members, int num_members )
42 if ( num_members == 0 ) {
47 for ( i=0; i<num_members; i++ )
48 len += strlen(members[i])+1;
50 *buffer = (char*)smb_xmalloc(len);
51 for ( i=0; i<num_members; i++ ) {
52 snprintf( &(*buffer)[idx], len-idx, "%s,", members[i]);
53 idx += strlen(members[i])+1;
55 /* terminate with NULL */
56 (*buffer)[len-1] = '\0';
61 /***************************************************************
62 Empty static struct for negative caching.
63 ****************************************************************/
65 /* Fill a grent structure from various other information */
67 static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name,
68 const char *gr_name, gid_t unix_gid)
70 fstring full_group_name;
72 fill_domain_username(full_group_name, dom_name, gr_name);
74 gr->gr_gid = unix_gid;
76 /* Group name and password */
78 safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
79 safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
84 /* Fill in the group membership field of a NT group given by group_sid */
86 static BOOL fill_grent_mem(struct winbindd_domain *domain,
88 enum SID_NAME_USE group_name_type,
89 int *num_gr_mem, char **gr_mem, int *gr_mem_len)
91 DOM_SID **sid_mem = NULL;
93 uint32 *name_types = NULL;
94 unsigned int buf_len, buf_ndx, i;
95 char **names = NULL, *buf;
101 if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
104 /* Initialise group membership information */
106 DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
110 if ( !((group_name_type==SID_NAME_DOM_GRP) ||
111 ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
113 DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
114 sid_to_string(sid_string, group_sid), domain->name,
119 /* Lookup group members */
120 status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names,
121 &sid_mem, &names, &name_types);
122 if (!NT_STATUS_IS_OK(status)) {
123 DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n",
124 sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status)));
129 DEBUG(10, ("looked up %d names\n", num_names));
131 if (DEBUGLEVEL >= 10) {
132 for (i = 0; i < num_names; i++)
133 DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
137 /* Add members to list */
140 buf_len = buf_ndx = 0;
144 for (i = 0; i < num_names; i++) {
151 DEBUG(10, ("processing name %s\n", the_name));
153 /* FIXME: need to cope with groups within groups. These
154 occur in Universal groups on a Windows 2000 native mode
157 /* make sure to allow machine accounts */
159 if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) {
160 DEBUG(3, ("name %s isn't a domain user\n", the_name));
164 /* Append domain name */
166 fill_domain_username(name, domain->name, the_name);
170 /* Add to list or calculate buffer length */
173 buf_len += len + 1; /* List is comma separated */
175 DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
177 DEBUG(10, ("appending %s at ndx %d\n", name, len));
178 safe_strcpy(&buf[buf_ndx], name, len);
185 /* Allocate buffer */
187 if (!buf && buf_len != 0) {
188 if (!(buf = malloc(buf_len))) {
189 DEBUG(1, ("out of memory\n"));
193 memset(buf, 0, buf_len);
197 if (buf && buf_ndx > 0) {
198 buf[buf_ndx - 1] = '\0';
202 *gr_mem_len = buf_len;
204 DEBUG(10, ("num_mem = %d, len = %d, mem = %s\n", *num_gr_mem,
205 buf_len, *num_gr_mem ? buf : "NULL"));
210 talloc_destroy(mem_ctx);
212 DEBUG(10, ("fill_grent_mem returning %d\n", result));
217 /* Return a group structure from a group name */
219 enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
223 struct winbindd_domain *domain;
224 enum SID_NAME_USE name_type;
225 fstring name_domain, name_group;
230 /* Ensure null termination */
231 state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
233 DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
234 state->request.data.groupname));
236 /* Parse domain and groupname */
238 memset(name_group, 0, sizeof(fstring));
240 tmp = state->request.data.groupname;
242 parse_domain_user(tmp, name_domain, name_group);
244 /* if no domain or our local domain, then do a local tdb search */
246 if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
249 if ( !(grp=wb_getgrnam(name_group)) ) {
250 DEBUG(5,("winbindd_getgrnam: lookup for %s\\%s failed\n",
251 name_domain, name_group));
252 return WINBINDD_ERROR;
254 memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
256 gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
258 state->response.data.gr.gr_mem_ofs = 0;
259 state->response.length += gr_mem_len;
260 state->response.extra_data = buffer; /* give the memory away */
265 /* Get info for the domain */
267 if ((domain = find_domain_from_name(name_domain)) == NULL) {
268 DEBUG(3, ("could not get domain sid for domain %s\n",
270 return WINBINDD_ERROR;
272 /* should we deal with users for our domain? */
274 if ( lp_winbind_trusted_domains_only() && domain->primary) {
275 DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n",
276 name_domain, name_group));
277 return WINBINDD_ERROR;
280 /* Get rid and name type from name */
282 if (!winbindd_lookup_sid_by_name(domain, name_group, &group_sid,
284 DEBUG(1, ("group %s in domain %s does not exist\n",
285 name_group, name_domain));
286 return WINBINDD_ERROR;
289 if ( !((name_type==SID_NAME_DOM_GRP) ||
290 ((name_type==SID_NAME_ALIAS) && domain->primary)) )
292 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
293 name_group, name_type));
294 return WINBINDD_ERROR;
297 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid, 0))) {
298 DEBUG(1, ("error converting unix gid to sid\n"));
299 return WINBINDD_ERROR;
302 if (!fill_grent(&state->response.data.gr, name_domain,
304 !fill_grent_mem(domain, &group_sid, name_type,
305 &state->response.data.gr.num_gr_mem,
306 &gr_mem, &gr_mem_len)) {
307 return WINBINDD_ERROR;
310 /* Group membership lives at start of extra data */
312 state->response.data.gr.gr_mem_ofs = 0;
314 state->response.length += gr_mem_len;
315 state->response.extra_data = gr_mem;
320 /* Return a group structure from a gid number */
322 enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
324 struct winbindd_domain *domain;
327 enum SID_NAME_USE name_type;
333 DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
334 (unsigned long)state->request.data.gid));
336 /* Bug out if the gid isn't in the winbind range */
338 if ((state->request.data.gid < server_state.gid_low) ||
339 (state->request.data.gid > server_state.gid_high))
340 return WINBINDD_ERROR;
342 /* alway try local tdb lookup first */
343 if ( ( grp=wb_getgrgid(state->request.data.gid)) != NULL ) {
346 memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
348 gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
350 state->response.data.gr.gr_mem_ofs = 0;
351 state->response.length += gr_mem_len;
352 state->response.extra_data = buffer; /* give away the memory */
357 /* Get rid from gid */
358 if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
359 DEBUG(1, ("could not convert gid %lu to rid\n",
360 (unsigned long)state->request.data.gid));
361 return WINBINDD_ERROR;
364 /* Get name from sid */
366 if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
367 DEBUG(1, ("could not lookup sid\n"));
368 return WINBINDD_ERROR;
371 /* Fill in group structure */
373 domain = find_domain_from_sid(&group_sid);
376 DEBUG(1,("Can't find domain from sid\n"));
377 return WINBINDD_ERROR;
380 if ( !((name_type==SID_NAME_DOM_GRP) ||
381 ((name_type==SID_NAME_ALIAS) && domain->primary) ))
383 DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
384 group_name, name_type));
385 return WINBINDD_ERROR;
388 if (!fill_grent(&state->response.data.gr, dom_name, group_name,
389 state->request.data.gid) ||
390 !fill_grent_mem(domain, &group_sid, name_type,
391 &state->response.data.gr.num_gr_mem,
392 &gr_mem, &gr_mem_len))
393 return WINBINDD_ERROR;
395 /* Group membership lives at start of extra data */
397 state->response.data.gr.gr_mem_ofs = 0;
399 state->response.length += gr_mem_len;
400 state->response.extra_data = gr_mem;
406 * set/get/endgrent functions
409 /* "Rewind" file pointer for group database enumeration */
411 enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
413 struct winbindd_domain *domain;
415 DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
417 /* Check user has enabled this */
419 if (!lp_winbind_enum_groups())
420 return WINBINDD_ERROR;
422 /* Free old static data if it exists */
424 if (state->getgrent_state != NULL) {
425 free_getent_state(state->getgrent_state);
426 state->getgrent_state = NULL;
429 /* Create sam pipes for each domain we know about */
431 for (domain = domain_list(); domain != NULL; domain = domain->next) {
432 struct getent_state *domain_state;
435 /* don't add our domaina if we are a PDC or if we
436 are a member of a Samba domain */
438 if ( (IS_DC || lp_winbind_trusted_domains_only())
444 /* Create a state record for this domain */
446 if ((domain_state = (struct getent_state *)
447 malloc(sizeof(struct getent_state))) == NULL) {
448 DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n"));
449 return WINBINDD_ERROR;
452 ZERO_STRUCTP(domain_state);
454 fstrcpy(domain_state->domain_name, domain->name);
456 /* Add to list of open domains */
458 DLIST_ADD(state->getgrent_state, domain_state);
464 /* Close file pointer to ntdom group database */
466 enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
468 DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
470 free_getent_state(state->getgrent_state);
471 state->getgrent_state = NULL;
476 /* Get the list of domain groups and domain aliases for a domain. We fill in
477 the sam_entries and num_sam_entries fields with domain group information.
478 The dispinfo_ndx field is incremented to the index of the next group to
479 fetch. Return True if some groups were returned, False otherwise. */
481 #define MAX_FETCH_SAM_ENTRIES 100
483 static BOOL get_sam_group_entries(struct getent_state *ent)
487 struct acct_info *name_list = NULL, *tmp_name_list = NULL;
490 struct acct_info *sam_grp_entries = NULL;
491 struct winbindd_domain *domain;
493 if (ent->got_sam_entries)
496 if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
497 ent->domain_name))) {
498 DEBUG(1, ("get_sam_group_entries: could not create talloc context!\n"));
502 /* Free any existing group info */
504 SAFE_FREE(ent->sam_entries);
505 ent->num_sam_entries = 0;
506 ent->got_sam_entries = True;
508 /* Enumerate domain groups */
512 if (!(domain = find_domain_from_name(ent->domain_name))) {
513 DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
517 /* always get the domain global groups */
519 status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
521 if (!NT_STATUS_IS_OK(status)) {
522 DEBUG(3, ("get_sam_group_entries: could not enumerate domain groups! Error: %s\n", nt_errstr(status)));
527 /* Copy entries into return buffer */
530 if ( !(name_list = malloc(sizeof(struct acct_info) * num_entries)) ) {
531 DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n",
536 memcpy( name_list, sam_grp_entries, num_entries * sizeof(struct acct_info) );
539 ent->num_sam_entries = num_entries;
541 /* get the domain local groups if we are a member of a native win2k domain
542 and are not using LDAP to get the groups */
544 if ( lp_security() != SEC_ADS && domain->native_mode
547 DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
549 status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries);
551 if ( !NT_STATUS_IS_OK(status) ) {
552 DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n"));
556 DEBUG(4,("get_sam_group_entries: Returned %d local groups\n", num_entries));
558 /* Copy entries into return buffer */
561 if ( !(tmp_name_list = Realloc( name_list, sizeof(struct acct_info) * (ent->num_sam_entries+num_entries))) )
563 DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n",
566 SAFE_FREE( name_list );
570 name_list = tmp_name_list;
572 memcpy( &name_list[ent->num_sam_entries], sam_grp_entries,
573 num_entries * sizeof(struct acct_info) );
576 ent->num_sam_entries += num_entries;
580 /* Fill in remaining fields */
582 ent->sam_entries = name_list;
583 ent->sam_entry_index = 0;
585 result = (ent->num_sam_entries > 0);
588 talloc_destroy(mem_ctx);
593 /* Fetch next group entry from ntdom database */
595 #define MAX_GETGRENT_GROUPS 500
597 enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
599 struct getent_state *ent;
600 struct winbindd_gr *group_list = NULL;
601 int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
602 char *new_extra_data, *gr_mem_list = NULL;
604 DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
606 /* Check user has enabled this */
608 if (!lp_winbind_enum_groups())
609 return WINBINDD_ERROR;
611 num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
613 if ((state->response.extra_data =
614 malloc(num_groups * sizeof(struct winbindd_gr))) == NULL)
615 return WINBINDD_ERROR;
617 state->response.data.num_entries = 0;
619 group_list = (struct winbindd_gr *)state->response.extra_data;
621 if (!(ent = state->getgrent_state))
622 return WINBINDD_ERROR;
624 /* Start sending back groups */
626 for (i = 0; i < num_groups; i++) {
627 struct acct_info *name_list = NULL;
628 fstring domain_group_name;
632 char *gr_mem, *new_gr_mem_list;
634 struct winbindd_domain *domain;
636 /* Do we need to fetch another chunk of groups? */
640 DEBUG(10, ("entry_index = %d, num_entries = %d\n",
641 ent->sam_entry_index, ent->num_sam_entries));
643 if (ent->num_sam_entries == ent->sam_entry_index) {
645 while(ent && !get_sam_group_entries(ent)) {
646 struct getent_state *next_ent;
648 DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name));
650 /* Free state information for this domain */
652 SAFE_FREE(ent->sam_entries);
654 next_ent = ent->next;
655 DLIST_REMOVE(state->getgrent_state, ent);
661 /* No more domains */
667 name_list = ent->sam_entries;
670 find_domain_from_name(ent->domain_name))) {
671 DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
676 /* Lookup group info */
678 sid_copy(&group_sid, &domain->sid);
679 sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
681 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) {
683 DEBUG(1, ("could not look up gid for group %s\n",
684 name_list[ent->sam_entry_index].acct_name));
686 ent->sam_entry_index++;
690 DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid,
691 (unsigned long)name_list[ent->sam_entry_index].rid));
693 /* Fill in group entry */
695 fill_domain_username(domain_group_name, ent->domain_name,
696 name_list[ent->sam_entry_index].acct_name);
698 result = fill_grent(&group_list[group_list_ndx],
700 name_list[ent->sam_entry_index].acct_name,
703 /* Fill in group membership entry */
707 group_list[group_list_ndx].num_gr_mem = 0;
711 /* Get group membership */
712 if (state->request.cmd == WINBINDD_GETGRLST) {
715 sid_copy(&member_sid, &domain->sid);
716 sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
717 result = fill_grent_mem(
721 &group_list[group_list_ndx].num_gr_mem,
722 &gr_mem, &gr_mem_len);
727 /* Append to group membership list */
728 new_gr_mem_list = Realloc(
730 gr_mem_list_len + gr_mem_len);
732 if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
733 DEBUG(0, ("out of memory\n"));
734 SAFE_FREE(gr_mem_list);
739 DEBUG(10, ("list_len = %d, mem_len = %d\n",
740 gr_mem_list_len, gr_mem_len));
742 gr_mem_list = new_gr_mem_list;
744 memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
749 group_list[group_list_ndx].gr_mem_ofs =
752 gr_mem_list_len += gr_mem_len;
755 ent->sam_entry_index++;
757 /* Add group to return list */
761 DEBUG(10, ("adding group num_entries = %d\n",
762 state->response.data.num_entries));
765 state->response.data.num_entries++;
767 state->response.length +=
768 sizeof(struct winbindd_gr);
771 DEBUG(0, ("could not lookup domain group %s\n",
776 /* Copy the list of group memberships to the end of the extra data */
778 if (group_list_ndx == 0)
781 new_extra_data = Realloc(
782 state->response.extra_data,
783 group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
785 if (!new_extra_data) {
786 DEBUG(0, ("out of memory\n"));
788 SAFE_FREE(state->response.extra_data);
789 SAFE_FREE(gr_mem_list);
791 return WINBINDD_ERROR;
794 state->response.extra_data = new_extra_data;
796 memcpy(&((char *)state->response.extra_data)
797 [group_list_ndx * sizeof(struct winbindd_gr)],
798 gr_mem_list, gr_mem_list_len);
800 SAFE_FREE(gr_mem_list);
802 state->response.length += gr_mem_list_len;
804 DEBUG(10, ("returning %d groups, length = %d\n",
805 group_list_ndx, gr_mem_list_len));
811 return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
814 /* List domain groups without mapping to unix ids */
816 enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
818 uint32 total_entries = 0;
819 struct winbindd_domain *domain;
820 const char *which_domain;
821 char *extra_data = NULL;
823 unsigned int extra_data_len = 0, i;
825 DEBUG(3, ("[%5lu]: list groups\n", (unsigned long)state->pid));
827 /* Ensure null termination */
828 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
829 which_domain = state->request.domain_name;
831 /* Enumerate over trusted domains */
833 for (domain = domain_list(); domain; domain = domain->next) {
834 struct getent_state groups;
836 /* if we have a domain name restricting the request and this
837 one in the list doesn't match, then just bypass the remainder
840 if ( *which_domain && !strequal(which_domain, domain->name) )
845 /* Get list of sam groups */
847 fstrcpy(groups.domain_name, domain->name);
849 get_sam_group_entries(&groups);
851 if (groups.num_sam_entries == 0) {
852 /* this domain is empty or in an error state */
856 /* keep track the of the total number of groups seen so
857 far over all domains */
858 total_entries += groups.num_sam_entries;
860 /* Allocate some memory for extra data. Note that we limit
861 account names to sizeof(fstring) = 128 characters. */
862 ted = Realloc(extra_data, sizeof(fstring) * total_entries);
865 DEBUG(0,("failed to enlarge buffer!\n"));
866 SAFE_FREE(extra_data);
867 return WINBINDD_ERROR;
871 /* Pack group list into extra data fields */
872 for (i = 0; i < groups.num_sam_entries; i++) {
873 char *group_name = ((struct acct_info *)
874 groups.sam_entries)[i].acct_name;
877 fill_domain_username(name, domain->name, group_name);
878 /* Append to extra data */
879 memcpy(&extra_data[extra_data_len], name,
881 extra_data_len += strlen(name);
882 extra_data[extra_data_len++] = ',';
885 SAFE_FREE(groups.sam_entries);
888 /* Assign extra_data fields in response structure */
890 extra_data[extra_data_len - 1] = '\0';
891 state->response.extra_data = extra_data;
892 state->response.length += extra_data_len;
895 /* No domains may have responded but that's still OK so don't
901 /* Get user supplementary groups. This is much quicker than trying to
902 invert the groups database. We merge the groups from the gids and
903 other_sids info3 fields as trusted domain, universal group
904 memberships, and nested groups (win2k native mode only) are not
905 returned by the getgroups RPC call but are present in the info3. */
907 enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
909 fstring name_domain, name_user;
910 DOM_SID user_sid, group_sid;
911 enum SID_NAME_USE name_type;
912 uint32 num_groups = 0;
915 DOM_SID **user_grpsids;
916 struct winbindd_domain *domain;
917 enum winbindd_result result = WINBINDD_ERROR;
921 NET_USER_INFO_3 *info3 = NULL;
923 /* Ensure null termination */
924 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
926 DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
927 state->request.data.username));
929 if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
930 state->request.data.username)))
931 return WINBINDD_ERROR;
933 /* Parse domain and username */
935 parse_domain_user(state->request.data.username,
936 name_domain, name_user);
938 /* Get info for the domain */
940 if ((domain = find_domain_from_name(name_domain)) == NULL) {
941 DEBUG(7, ("could not find domain entry for domain %s\n",
946 if ( domain->primary && lp_winbind_trusted_domains_only()) {
947 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getgroups() for %s\\%s.\n",
948 name_domain, name_user));
949 return WINBINDD_ERROR;
952 /* Get rid and name type from name. The following costs 1 packet */
954 if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid,
956 DEBUG(1, ("user '%s' does not exist\n", name_user));
960 if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
961 DEBUG(1, ("name '%s' is not a user name: %d\n",
962 name_user, name_type));
966 /* Treat the info3 cache as authoritative as the
967 lookup_usergroups() function may return cached data. */
969 if ( !opt_nocache && (info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
971 DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
972 info3->num_groups2, info3->num_other_sids));
974 num_groups = info3->num_other_sids + info3->num_groups2;
975 gid_list = calloc(sizeof(gid_t), num_groups);
977 /* Go through each other sid and convert it to a gid */
979 for (i = 0; i < info3->num_other_sids; i++) {
982 enum SID_NAME_USE sid_type;
984 /* Is this sid known to us? It can either be
985 a trusted domain sid or a foreign sid. */
987 if (!winbindd_lookup_name_by_sid( &info3->other_sids[i].sid,
988 dom_name, name, &sid_type))
990 DEBUG(10, ("winbindd_getgroups: could not lookup name for %s\n",
991 sid_string_static(&info3->other_sids[i].sid)));
995 /* Check it is a domain group or an alias (domain local group)
996 in a win2k native mode domain. */
998 if ( !((sid_type==SID_NAME_DOM_GRP) ||
999 ((sid_type==SID_NAME_ALIAS) && domain->primary)) )
1001 DEBUG(10, ("winbindd_getgroups: sid type %d "
1002 "for %s is not a domain group\n",
1005 &info3->other_sids[i].sid)));
1011 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&info3->other_sids[i].sid, &gid_list[num_gids], 0)) )
1013 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
1014 sid_string_static(&info3->other_sids[i].sid)));
1018 /* We've jumped through a lot of hoops to get here */
1020 DEBUG(10, ("winbindd_getgroups: mapped other sid %s to "
1021 "gid %lu\n", sid_string_static(
1022 &info3->other_sids[i].sid),
1023 (unsigned long)gid_list[num_gids]));
1028 for (i = 0; i < info3->num_groups2; i++) {
1030 /* create the group SID */
1032 sid_copy( &group_sid, &domain->sid );
1033 sid_append_rid( &group_sid, info3->gids[i].g_rid );
1035 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid_list[num_gids], 0)) ) {
1036 DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
1037 sid_string_static(&group_sid)));
1046 status = domain->methods->lookup_usergroups(domain, mem_ctx,
1047 &user_sid, &num_groups,
1049 if (!NT_STATUS_IS_OK(status))
1052 gid_list = malloc(sizeof(gid_t) * num_groups);
1054 if (state->response.extra_data)
1057 for (i = 0; i < num_groups; i++) {
1058 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_grpsids[i], &gid_list[num_gids], 0))) {
1059 DEBUG(1, ("unable to convert group sid %s to gid\n",
1060 sid_string_static(user_grpsids[i])));
1067 /* Send data back to client */
1069 state->response.data.num_entries = num_gids;
1070 state->response.extra_data = gid_list;
1071 state->response.length += num_gids * sizeof(gid_t);
1073 result = WINBINDD_OK;
1077 talloc_destroy(mem_ctx);
1083 /* Get user supplementary sids. This is equivalent to the
1084 winbindd_getgroups() function but it involves a SID->SIDs mapping
1085 rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
1086 idmap. This call is designed to be used with applications that need
1087 to do ACL evaluation themselves. Note that the cached info3 data is
1090 this function assumes that the SID that comes in is a user SID. If
1091 you pass in another type of SID then you may get unpredictable
1094 enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
1098 DOM_SID **user_grpsids;
1099 struct winbindd_domain *domain;
1100 enum winbindd_result result = WINBINDD_ERROR;
1102 TALLOC_CTX *mem_ctx;
1105 unsigned ofs, ret_size = 0;
1107 /* Ensure null termination */
1108 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
1110 if (!string_to_sid(&user_sid, state->request.data.sid)) {
1111 DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
1112 return WINBINDD_ERROR;
1115 if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)",
1116 state->request.data.username))) {
1117 return WINBINDD_ERROR;
1120 /* Get info for the domain */
1121 if ((domain = find_domain_from_sid(&user_sid)) == NULL) {
1122 DEBUG(0,("could not find domain entry for sid %s\n",
1123 sid_string_static(&user_sid)));
1127 status = domain->methods->lookup_usergroups(domain, mem_ctx,
1128 &user_sid, &num_groups,
1130 if (!NT_STATUS_IS_OK(status))
1133 if (num_groups == 0) {
1137 /* work out the response size */
1138 for (i = 0; i < num_groups; i++) {
1139 const char *s = sid_string_static(user_grpsids[i]);
1140 ret_size += strlen(s) + 1;
1143 /* build the reply */
1144 ret = malloc(ret_size);
1145 if (!ret) goto done;
1147 for (i = 0; i < num_groups; i++) {
1148 const char *s = sid_string_static(user_grpsids[i]);
1149 safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
1150 ofs += strlen(ret+ofs) + 1;
1154 /* Send data back to client */
1155 state->response.data.num_entries = num_groups;
1156 state->response.extra_data = ret;
1157 state->response.length += ret_size;
1158 result = WINBINDD_OK;
1161 talloc_destroy(mem_ctx);