X-Git-Url: http://git.samba.org/samba.git/?p=tprouty%2Fsamba.git;a=blobdiff_plain;f=source%2Fnsswitch%2Fwinbindd_group.c;h=4b49c1873e2425974512436faf3b1438e4010360;hp=180a3db8e2e02c0968972a10cbcf516284a0e9dc;hb=620f2e608f70ba92f032720c031283d295c5c06a;hpb=60107efdc61247034424d008c6f1eb4d46a19881 diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c index 180a3db8e2..4b49c1873e 100644 --- a/source/nsswitch/winbindd_group.c +++ b/source/nsswitch/winbindd_group.c @@ -25,6 +25,8 @@ #include "includes.h" #include "winbindd.h" +extern BOOL opt_nocache; + #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND @@ -45,7 +47,7 @@ static int gr_mem_buffer( char **buffer, char **members, int num_members ) for ( i=0; iinternal) + return fill_passdb_alias_grmem(domain, group_sid, + num_gr_mem, + gr_mem, gr_mem_len); if ( !((group_name_type==SID_NAME_DOM_GRP) || - ((group_name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((group_name_type==SID_NAME_ALIAS) && domain->primary)) ) { DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n", sid_to_string(sid_string, group_sid), domain->name, @@ -152,15 +163,10 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, occur in Universal groups on a Windows 2000 native mode server. */ - if (name_types[i] != SID_NAME_USER) { - DEBUG(3, ("name %s isn't a domain user\n", the_name)); - continue; - } + /* make sure to allow machine accounts */ - /* Don't bother with machine accounts */ - - if (the_name[strlen(the_name) - 1] == '$') { - DEBUG(10, ("%s is machine account\n", the_name)); + if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) { + DEBUG(3, ("name %s isn't a domain user\n", the_name)); continue; } @@ -188,7 +194,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, /* Allocate buffer */ if (!buf && buf_len != 0) { - if (!(buf = malloc(buf_len))) { + if (!(buf = SMB_MALLOC(buf_len))) { DEBUG(1, ("out of memory\n")); result = False; goto done; @@ -246,14 +252,11 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) /* if no domain or our local domain, then do a local tdb search */ - if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) { + if ( (!*name_domain || strequal(name_domain, get_global_sam_name())) && + ((grp = wb_getgrnam(name_group)) != NULL) ) { + char *buffer = NULL; - if ( !(grp=wb_getgrnam(name_group)) ) { - DEBUG(5,("winbindd_getgrnam: lookup for %s\\%s failed\n", - name_domain, name_group)); - return WINBINDD_ERROR; - } memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) ); gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem ); @@ -265,26 +268,31 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) return WINBINDD_OK; } - /* should we deal with users for our domain? */ - - if ( lp_winbind_trusted_domains_only() && strequal(name_domain, lp_workgroup())) { - DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n", - name_domain, name_group)); - return WINBINDD_ERROR; - } + /* if no domain or our local domain and no local tdb group, default to + * our local domain for aliases */ + + if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) { + fstrcpy(name_domain, get_global_sam_name()); + } - /* Get info for the domain */ if ((domain = find_domain_from_name(name_domain)) == NULL) { - DEBUG(0, ("could not get domain sid for domain %s\n", + DEBUG(3, ("could not get domain sid for domain %s\n", name_domain)); return WINBINDD_ERROR; } + /* should we deal with users for our domain? */ + + if ( lp_winbind_trusted_domains_only() && domain->primary) { + DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n", + name_domain, name_group)); + return WINBINDD_ERROR; + } /* Get rid and name type from name */ - if (!winbindd_lookup_sid_by_name(domain, name_group, &group_sid, + if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid, &name_type)) { DEBUG(1, ("group %s in domain %s does not exist\n", name_group, name_domain)); @@ -292,7 +300,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) } if ( !((name_type==SID_NAME_DOM_GRP) || - ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((name_type==SID_NAME_ALIAS) && domain->primary) || + ((name_type==SID_NAME_ALIAS) && domain->internal)) ) { DEBUG(1, ("name '%s' is not a local or domain group: %d\n", name_group, name_type)); @@ -383,7 +392,8 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) } if ( !((name_type==SID_NAME_DOM_GRP) || - ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((name_type==SID_NAME_ALIAS) && domain->primary) || + ((name_type==SID_NAME_ALIAS) && domain->internal)) ) { DEBUG(1, ("name '%s' is not a local or domain group: %d\n", group_name, name_type)); @@ -436,20 +446,18 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state) for (domain = domain_list(); domain != NULL; domain = domain->next) { struct getent_state *domain_state; - + /* Create a state record for this domain */ + /* don't add our domaina if we are a PDC or if we are a member of a Samba domain */ - if ( (IS_DC || lp_winbind_trusted_domains_only()) - && strequal(domain->name, lp_workgroup()) ) + if ( lp_winbind_trusted_domains_only() && domain->primary ) { continue; } - /* Create a state record for this domain */ - if ((domain_state = (struct getent_state *) - malloc(sizeof(struct getent_state))) == NULL) { + if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) { DEBUG(1, ("winbindd_setgrent: malloc failed for domain_state!\n")); return WINBINDD_ERROR; } @@ -463,6 +471,8 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state) DLIST_ADD(state->getgrent_state, domain_state); } + state->getgrent_initialized = True; + return WINBINDD_OK; } @@ -473,6 +483,7 @@ enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state) DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid)); free_getent_state(state->getgrent_state); + state->getgrent_initialized = False; state->getgrent_state = NULL; return WINBINDD_OK; @@ -483,8 +494,6 @@ enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state) The dispinfo_ndx field is incremented to the index of the next group to fetch. Return True if some groups were returned, False otherwise. */ -#define MAX_FETCH_SAM_ENTRIES 100 - static BOOL get_sam_group_entries(struct getent_state *ent) { NTSTATUS status; @@ -532,7 +541,7 @@ static BOOL get_sam_group_entries(struct getent_state *ent) /* Copy entries into return buffer */ if (num_entries) { - if ( !(name_list = malloc(sizeof(struct acct_info) * num_entries)) ) { + if ( !(name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries)) ) { DEBUG(0,("get_sam_group_entries: Failed to malloc memory for %d domain groups!\n", num_entries)); result = False; @@ -546,8 +555,8 @@ static BOOL get_sam_group_entries(struct getent_state *ent) /* get the domain local groups if we are a member of a native win2k domain and are not using LDAP to get the groups */ - if ( lp_security() != SEC_ADS && domain->native_mode - && strequal(lp_workgroup(), domain->name) ) + if ( ( lp_security() != SEC_ADS && domain->native_mode + && domain->primary) || domain->internal ) { DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n")); @@ -563,7 +572,7 @@ static BOOL get_sam_group_entries(struct getent_state *ent) /* Copy entries into return buffer */ if ( num_entries ) { - if ( !(tmp_name_list = Realloc( name_list, sizeof(struct acct_info) * (ent->num_sam_entries+num_entries))) ) + if ( !(tmp_name_list = SMB_REALLOC_ARRAY( name_list, struct acct_info, ent->num_sam_entries+num_entries)) ) { DEBUG(0,("get_sam_group_entries: Failed to realloc more memory for %d local groups!\n", num_entries)); @@ -615,14 +624,19 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries); - if ((state->response.extra_data = - malloc(num_groups * sizeof(struct winbindd_gr))) == NULL) + if ((state->response.extra_data = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups)) == NULL) return WINBINDD_ERROR; + memset(state->response.extra_data, '\0', + num_groups * sizeof(struct winbindd_gr) ); + state->response.data.num_entries = 0; group_list = (struct winbindd_gr *)state->response.extra_data; + if (!state->getgrent_initialized) + winbindd_setgrent(state); + if (!(ent = state->getgrent_state)) return WINBINDD_ERROR; @@ -730,9 +744,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) if (result) { /* Append to group membership list */ - new_gr_mem_list = Realloc( - gr_mem_list, - gr_mem_list_len + gr_mem_len); + new_gr_mem_list = SMB_REALLOC( gr_mem_list, gr_mem_list_len + gr_mem_len); if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) { DEBUG(0, ("out of memory\n")); @@ -783,7 +795,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) if (group_list_ndx == 0) goto done; - new_extra_data = Realloc( + new_extra_data = SMB_REALLOC( state->response.extra_data, group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len); @@ -864,7 +876,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) /* Allocate some memory for extra data. Note that we limit account names to sizeof(fstring) = 128 characters. */ - ted = Realloc(extra_data, sizeof(fstring) * total_entries); + ted = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries); if (!ted) { DEBUG(0,("failed to enlarge buffer!\n")); @@ -887,7 +899,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) extra_data[extra_data_len++] = ','; } - free(groups.sam_entries); + SAFE_FREE(groups.sam_entries); } /* Assign extra_data fields in response structure */ @@ -903,6 +915,65 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) return WINBINDD_OK; } +static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num) +{ + gid_t gid; + DOM_SID *aliases; + int j, num_aliases; + + DEBUG(10, ("Adding local gids from SID: %s\n", + sid_string_static(sid))); + + /* Don't expand aliases if not explicitly activated -- for now + -- jerry */ + + if (!lp_winbind_nested_groups()) + return; + + /* Add nested group memberships */ + + if (!pdb_enum_alias_memberships(sid, 1, &aliases, &num_aliases)) + return; + + for (j=0; jrequest.data.username, - name_domain, name_user); + name_domain, name_user); - /* bail if there is no domain */ - - if ( !*name_domain ) - goto done; - /* Get info for the domain */ if ((domain = find_domain_from_name(name_domain)) == NULL) { - DEBUG(0, ("could not find domain entry for domain %s\n", + DEBUG(7, ("could not find domain entry for domain %s\n", name_domain)); goto done; } + if ( domain->primary && lp_winbind_trusted_domains_only()) { + DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getgroups() for %s\\%s.\n", + name_domain, name_user)); + return WINBINDD_ERROR; + } + /* Get rid and name type from name. The following costs 1 packet */ - if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid, + if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, &name_type)) { DEBUG(1, ("user '%s' does not exist\n", name_user)); goto done; } - if (name_type != SID_NAME_USER) { + if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) { DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, name_type)); goto done; } + add_gids_from_user_sid(&user_sid, &gid_list, &num_gids); + /* Treat the info3 cache as authoritative as the lookup_usergroups() function may return cached data. */ - if ((info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) { + if ( !opt_nocache && (info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) { DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n", info3->num_groups2, info3->num_other_sids)); num_groups = info3->num_other_sids + info3->num_groups2; - gid_list = calloc(sizeof(gid_t), num_groups); /* Go through each other sid and convert it to a gid */ @@ -1000,7 +1073,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) in a win2k native mode domain. */ if ( !((sid_type==SID_NAME_DOM_GRP) || - ((sid_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((sid_type==SID_NAME_ALIAS) && domain->primary)) ) { DEBUG(10, ("winbindd_getgroups: sid type %d " "for %s is not a domain group\n", @@ -1010,23 +1083,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) continue; } - /* Map to a gid */ - - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&info3->other_sids[i].sid, &gid_list[num_gids], 0)) ) - { - DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n", - sid_string_static(&info3->other_sids[i].sid))); - continue; - } - - /* We've jumped through a lot of hoops to get here */ - - DEBUG(10, ("winbindd_getgroups: mapped other sid %s to " - "gid %lu\n", sid_string_static( - &info3->other_sids[i].sid), - (unsigned long)gid_list[num_gids])); - - num_gids++; + add_gids_from_group_sid(&info3->other_sids[i].sid, + &gid_list, &num_gids); } for (i = 0; i < info3->num_groups2; i++) { @@ -1036,12 +1094,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) sid_copy( &group_sid, &domain->sid ); sid_append_rid( &group_sid, info3->gids[i].g_rid ); - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid_list[num_gids], 0)) ) { - DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n", - sid_string_static(&group_sid))); - } - - num_gids++; + add_gids_from_group_sid(&group_sid, &gid_list, + &num_gids); } SAFE_FREE(info3); @@ -1053,21 +1107,21 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) if (!NT_STATUS_IS_OK(status)) goto done; - gid_list = malloc(sizeof(gid_t) * num_groups); - if (state->response.extra_data) goto done; for (i = 0; i < num_groups; i++) { - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_grpsids[i], &gid_list[num_gids], 0))) { - DEBUG(1, ("unable to convert group sid %s to gid\n", - sid_string_static(user_grpsids[i]))); - continue; - } - num_gids++; + add_gids_from_group_sid(user_grpsids[i], + &gid_list, &num_gids); } } + /* We want at least one group... */ + if (gid_list == NULL) + goto done; + + remove_duplicate_gids( &num_gids, gid_list ); + /* Send data back to client */ state->response.data.num_entries = num_gids; @@ -1083,6 +1137,48 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) return result; } +static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid, + DOM_SID ***sids, int *num_sids) +{ + int i; + + for (i=0; i<(*num_sids); i++) { + if (sid_compare(sid, (*sids)[i]) == 0) + return; + } + + *sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID *, *num_sids+1); + + if (*sids == NULL) + return; + + (*sids)[*num_sids] = TALLOC_P(mem_ctx, DOM_SID); + sid_copy((*sids)[*num_sids], sid); + *num_sids += 1; + return; +} + +static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, + DOM_SID ***user_grpsids, + int *num_groups) +{ + DOM_SID *aliases = NULL; + int i, num_aliases = 0; + + if (!pdb_enum_alias_memberships(sid, 1, &aliases, &num_aliases)) + return; + + if (num_aliases == 0) + return; + + for (i=0; iSIDs mapping @@ -1104,7 +1200,7 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) enum winbindd_result result = WINBINDD_ERROR; unsigned int i; TALLOC_CTX *mem_ctx; - char *ret; + char *ret = NULL; uint32 num_groups; unsigned ofs, ret_size = 0; @@ -1127,7 +1223,7 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) sid_string_static(&user_sid))); goto done; } - + status = domain->methods->lookup_usergroups(domain, mem_ctx, &user_sid, &num_groups, &user_grpsids); @@ -1138,6 +1234,20 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) goto no_groups; } + if (lp_winbind_nested_groups()) { + int k; + /* num_groups is changed during the loop, that's why we have + to count down here.*/ + + for (k=num_groups-1; k>=0; k--) { + add_local_sids_from_sid(mem_ctx, user_grpsids[k], + &user_grpsids, &num_groups); + } + + add_local_sids_from_sid(mem_ctx, &user_sid, &user_grpsids, + &num_groups); + } + /* work out the response size */ for (i = 0; i < num_groups; i++) { const char *s = sid_string_static(user_grpsids[i]); @@ -1145,12 +1255,12 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) } /* build the reply */ - ret = malloc(ret_size); + ret = SMB_MALLOC(ret_size); if (!ret) goto done; ofs = 0; for (i = 0; i < num_groups; i++) { const char *s = sid_string_static(user_grpsids[i]); - safe_strcpy(ret + ofs, s, ret_size - ofs); + safe_strcpy(ret + ofs, s, ret_size - ofs - 1); ofs += strlen(ret+ofs) + 1; }