diff options
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/winbindd.c | 3 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.h | 39 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_ads.c | 262 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 159 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 2 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_group.c | 114 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_idmap.c | 577 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_rpc.c | 150 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_user.c | 56 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_util.c | 40 |
10 files changed, 642 insertions, 760 deletions
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index b6e399153f..ff21a4644f 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -895,12 +895,13 @@ int main(int argc, char **argv) exit(1); } poptFreeContext(pc); - register_msg_pool_usage(); /* Loop waiting for requests */ process_loop(); + trustdom_cache_shutdown(); uni_group_cache_shutdown(); + return 0; } diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index ad0d6fbc3b..2d9a0b5949 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -4,6 +4,7 @@ Winbind daemon for ntdom nss module Copyright (C) Tim Potter 2000 + Copyright (C) Anthony Liguori 2003 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -65,7 +66,8 @@ struct getent_state { struct getpwent_user { fstring name; /* Account name */ fstring gecos; /* User information */ - uint32 user_rid, group_rid; /* NT user and group rids */ + DOM_SID user_sid; /* NT user and primary group SIDs */ + DOM_SID group_sid; }; /* Server state structure */ @@ -83,8 +85,8 @@ extern struct winbindd_state server_state; /* Server information */ typedef struct { char *acct_name; char *full_name; - uint32 user_rid; - uint32 group_rid; /* primary group */ + DOM_SID *user_sid; /* NT user and primary group SIDs */ + DOM_SID *group_sid; } WINBIND_USERINFO; /* Structures to hold per domain information */ @@ -140,6 +142,7 @@ struct winbindd_methods { /* convert one user or group name to a sid */ NTSTATUS (*name_to_sid)(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, const char *name, DOM_SID *sid, enum SID_NAME_USE *type); @@ -151,10 +154,10 @@ struct winbindd_methods { char **name, enum SID_NAME_USE *type); - /* lookup user info for a given rid */ + /* lookup user info for a given SID */ NTSTATUS (*query_user)(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, + DOM_SID *user_sid, WINBIND_USERINFO *user_info); /* lookup all groups that a user is a member of. The backend @@ -162,14 +165,15 @@ struct winbindd_methods { function */ NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, - uint32 *num_groups, uint32 **user_gids); + DOM_SID *user_sid, + uint32 *num_groups, DOM_SID ***user_gids); /* find all members of the group with the specified group_rid */ NTSTATUS (*lookup_groupmem)(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 group_rid, uint32 *num_names, - uint32 **rid_mem, char ***names, + DOM_SID *group_sid, + uint32 *num_names, + DOM_SID ***sid_mem, char ***names, uint32 **name_types); /* return the current global sequence number */ @@ -198,6 +202,23 @@ typedef struct { POLICY_HND pol; } CLI_POLICY_HND; +/* Filled out by IDMAP backends */ +struct winbindd_idmap_methods { + /* Called when backend is first loaded */ + BOOL (*init)(void); + + BOOL (*get_sid_from_uid)(uid_t uid, DOM_SID *sid); + BOOL (*get_sid_from_gid)(gid_t gid, DOM_SID *sid); + + BOOL (*get_uid_from_sid)(DOM_SID *sid, uid_t *uid); + BOOL (*get_gid_from_sid)(DOM_SID *sid, gid_t *gid); + + /* Called when backend is unloaded */ + BOOL (*close)(void); + /* Called to dump backend status */ + void (*status)(void); +}; + #include "winbindd_proto.h" #include "rpc_parse.h" diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index 63dc90bc28..beb40af79d 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -4,6 +4,7 @@ Winbind ADS backend functions Copyright (C) Andrew Tridgell 2001 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -88,13 +89,6 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) return ads; } -/* useful utility */ -static void sid_from_rid(struct winbindd_domain *domain, uint32 rid, DOM_SID *sid) -{ - sid_copy(sid, &domain->sid); - sid_append_rid(sid, rid); -} - /* Query display info for a realm. This is the basic user list fn */ static NTSTATUS query_user_list(struct winbindd_domain *domain, @@ -143,7 +137,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { char *name, *gecos; DOM_SID sid; - uint32 rid, group; + DOM_SID *sid2; + DOM_SID *group_sid; + uint32 group; uint32 atype; if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) || @@ -163,15 +159,20 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, continue; } - if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) { - DEBUG(1,("No rid for %s !?\n", name)); - continue; + sid2 = talloc(mem_ctx, sizeof(*sid2)); + if (!sid2) { + status = NT_STATUS_NO_MEMORY; + goto done; } + sid_copy(sid2, &sid); + + group_sid = rid_to_talloced_sid(domain, mem_ctx, group); + (*info)[i].acct_name = name; (*info)[i].full_name = gecos; - (*info)[i].user_rid = rid; - (*info)[i].group_rid = group; + (*info)[i].user_sid = sid2; + (*info)[i].group_sid = group_sid; i++; } @@ -296,6 +297,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, /* convert a single name to a sid in a domain */ static NTSTATUS name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, const char *name, DOM_SID *sid, enum SID_NAME_USE *type) @@ -328,13 +330,13 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, } -/* convert a DN to a name, rid and name type +/* convert a DN to a name, SID and name type this might become a major speed bottleneck if groups have lots of users, in which case we could cache the results */ static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *dn, - char **name, uint32 *name_type, uint32 *rid) + char **name, uint32 *name_type, DOM_SID *sid) { char *exp; void *res = NULL; @@ -342,7 +344,6 @@ static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, "objectSid", "sAMAccountType", NULL}; ADS_STATUS rc; uint32 atype; - DOM_SID sid; char *escaped_dn = escape_ldap_string_alloc(dn); if (!escaped_dn) { @@ -365,8 +366,7 @@ static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, } (*name_type) = ads_atype_map(atype); - if (!ads_pull_sid(ads, res, "objectSid", &sid) || - !sid_peek_rid(&sid, rid)) { + if (!ads_pull_sid(ads, res, "objectSid", sid)) { goto failed; } @@ -381,60 +381,63 @@ failed: /* Lookup user information from a rid */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, + DOM_SID *sid, WINBIND_USERINFO *info) { ADS_STRUCT *ads = NULL; const char *attrs[] = {"userPrincipalName", "sAMAccountName", - "name", "objectSid", + "name", "primaryGroupID", NULL}; ADS_STATUS rc; int count; void *msg = NULL; char *exp; - DOM_SID sid; char *sidstr; + uint32 group_rid; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + DOM_SID *sid2; + fstring sid_string; DEBUG(3,("ads: query_user\n")); - sid_from_rid(domain, user_rid, &sid); - ads = ads_cached_connection(domain); if (!ads) goto done; - sidstr = sid_binstring(&sid); + sidstr = sid_binstring(sid); asprintf(&exp, "(objectSid=%s)", sidstr); rc = ads_search_retry(ads, &msg, exp, attrs); free(exp); free(sidstr); if (!ADS_ERR_OK(rc)) { - DEBUG(1,("query_user(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc))); + DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc))); goto done; } count = ads_count_replies(ads, msg); if (count != 1) { - DEBUG(1,("query_user(rid=%d): Not found\n", user_rid)); + DEBUG(1,("query_user(sid=%s): Not found\n", sid_to_string(sid_string, sid))); goto done; } info->acct_name = ads_pull_username(ads, mem_ctx, msg); info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); - if (!ads_pull_sid(ads, msg, "objectSid", &sid)) { - DEBUG(1,("No sid for %d !?\n", user_rid)); - goto done; - } - if (!ads_pull_uint32(ads, msg, "primaryGroupID", &info->group_rid)) { - DEBUG(1,("No primary group for %d !?\n", user_rid)); + + if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { + DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid))); goto done; } - if (!sid_peek_check_rid(&domain->sid,&sid, &info->user_rid)) { - DEBUG(1,("No rid for %d !?\n", user_rid)); + sid2 = talloc(mem_ctx, sizeof(*sid2)); + if (!sid2) { + status = NT_STATUS_NO_MEMORY; goto done; } + sid_copy(sid2, sid); + + info->user_sid = sid2; + + info->group_sid = rid_to_talloced_sid(domain, mem_ctx, group_rid); status = NT_STATUS_OK; @@ -445,12 +448,91 @@ done: return status; } +/* Lookup groups a user is a member of - alternate method, for when + tokenGroups are not available. */ +static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_dn, + DOM_SID *primary_group, + uint32 *num_groups, DOM_SID ***user_gids) +{ + ADS_STATUS rc; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + int count; + void *res = NULL; + void *msg = NULL; + char *exp; + ADS_STRUCT *ads; + const char *group_attrs[] = {"objectSid", NULL}; + + ads = ads_cached_connection(domain); + if (!ads) goto done; + + /* buggy server, no tokenGroups. Instead lookup what groups this user + is a member of by DN search on member*/ + if (asprintf(&exp, "(&(member=%s)(objectClass=group))", user_dn) == -1) { + DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn)); + return NT_STATUS_NO_MEMORY; + } + + rc = ads_search_retry(ads, &res, exp, group_attrs); + free(exp); + + if (!ADS_ERR_OK(rc)) { + DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc))); + return ads_ntstatus(rc); + } + + count = ads_count_replies(ads, res); + if (count == 0) { + DEBUG(5,("lookup_usergroups: No supp groups found\n")); + + status = ads_ntstatus(rc); + goto done; + } + + (*user_gids) = talloc_zero(mem_ctx, sizeof(**user_gids) * (count + 1)); + (*user_gids)[0] = primary_group; + + *num_groups = 1; + + for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { + DOM_SID group_sid; + + if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) { + DEBUG(1,("No sid for this group ?!?\n")); + continue; + } + + if (sid_equal(&group_sid, primary_group)) continue; + + (*user_gids)[*num_groups] = talloc(mem_ctx, sizeof(***user_gids)); + if (!(*user_gids)[*num_groups]) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + sid_copy((*user_gids)[*num_groups], &group_sid); + + (*num_groups)++; + + } + + status = NT_STATUS_OK; + + DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn)); +done: + if (res) ads_msgfree(ads, res); + if (msg) ads_msgfree(ads, msg); + + return status; +} /* Lookup groups a user is a member of. */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, - uint32 *num_groups, uint32 **user_gids) + DOM_SID *sid, + uint32 *num_groups, DOM_SID ***user_gids) { ADS_STRUCT *ads = NULL; const char *attrs[] = {"distinguishedName", NULL}; @@ -462,63 +544,94 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, char *user_dn; DOM_SID *sids; int i; - uint32 primary_group; - DOM_SID sid; + DOM_SID *primary_group; + uint32 primary_group_rid; char *sidstr; + fstring sid_string; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - *num_groups = 0; - DEBUG(3,("ads: lookup_usergroups\n")); - - (*num_groups) = 0; - - sid_from_rid(domain, user_rid, &sid); + *num_groups = 0; ads = ads_cached_connection(domain); if (!ads) goto done; - sidstr = sid_binstring(&sid); - asprintf(&exp, "(objectSid=%s)", sidstr); + if (!(sidstr = sid_binstring(sid))) { + DEBUG(1,("lookup_usergroups(sid=%s) sid_binstring returned NULL\n", sid_to_string(sid_string, sid))); + status = NT_STATUS_NO_MEMORY; + goto done; + } + if (asprintf(&exp, "(objectSid=%s)", sidstr) == -1) { + free(sidstr); + DEBUG(1,("lookup_usergroups(sid=%s) asprintf failed!\n", sid_to_string(sid_string, sid))); + status = NT_STATUS_NO_MEMORY; + goto done; + } + rc = ads_search_retry(ads, &msg, exp, attrs); free(exp); free(sidstr); + if (!ADS_ERR_OK(rc)) { - DEBUG(1,("lookup_usergroups(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc))); + DEBUG(1,("lookup_usergroups(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc))); goto done; } user_dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName"); + if (!user_dn) { + DEBUG(1,("lookup_usergroups(sid=%s) ads_search did not return a a distinguishedName!\n", sid_to_string(sid_string, sid))); + if (msg) ads_msgfree(ads, msg); + goto done; + } if (msg) ads_msgfree(ads, msg); rc = ads_search_retry_dn(ads, &msg, user_dn, attrs2); if (!ADS_ERR_OK(rc)) { - DEBUG(1,("lookup_usergroups(rid=%d) ads_search tokenGroups: %s\n", user_rid, ads_errstr(rc))); + DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc))); goto done; } - if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group)) { - DEBUG(1,("%s: No primary group for rid=%d !?\n", domain->name, user_rid)); + if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) { + DEBUG(1,("%s: No primary group for sid=%s !?\n", domain->name, sid_to_string(sid_string, sid))); goto done; } - count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids) + 1; - (*user_gids) = (uint32 *)talloc_zero(mem_ctx, sizeof(uint32) * count); - (*user_gids)[(*num_groups)++] = primary_group; + primary_group = rid_to_talloced_sid(domain, mem_ctx, primary_group_rid); - for (i=1;i<count;i++) { - uint32 rid; - if (!sid_peek_check_rid(&domain->sid, &sids[i-1], &rid)) continue; - (*user_gids)[*num_groups] = rid; + count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids); + + if (msg) ads_msgfree(ads, msg); + + /* there must always be at least one group in the token, + unless we are talking to a buggy Win2k server */ + if (count == 0) { + return lookup_usergroups_alt(domain, mem_ctx, user_dn, + primary_group, + num_groups, user_gids); + } + + (*user_gids) = talloc_zero(mem_ctx, sizeof(**user_gids) * (count + 1)); + (*user_gids)[0] = primary_group; + + *num_groups = 1; + + for (i=0;i<count;i++) { + if (sid_equal(&sids[i], primary_group)) continue; + + (*user_gids)[*num_groups] = talloc(mem_ctx, sizeof(***user_gids)); + if (!(*user_gids)[*num_groups]) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + sid_copy((*user_gids)[*num_groups], &sids[i]); (*num_groups)++; } status = NT_STATUS_OK; - DEBUG(3,("ads lookup_usergroups for rid=%d\n", user_rid)); + DEBUG(3,("ads lookup_usergroups for sid=%s\n", sid_to_string(sid_string, sid))); done: - if (msg) ads_msgfree(ads, msg); - return status; } @@ -527,11 +640,10 @@ done: */ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 group_rid, uint32 *num_names, - uint32 **rid_mem, char ***names, + DOM_SID *group_sid, uint32 *num_names, + DOM_SID ***sid_mem, char ***names, uint32 **name_types) { - DOM_SID group_sid; ADS_STATUS rc; int count; void *res=NULL; @@ -542,14 +654,14 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, const char *attrs[] = {"member", NULL}; char **members; int i, num_members; + fstring sid_string; *num_names = 0; ads = ads_cached_connection(domain); if (!ads) goto done; - sid_from_rid(domain, group_rid, &group_sid); - sidstr = sid_binstring(&group_sid); + sidstr = sid_binstring(group_sid); /* search for all members of the group */ asprintf(&exp, "(objectSid=%s)",sidstr); @@ -581,24 +693,30 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, for (i=0;members[i];i++) /* noop */ ; num_members = i; - (*rid_mem) = talloc_zero(mem_ctx, sizeof(uint32) * num_members); - (*name_types) = talloc_zero(mem_ctx, sizeof(uint32) * num_members); - (*names) = talloc_zero(mem_ctx, sizeof(char *) * num_members); + (*sid_mem) = talloc_zero(mem_ctx, sizeof(**sid_mem) * num_members); + (*name_types) = talloc_zero(mem_ctx, sizeof(**name_types) * num_members); + (*names) = talloc_zero(mem_ctx, sizeof(**names) * num_members); for (i=0;i<num_members;i++) { - uint32 name_type, rid; + uint32 name_type; char *name; + DOM_SID sid; - if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &rid)) { + if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) { (*names)[*num_names] = name; (*name_types)[*num_names] = name_type; - (*rid_mem)[*num_names] = rid; + (*sid_mem)[*num_names] = talloc(mem_ctx, sizeof(***sid_mem)); + if (!(*sid_mem)[*num_names]) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + sid_copy((*sid_mem)[*num_names], &sid); (*num_names)++; } } status = NT_STATUS_OK; - DEBUG(3,("ads lookup_groupmem for rid=%d\n", group_rid)); + DEBUG(3,("ads lookup_groupmem for sid=%s\n", sid_to_string(sid_string, group_sid))); done: if (res) ads_msgfree(ads, res); diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 6ba1d48f5a..5eabcfca20 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -192,6 +192,23 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx) return ret; } +/* pull a string from a cache entry, using the supplied + talloc context +*/ +static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx) +{ + DOM_SID *sid; + char *sid_string; + sid = talloc(mem_ctx, sizeof(*sid)); + if (!sid) return NULL; + + sid_string = centry_string(centry, mem_ctx); + if (!string_to_sid(sid, sid_string)) { + return NULL; + } + return sid; +} + /* the server is considered down if it can't give us a sequence number */ static BOOL wcache_server_down(struct winbindd_domain *domain) { @@ -260,6 +277,9 @@ static BOOL centry_expired(struct winbindd_domain *domain, struct cache_entry *c */ static struct cache_entry *wcache_fetch(struct winbind_cache *cache, struct winbindd_domain *domain, + const char *format, ...) PRINTF_ATTRIBUTE(3,4); +static struct cache_entry *wcache_fetch(struct winbind_cache *cache, + struct winbindd_domain *domain, const char *format, ...) { va_list ap; @@ -370,6 +390,12 @@ static void centry_put_string(struct cache_entry *centry, const char *s) centry->ofs += len; } +static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid) +{ + fstring sid_string; + centry_put_string(centry, sid_to_string(sid_string, sid)); +} + /* start a centry for output. When finished, call centry_end() */ @@ -393,6 +419,7 @@ struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status /* finish a centry and write it to the tdb */ +static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3); static void centry_end(struct cache_entry *centry, const char *format, ...) { va_list ap; @@ -412,39 +439,29 @@ static void centry_end(struct cache_entry *centry, const char *format, ...) free(kstr); } -/* form a sid from the domain plus rid */ -static DOM_SID *form_sid(struct winbindd_domain *domain, uint32 rid) -{ - static DOM_SID sid; - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, rid); - return &sid; -} - -static void wcache_save_name_to_sid(struct winbindd_domain *domain, NTSTATUS status, - const char *name, DOM_SID *sid, enum SID_NAME_USE type) +static void wcache_save_name_to_sid(struct winbindd_domain *domain, + NTSTATUS status, + const char *name, DOM_SID *sid, + enum SID_NAME_USE type) { struct cache_entry *centry; - uint32 len; fstring uname; + fstring sid_string; centry = centry_start(domain, status); if (!centry) return; - len = sid_size(sid); - centry_expand(centry, len); - centry_put_uint32(centry, type); - sid_linearize(centry->data + centry->ofs, len, sid); - centry->ofs += len; + centry_put_sid(centry, sid); fstrcpy(uname, name); strupper(uname); - centry_end(centry, "NS/%s/%s", domain->name, uname); + centry_end(centry, "NS/%s", sid_to_string(sid_string, sid)); centry_free(centry); } static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, - DOM_SID *sid, const char *name, enum SID_NAME_USE type, uint32 rid) + DOM_SID *sid, const char *name, enum SID_NAME_USE type) { struct cache_entry *centry; + fstring sid_string; centry = centry_start(domain, status); if (!centry) return; @@ -452,7 +469,7 @@ static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS sta centry_put_uint32(centry, type); centry_put_string(centry, name); } - centry_end(centry, "SN/%s/%d", domain->name, rid); + centry_end(centry, "SN/%s", sid_to_string(sid_string, sid)); centry_free(centry); } @@ -460,14 +477,15 @@ static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS sta static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info) { struct cache_entry *centry; + fstring sid_string; centry = centry_start(domain, status); if (!centry) return; centry_put_string(centry, info->acct_name); centry_put_string(centry, info->full_name); - centry_put_uint32(centry, info->user_rid); - centry_put_uint32(centry, info->group_rid); - centry_end(centry, "U/%s/%d", domain->name, info->user_rid); + centry_put_sid(centry, info->user_sid); + centry_put_sid(centry, info->group_sid); + centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid)); centry_free(centry); } @@ -481,7 +499,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - int i; + unsigned int i; if (!cache->tdb) goto do_query; @@ -497,8 +515,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, for (i=0; i<(*num_entries); i++) { (*info)[i].acct_name = centry_string(centry, mem_ctx); (*info)[i].full_name = centry_string(centry, mem_ctx); - (*info)[i].user_rid = centry_uint32(centry); - (*info)[i].group_rid = centry_uint32(centry); + (*info)[i].user_sid = centry_sid(centry, mem_ctx); + (*info)[i].group_sid = centry_sid(centry, mem_ctx); } do_cached: @@ -524,18 +542,18 @@ do_query: for (i=0; i<(*num_entries); i++) { centry_put_string(centry, (*info)[i].acct_name); centry_put_string(centry, (*info)[i].full_name); - centry_put_uint32(centry, (*info)[i].user_rid); - centry_put_uint32(centry, (*info)[i].group_rid); + centry_put_sid(centry, (*info)[i].user_sid); + centry_put_sid(centry, (*info)[i].group_sid); if (cache->backend->consistent) { /* when the backend is consistent we can pre-prime some mappings */ wcache_save_name_to_sid(domain, NT_STATUS_OK, (*info)[i].acct_name, - form_sid(domain, (*info)[i].user_rid), + (*info)[i].user_sid, SID_NAME_USER); wcache_save_sid_to_name(domain, NT_STATUS_OK, - form_sid(domain, (*info)[i].user_rid), + (*info)[i].user_sid, (*info)[i].acct_name, - SID_NAME_USER, (*info)[i].user_rid); + SID_NAME_USER); wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]); } } @@ -555,7 +573,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - int i; + unsigned int i; if (!cache->tdb) goto do_query; @@ -615,7 +633,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - int i; + unsigned int i; if (!cache->tdb) goto do_query; @@ -669,7 +687,7 @@ do_query: centry_put_string(centry, (*info)[i].acct_name); centry_put_string(centry, (*info)[i].acct_desc); centry_put_uint32(centry, (*info)[i].rid); - } + } centry_end(centry, "GL/%s/local", domain->name); centry_free(centry); @@ -679,6 +697,7 @@ skip_save: /* convert a single name to a sid in a domain */ static NTSTATUS name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, const char *name, DOM_SID *sid, enum SID_NAME_USE *type) @@ -687,6 +706,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, struct cache_entry *centry = NULL; NTSTATUS status; fstring uname; + DOM_SID *sid2; if (!cache->tdb) goto do_query; @@ -695,7 +715,12 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, centry = wcache_fetch(cache, domain, "NS/%s/%s", domain->name, uname); if (!centry) goto do_query; *type = centry_uint32(centry); - sid_parse(centry->data + centry->ofs, centry->len - centry->ofs, sid); + sid2 = centry_sid(centry, mem_ctx); + if (!sid2) { + ZERO_STRUCTP(sid); + } else { + sid_copy(sid, sid2); + } status = centry->status; centry_free(centry); @@ -707,7 +732,7 @@ do_query: if (wcache_server_down(domain)) { return NT_STATUS_SERVER_DISABLED; } - status = cache->backend->name_to_sid(domain, name, sid, type); + status = cache->backend->name_to_sid(domain, mem_ctx, name, sid, type); /* and save it */ wcache_save_name_to_sid(domain, status, name, sid, *type); @@ -729,14 +754,11 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - uint32 rid = 0; - - if (!sid_peek_check_rid(&domain->sid, sid, &rid)) - return NT_STATUS_INVALID_PARAMETER; + fstring sid_string; if (!cache->tdb) goto do_query; - centry = wcache_fetch(cache, domain, "SN/%s/%d", domain->name, rid); + centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid)); if (!centry) goto do_query; if (NT_STATUS_IS_OK(centry->status)) { *type = centry_uint32(centry); @@ -756,7 +778,7 @@ do_query: /* and save it */ refresh_sequence_number(domain, True); - wcache_save_sid_to_name(domain, status, sid, *name, *type, rid); + wcache_save_sid_to_name(domain, status, sid, *name, *type); wcache_save_name_to_sid(domain, status, *name, sid, *type); return status; @@ -766,22 +788,23 @@ do_query: /* Lookup user information from a rid */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, + DOM_SID *user_sid, WINBIND_USERINFO *info) { struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; + fstring sid_string; if (!cache->tdb) goto do_query; - centry = wcache_fetch(cache, domain, "U/%s/%d", domain->name, user_rid); + centry = wcache_fetch(cache, domain, "U/%s", sid_to_string(sid_string, user_sid)); if (!centry) goto do_query; info->acct_name = centry_string(centry, mem_ctx); info->full_name = centry_string(centry, mem_ctx); - info->user_rid = centry_uint32(centry); - info->group_rid = centry_uint32(centry); + info->user_sid = centry_sid(centry, mem_ctx); + info->group_sid = centry_sid(centry, mem_ctx); status = centry->status; centry_free(centry); return status; @@ -793,7 +816,7 @@ do_query: return NT_STATUS_SERVER_DISABLED; } - status = cache->backend->query_user(domain, mem_ctx, user_rid, info); + status = cache->backend->query_user(domain, mem_ctx, user_sid, info); /* and save it */ refresh_sequence_number(domain, True); @@ -806,17 +829,18 @@ do_query: /* Lookup groups a user is a member of. */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, - uint32 *num_groups, uint32 **user_gids) + DOM_SID *user_sid, + uint32 *num_groups, DOM_SID ***user_gids) { struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - int i; + unsigned int i; + fstring sid_string; if (!cache->tdb) goto do_query; - centry = wcache_fetch(cache, domain, "UG/%s/%d", domain->name, user_rid); + centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid)); if (!centry) goto do_query; *num_groups = centry_uint32(centry); @@ -826,7 +850,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, (*user_gids) = talloc(mem_ctx, sizeof(**user_gids) * (*num_groups)); if (! (*user_gids)) smb_panic("lookup_usergroups out of memory"); for (i=0; i<(*num_groups); i++) { - (*user_gids)[i] = centry_uint32(centry); + (*user_gids)[i] = centry_sid(centry, mem_ctx); } do_cached: @@ -841,7 +865,7 @@ do_query: if (wcache_server_down(domain)) { return NT_STATUS_SERVER_DISABLED; } - status = cache->backend->lookup_usergroups(domain, mem_ctx, user_rid, num_groups, user_gids); + status = cache->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids); /* and save it */ refresh_sequence_number(domain, True); @@ -849,9 +873,9 @@ do_query: if (!centry) goto skip_save; centry_put_uint32(centry, *num_groups); for (i=0; i<(*num_groups); i++) { - centry_put_uint32(centry, (*user_gids)[i]); + centry_put_sid(centry, (*user_gids)[i]); } - centry_end(centry, "UG/%s/%d", domain->name, user_rid); + centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid)); centry_free(centry); skip_save: @@ -861,34 +885,35 @@ skip_save: static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 group_rid, uint32 *num_names, - uint32 **rid_mem, char ***names, + DOM_SID *group_sid, uint32 *num_names, + DOM_SID ***sid_mem, char ***names, uint32 **name_types) { struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - int i; + unsigned int i; + fstring sid_string; if (!cache->tdb) goto do_query; - centry = wcache_fetch(cache, domain, "GM/%s/%d", domain->name, group_rid); + centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid)); if (!centry) goto do_query; *num_names = centry_uint32(centry); if (*num_names == 0) goto do_cached; - (*rid_mem) = talloc(mem_ctx, sizeof(**rid_mem) * (*num_names)); + (*sid_mem) = talloc(mem_ctx, sizeof(**sid_mem) * (*num_names)); (*names) = talloc(mem_ctx, sizeof(**names) * (*num_names)); (*name_types) = talloc(mem_ctx, sizeof(**name_types) * (*num_names)); - if (! (*rid_mem) || ! (*names) || ! (*name_types)) { + if (! (*sid_mem) || ! (*names) || ! (*name_types)) { smb_panic("lookup_groupmem out of memory"); } for (i=0; i<(*num_names); i++) { - (*rid_mem)[i] = centry_uint32(centry); + (*sid_mem)[i] = centry_sid(centry, mem_ctx); (*names)[i] = centry_string(centry, mem_ctx); (*name_types)[i] = centry_uint32(centry); } @@ -900,7 +925,7 @@ do_cached: do_query: (*num_names) = 0; - (*rid_mem) = NULL; + (*sid_mem) = NULL; (*names) = NULL; (*name_types) = NULL; @@ -908,8 +933,8 @@ do_query: if (wcache_server_down(domain)) { return NT_STATUS_SERVER_DISABLED; } - status = cache->backend->lookup_groupmem(domain, mem_ctx, group_rid, num_names, - rid_mem, names, name_types); + status = cache->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names, + sid_mem, names, name_types); /* and save it */ refresh_sequence_number(domain, True); @@ -917,11 +942,11 @@ do_query: if (!centry) goto skip_save; centry_put_uint32(centry, *num_names); for (i=0; i<(*num_names); i++) { - centry_put_uint32(centry, (*rid_mem)[i]); + centry_put_sid(centry, (*sid_mem)[i]); centry_put_string(centry, (*names)[i]); centry_put_uint32(centry, (*name_types)[i]); } - centry_end(centry, "GM/%s/%d", domain->name, group_rid); + centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid)); centry_free(centry); skip_save: diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 7502f3696b..dbcfdcf88f 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -373,7 +373,7 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index, } result = cli_full_connection(&new_conn->cli, global_myname(), new_conn->controller, - &dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain, + &dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain, ipc_password, CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, &retry); secrets_named_mutex_release(new_conn->controller); diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 94a826fbbc..d06db5943c 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -49,43 +49,44 @@ static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name, return True; } -/* Fill in the group membership field of a NT group given by group_rid */ +/* Fill in the group membership field of a NT group given by group_sid */ static BOOL fill_grent_mem(struct winbindd_domain *domain, - uint32 group_rid, + DOM_SID *group_sid, enum SID_NAME_USE group_name_type, int *num_gr_mem, char **gr_mem, int *gr_mem_len) { - uint32 *rid_mem = NULL, num_names = 0; + DOM_SID **sid_mem = NULL; + uint32 num_names = 0; uint32 *name_types = NULL; - int buf_len, buf_ndx, i; + unsigned int buf_len, buf_ndx, i; char **names = NULL, *buf; BOOL result = False; TALLOC_CTX *mem_ctx; NTSTATUS status; + fstring sid_string; if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name))) return False; /* Initialise group membership information */ - DEBUG(10, ("group %s rid 0x%x\n", domain ? domain->name : "NULL", - group_rid)); + DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid))); *num_gr_mem = 0; if (group_name_type != SID_NAME_DOM_GRP) { - DEBUG(1, ("rid %d in domain %s isn't a domain group\n", - group_rid, domain->name)); + DEBUG(1, ("SID %s in domain %s isn't a domain group\n", + sid_to_string(sid_string, group_sid), domain->name)); goto done; } /* Lookup group members */ - status = domain->methods->lookup_groupmem(domain, mem_ctx, group_rid, &num_names, - &rid_mem, &names, &name_types); + status = domain->methods->lookup_groupmem(domain, mem_ctx, group_sid, &num_names, + &sid_mem, &names, &name_types); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("could not lookup membership for group rid %d in domain %s (error: %s)\n", - group_rid, domain->name, nt_errstr(status))); + DEBUG(1, ("could not lookup membership for group rid %s in domain %s (error: %s)\n", + sid_to_string(sid_string, group_sid), domain->name, nt_errstr(status))); goto done; } @@ -94,7 +95,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, if (DEBUGLEVEL >= 10) { for (i = 0; i < num_names; i++) - DEBUG(10, ("\t%20s %x %d\n", names[i], rid_mem[i], + DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]), name_types[i])); } @@ -190,7 +191,6 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) DOM_SID group_sid; struct winbindd_domain *domain; enum SID_NAME_USE name_type; - uint32 group_rid; fstring name_domain, name_group; char *tmp, *gr_mem; gid_t gid; @@ -233,10 +233,6 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - /* Fill in group structure */ - if (!sid_peek_check_rid(&domain->sid, &group_sid, &group_rid)) - return WINBINDD_ERROR; - if (!winbindd_idmap_get_gid_from_sid(&group_sid, &gid)) { DEBUG(1, ("error converting unix gid to sid\n")); return WINBINDD_ERROR; @@ -244,7 +240,7 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) if (!fill_grent(&state->response.data.gr, name_domain, name_group, gid) || - !fill_grent_mem(domain, group_rid, name_type, + !fill_grent_mem(domain, &group_sid, name_type, &state->response.data.gr.num_gr_mem, &gr_mem, &gr_mem_len)) { return WINBINDD_ERROR; @@ -269,7 +265,6 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) enum SID_NAME_USE name_type; fstring dom_name; fstring group_name; - uint32 group_rid; int gr_mem_len; char *gr_mem; @@ -284,17 +279,13 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) /* Get rid from gid */ - if (!winbindd_idmap_get_rid_from_gid(state->request.data.gid, - &group_rid, &domain)) { + if (!winbindd_idmap_get_sid_from_gid(state->request.data.gid, &group_sid)) { DEBUG(1, ("could not convert gid %d to rid\n", state->request.data.gid)); return WINBINDD_ERROR; } - /* Get sid from gid */ - - sid_copy(&group_sid, &domain->sid); - sid_append_rid(&group_sid, group_rid); + /* Get name from sid */ if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) { DEBUG(1, ("could not lookup sid\n")); @@ -310,9 +301,16 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) /* Fill in group structure */ + domain = find_domain_from_sid(&group_sid); + + if (!domain) { + DEBUG(1,("Can't find domain from sid\n")); + return WINBINDD_ERROR; + } + if (!fill_grent(&state->response.data.gr, dom_name, group_name, state->request.data.gid) || - !fill_grent_mem(domain, group_rid, name_type, + !fill_grent_mem(domain, &group_sid, name_type, &state->response.data.gr.num_gr_mem, &gr_mem, &gr_mem_len)) return WINBINDD_ERROR; @@ -544,7 +542,9 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) gid_t group_gid; int gr_mem_len; char *gr_mem, *new_gr_mem_list; - + DOM_SID group_sid; + struct winbindd_domain *domain; + /* Do we need to fetch another chunk of groups? */ tryagain: @@ -578,16 +578,25 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) name_list = ent->sam_entries; + if (!(domain = + find_domain_from_name(ent->domain_name))) { + DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name)); + result = False; + goto done; + } + /* Lookup group info */ - if (!winbindd_idmap_get_gid_from_rid( - ent->domain_name, - name_list[ent->sam_entry_index].rid, - &group_gid)) { + sid_copy(&group_sid, &domain->sid); + sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid); + + if (!winbindd_idmap_get_gid_from_sid( + &group_sid, + &group_gid)) { DEBUG(1, ("could not look up gid for group %s\n", name_list[ent->sam_entry_index].acct_name)); - + ent->sam_entry_index++; goto tryagain; } @@ -608,15 +617,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) /* Fill in group membership entry */ if (result) { - struct winbindd_domain *domain; - - if (!(domain = - find_domain_from_name(ent->domain_name))) { - DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name)); - result = False; - goto done; - } - + DOM_SID member_sid; group_list[group_list_ndx].num_gr_mem = 0; gr_mem = NULL; gr_mem_len = 0; @@ -625,9 +626,11 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) if (state->request.cmd == WINBINDD_GETGRLST) { result = True; } else { + sid_copy(&member_sid, &domain->sid); + sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid); result = fill_grent_mem( domain, - name_list[ent->sam_entry_index].rid, + &member_sid, SID_NAME_DOM_GRP, &group_list[group_list_ndx].num_gr_mem, &gr_mem, &gr_mem_len); @@ -730,7 +733,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) struct winbindd_domain *domain; char *extra_data = NULL; char *ted = NULL; - int extra_data_len = 0, i; + unsigned int extra_data_len = 0, i; DEBUG(3, ("[%5d]: list groups\n", state->pid)); @@ -805,13 +808,13 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) fstring name_domain, name_user; DOM_SID user_sid; enum SID_NAME_USE name_type; - uint32 user_rid, num_groups, num_gids; + uint32 num_groups, num_gids; NTSTATUS status; - uint32 *user_gids; + DOM_SID **user_gids; struct winbindd_domain *domain; enum winbindd_result result = WINBINDD_ERROR; gid_t *gid_list; - int i; + unsigned int i; TALLOC_CTX *mem_ctx; /* Ensure null termination */ @@ -852,9 +855,9 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; } - sid_split_rid(&user_sid, &user_rid); - - status = domain->methods->lookup_usergroups(domain, mem_ctx, user_rid, &num_groups, &user_gids); + status = domain->methods->lookup_usergroups(domain, mem_ctx, + &user_sid, &num_groups, + &user_gids); if (!NT_STATUS_IS_OK(status)) goto done; /* Copy data back to client */ @@ -866,12 +869,13 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; for (i = 0; i < num_groups; i++) { - if (!winbindd_idmap_get_gid_from_rid(domain->name, - user_gids[i], - &gid_list[num_gids])) { + if (!winbindd_idmap_get_gid_from_sid( + user_gids[i], + &gid_list[num_gids])) { + fstring sid_string; - DEBUG(1, ("unable to convert group rid %d to gid\n", - user_gids[i])); + DEBUG(1, ("unable to convert group sid %s to gid\n", + sid_to_string(sid_string, user_gids[i]))); continue; } diff --git a/source3/nsswitch/winbindd_idmap.c b/source3/nsswitch/winbindd_idmap.c index 6d184fec5f..3b23089200 100644 --- a/source3/nsswitch/winbindd_idmap.c +++ b/source3/nsswitch/winbindd_idmap.c @@ -1,20 +1,19 @@ /* Unix SMB/CIFS implementation. - - Winbind daemon - user related function - + Winbind ID Mapping Copyright (C) Tim Potter 2000 - + Copyright (C) Anthony Liguori <aliguor@us.ibm.com> 2003 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -22,508 +21,174 @@ #include "winbindd.h" -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_WINBIND - -/* High water mark keys */ +static struct { + const char *name; + /* Function to create a member of the idmap_methods list */ + BOOL (*reg_meth)(struct winbindd_idmap_methods **methods); + struct winbindd_idmap_methods *methods; +} builtin_winbindd_idmap_functions[] = { + { "tdb", winbind_idmap_reg_tdb, NULL }, + { NULL, NULL, NULL } +}; -#define HWM_GROUP "GROUP HWM" -#define HWM_USER "USER HWM" +/* singleton pattern: uberlazy evaluation */ +static struct winbindd_idmap_methods *impl; -/* idmap version determines auto-conversion */ -#define IDMAP_VERSION 2 - -/* Globals */ - -static TDB_CONTEXT *idmap_tdb; - -/* Allocate either a user or group id from the pool */ - -static BOOL allocate_id(uid_t *id, BOOL isgroup) +static struct winbindd_idmap_methods *get_impl(const char *name) { - int hwm; + int i = 0; + struct winbindd_idmap_methods *ret = NULL; - /* Get current high water mark */ + while (builtin_winbindd_idmap_functions[i].name && + strcmp(builtin_winbindd_idmap_functions[i].name, name)) { + i++; + } - if ((hwm = tdb_fetch_int32(idmap_tdb, - isgroup ? HWM_GROUP : HWM_USER)) == -1) { - return False; + if (builtin_winbindd_idmap_functions[i].name) { + if (!builtin_winbindd_idmap_functions[i].methods) { + builtin_winbindd_idmap_functions[i].reg_meth(&builtin_winbindd_idmap_functions[i].methods); } - /* Return next available uid in list */ - - if ((isgroup && (hwm > server_state.gid_high)) || - (!isgroup && (hwm > server_state.uid_high))) { - DEBUG(0, ("winbind %sid range full!\n", isgroup ? "g" : "u")); - return False; - } + ret = builtin_winbindd_idmap_functions[i].methods; + } - if (id) { - *id = hwm; - } - - hwm++; - - /* Store new high water mark */ - - tdb_store_int32(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm); - - return True; + return ret; } -/* Get an id from a rid */ -static BOOL get_id_from_sid(DOM_SID *sid, uid_t *id, BOOL isgroup) +/* Initialize backend */ +BOOL winbindd_idmap_init(void) { - TDB_DATA data, key; - fstring keystr; - BOOL result = False; - - /* Check if sid is present in database */ - sid_to_string(keystr, sid); - - key.dptr = keystr; - key.dsize = strlen(keystr) + 1; - - data = tdb_fetch(idmap_tdb, key); - - if (data.dptr) { - fstring scanstr; - int the_id; - - /* Parse and return existing uid */ - fstrcpy(scanstr, isgroup ? "GID" : "UID"); - fstrcat(scanstr, " %d"); - - if (sscanf(data.dptr, scanstr, &the_id) == 1) { - /* Store uid */ - if (id) { - *id = the_id; - } + BOOL ret = False; - result = True; - } + DEBUG(3, ("winbindd_idmap_init: using '%s' as backend\n", + lp_winbind_backend())); - SAFE_FREE(data.dptr); - } else { - - /* Allocate a new id for this sid */ - - if (id && allocate_id(id, isgroup)) { - fstring keystr2; - - /* Store new id */ - - slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" : "UID", *id); - - data.dptr = keystr2; - data.dsize = strlen(keystr2) + 1; - - tdb_store(idmap_tdb, key, data, TDB_REPLACE); - tdb_store(idmap_tdb, data, key, TDB_REPLACE); - - result = True; - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); } + } - return result; -} + if (impl) { + ret = impl->init(); + } -/* Get a uid from a user sid */ -BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid) -{ - return get_id_from_sid(sid, uid, False); -} + DEBUG(3, ("winbind_idmap_init: returning %s\n", ret ? "true" : "false")); -/* Get a gid from a group sid */ -BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid) -{ - return get_id_from_sid(sid, gid, True); + return ret; } -/* Get a uid from a user rid */ -BOOL winbindd_idmap_get_uid_from_rid(const char *dom_name, uint32 rid, uid_t *uid) +/* Get UID from SID */ +BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid) { - struct winbindd_domain *domain; - DOM_SID sid; + BOOL ret = False; - if (!(domain = find_domain_from_name(dom_name))) { - return False; - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, rid); + if (impl) { + ret = impl->get_uid_from_sid(sid, uid); + } - return get_id_from_sid(&sid, uid, False); + return ret; } -/* Get a gid from a group rid */ -BOOL winbindd_idmap_get_gid_from_rid(const char *dom_name, uint32 rid, gid_t *gid) +/* Get GID from SID */ +BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid) { - struct winbindd_domain *domain; - DOM_SID sid; + BOOL ret = False; - if (!(domain = find_domain_from_name(dom_name))) { - return False; - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, rid); + if (impl) { + ret = impl->get_gid_from_sid(sid, gid); + } - return get_id_from_sid(&sid, gid, True); + return ret; } - -BOOL get_sid_from_id(int id, DOM_SID *sid, BOOL isgroup) +/* Get SID from UID */ +BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid) { - TDB_DATA key, data; - fstring keystr; - BOOL result = False; - - slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id); - - key.dptr = keystr; - key.dsize = strlen(keystr) + 1; + BOOL ret = False; - data = tdb_fetch(idmap_tdb, key); - - if (data.dptr) { - result = string_to_sid(sid, data.dptr); - SAFE_FREE(data.dptr); + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); } + } - return result; -} + if (impl) { + ret = impl->get_sid_from_uid(uid, sid); + } -/* Get a sid from a uid */ -BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid) -{ - return get_sid_from_id((int)uid, sid, False); + return ret; } -/* Get a sid from a gid */ +/* Get SID from GID */ BOOL winbindd_idmap_get_sid_from_gid(gid_t gid, DOM_SID *sid) { - return get_sid_from_id((int)gid, sid, True); -} - -/* Get a user rid from a uid */ -BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid, - struct winbindd_domain **domain) -{ - DOM_SID sid; - - if (!get_sid_from_id((int)uid, &sid, False)) { - return False; - } + BOOL ret = False; - *domain = find_domain_from_sid(&sid); - if (! *domain) return False; + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } - sid_split_rid(&sid, user_rid); + if (impl) { + ret = impl->get_sid_from_gid(gid, sid); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } - return True; -} - -/* Get a group rid from a gid */ - -BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid, - struct winbindd_domain **domain) -{ - DOM_SID sid; - - if (!get_sid_from_id((int)gid, &sid, True)) { - return False; - } - - *domain = find_domain_from_sid(&sid); - if (! *domain) return False; - - sid_split_rid(&sid, group_rid); - - return True; -} - -/* convert one record to the new format */ -static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *ignored) -{ - struct winbindd_domain *domain; - char *p; - DOM_SID sid; - uint32 rid; - fstring keystr; - fstring dom_name; - TDB_DATA key2; - - p = strchr(key.dptr, '/'); - if (!p) - return 0; - - *p = 0; - fstrcpy(dom_name, key.dptr); - *p++ = '/'; - - domain = find_domain_from_name(dom_name); - if (!domain) { - /* We must delete the old record. */ - DEBUG(0,("winbindd: convert_fn : Unable to find domain %s\n", dom_name )); - DEBUG(0,("winbindd: convert_fn : deleting record %s\n", key.dptr )); - tdb_delete(idmap_tdb, key); - return 0; - } - - rid = atoi(p); - - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, rid); - - sid_to_string(keystr, &sid); - key2.dptr = keystr; - key2.dsize = strlen(keystr) + 1; - - if (tdb_store(idmap_tdb, key2, data, TDB_INSERT) != 0) { - /* not good! */ - DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", key2.dptr )); - DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n")); - return -1; - } - - if (tdb_store(idmap_tdb, data, key2, TDB_REPLACE) != 0) { - /* not good! */ - DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", data.dptr )); - DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n")); - return -1; - } - - tdb_delete(idmap_tdb, key); - - return 0; -} - -#if 0 -/***************************************************************************** - Make a backup copy of the old idmap just to be safe.... JRA. -*****************************************************************************/ - -static BOOL backup_old_idmap(const char *idmap_name) -{ - pstring new_name; - int outfd = -1; - SMB_OFF_T size; - struct stat st; - - pstrcpy(new_name, idmap_name); - pstrcat(new_name, ".bak"); - - DEBUG(10,("backup_old_idmap: backing up %s to %s before upgrade.\n", - idmap_name, new_name )); - - if (tdb_lockall(idmap_tdb) == -1) { - DEBUG(10,("backup_old_idmap: failed to lock %s. Error %s\n", - idmap_name, tdb_errorstr(idmap_tdb) )); - return False; - } - if ((outfd = open(new_name, O_CREAT|O_EXCL|O_RDWR, 0600)) == -1) { - DEBUG(10,("backup_old_idmap: failed to open %s. Error %s\n", - new_name, strerror(errno) )); - goto fail; - } - - if (fstat(idmap_tdb->fd, &st) == -1) { - DEBUG(10,("backup_old_idmap: failed to fstat %s. Error %s\n", - idmap_name, strerror(errno) )); - goto fail; - } - - size = (SMB_OFF_T)st.st_size; - - if (transfer_file(idmap_tdb->fd, outfd, size) != size ) { - DEBUG(10,("backup_old_idmap: failed to copy %s. Error %s\n", - idmap_name, strerror(errno) )); - goto fail; - } - - if (close(outfd) == -1) { - DEBUG(10,("backup_old_idmap: failed to close %s. Error %s\n", - idmap_name, strerror(errno) )); - outfd = -1; - goto fail; - } - tdb_unlockall(idmap_tdb); - return True; - -fail: - - if (outfd != -1) - close(outfd); - tdb_unlockall(idmap_tdb); - return False; -} -#endif - -/***************************************************************************** - Convert the idmap database from an older version. -*****************************************************************************/ - -static BOOL idmap_convert(const char *idmap_name) -{ - int32 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION"); - BOOL bigendianheader = (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False; - - if (vers == IDMAP_VERSION) - return True; - -#if 0 - /* Make a backup copy before doing anything else.... */ - if (!backup_old_idmap(idmap_name)) - return False; -#endif - - if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) { - /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */ - /* - * high and low records were created on a - * big endian machine and will need byte-reversing. - */ - - int32 wm; - - wm = tdb_fetch_int32(idmap_tdb, HWM_USER); - - if (wm != -1) { - wm = IREV(wm); - } else - wm = server_state.uid_low; - - if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) { - DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n")); - return False; - } - - wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP); - if (wm != -1) { - wm = IREV(wm); - } else - wm = server_state.gid_low; - - if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) { - DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n")); - return False; - } - } - - /* the old format stored as DOMAIN/rid - now we store the SID direct */ - tdb_traverse(idmap_tdb, convert_fn, NULL); - - if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) { - DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n")); - return False; - } - - return True; -} - -/***************************************************************************** - Initialise idmap database. -*****************************************************************************/ - -BOOL winbindd_idmap_init(void) -{ - /* Open tdb cache */ - - if (!(idmap_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0, - TDB_DEFAULT, O_RDWR | O_CREAT, 0600))) { - DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n")); - return False; - } - - /* possibly convert from an earlier version */ - if (!idmap_convert(lock_path("winbindd_idmap.tdb"))) { - DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n")); - return False; - } - - /* Create high water marks for group and user id */ - - if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) { - if (tdb_store_int32(idmap_tdb, HWM_USER, server_state.uid_low) == -1) { - DEBUG(0, ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n")); - return False; - } - } - - if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) { - if (tdb_store_int32(idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) { - DEBUG(0, ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n")); - return False; - } - } - - return True; + return ret; } +/* Close backend */ BOOL winbindd_idmap_close(void) { - if (idmap_tdb) - return (tdb_close(idmap_tdb) == 0); - return True; -} + BOOL ret = False; -/* Dump status information to log file. Display different stuff based on - the debug level: + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } - Debug Level Information Displayed - ================================================================= - 0 Percentage of [ug]id range allocated - 0 High water marks (next allocated ids) -*/ + if (impl) { + ret = impl->close(); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } -#define DUMP_INFO 0 + return ret; +} +/* Dump backend status */ void winbindd_idmap_status(void) { - int user_hwm, group_hwm; - - DEBUG(0, ("winbindd idmap status:\n")); - - /* Get current high water marks */ - - if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) { - DEBUG(DUMP_INFO, ("\tCould not get userid high water mark!\n")); - } - - if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) { - DEBUG(DUMP_INFO, ("\tCould not get groupid high water mark!\n")); - } - - /* Display next ids to allocate */ - - if (user_hwm != -1) { - DEBUG(DUMP_INFO, ("\tNext userid to allocate is %d\n", user_hwm)); - } - - if (group_hwm != -1) { - DEBUG(DUMP_INFO, ("\tNext groupid to allocate is %d\n", group_hwm)); - } - - /* Display percentage of id range already allocated. */ - - if (user_hwm != -1) { - int num_users = user_hwm - server_state.uid_low; - int total_users = server_state.uid_high - server_state.uid_low; - - DEBUG(DUMP_INFO, ("\tUser id range is %d%% full (%d of %d)\n", - num_users * 100 / total_users, num_users, - total_users)); - } - - if (group_hwm != -1) { - int num_groups = group_hwm - server_state.gid_low; - int total_groups = server_state.gid_high - server_state.gid_low; - - DEBUG(DUMP_INFO, ("\tGroup id range is %d%% full (%d of %d)\n", - num_groups * 100 / total_groups, num_groups, - total_groups)); - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } - /* Display complete mapping of users and groups to rids */ + if (impl) { + impl->status(); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } } diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c index 48f528f520..9ec35617f1 100644 --- a/source3/nsswitch/winbindd_rpc.c +++ b/source3/nsswitch/winbindd_rpc.c @@ -3,7 +3,7 @@ Winbind rpc backend functions - Copyright (C) Tim Potter 2000-2001 + Copyright (C) Tim Potter 2000-2001,2003 Copyright (C) Andrew Tridgell 2001 This program is free software; you can redistribute it and/or modify @@ -26,6 +26,7 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND + /* Query display info for a domain. This returns enough information plus a bit extra to give an overview of domain users for the User Manager application. */ @@ -39,18 +40,17 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, POLICY_HND dom_pol; BOOL got_dom_pol = False; uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; - int i, loop_count = 0; - int retry; + unsigned int i, start_idx, retry; DEBUG(3,("rpc: query_user_list\n")); *num_entries = 0; *info = NULL; - /* Get sam handle */ - retry = 0; do { + /* Get sam handle */ + if (!(hnd = cm_get_sam_handle(domain->name))) goto done; @@ -66,50 +66,39 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, got_dom_pol = True; - i = 0; + i = start_idx = 0; do { - SAM_DISPINFO_CTR ctr; - SAM_DISPINFO_1 info1; - uint32 count = 0, start=i, max_entries, max_size; - int j; TALLOC_CTX *ctx2; + char **dom_users; + uint32 num_dom_users, *dom_rids, j, size = 0xffff; + uint16 acb_mask = ACB_NORMAL; - ctr.sam.info1 = &info1; - - ctx2 = talloc_init("winbindd dispinfo"); - if (!ctx2) { + if (!(ctx2 = talloc_init("winbindd enum_users"))) { result = NT_STATUS_NO_MEMORY; goto done; - } - - get_query_dispinfo_params( - loop_count, &max_entries, &max_size); + } - /* Query display info level 1 */ - result = cli_samr_query_dispinfo( - hnd->cli, ctx2, &dom_pol, &start, 1, &count, - max_entries, max_size, &ctr); + result = cli_samr_enum_dom_users( + hnd->cli, ctx2, &dom_pol, &start_idx, acb_mask, + size, &dom_users, &dom_rids, &num_dom_users); - loop_count++; + *num_entries += num_dom_users; - if (!NT_STATUS_IS_OK(result) && - !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break; + *info = talloc_realloc( + mem_ctx, *info, + (*num_entries) * sizeof(WINBIND_USERINFO)); - (*num_entries) += count; - - /* now map the result into the WINBIND_USERINFO structure */ - (*info) = talloc_realloc(mem_ctx, *info, - (*num_entries)*sizeof(WINBIND_USERINFO)); if (!(*info)) { result = NT_STATUS_NO_MEMORY; talloc_destroy(ctx2); goto done; } - for (j=0;j<count;i++, j++) { - (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name); - (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name); - (*info)[i].user_rid = info1.sam[j].rid_user; + for (j = 0; j < num_dom_users; i++, j++) { + (*info)[i].acct_name = + talloc_strdup(mem_ctx, dom_users[j]); + (*info)[i].full_name = talloc_strdup(mem_ctx, ""); + (*info)[i].user_sid = rid_to_talloced_sid(domain, mem_ctx, dom_rids[j]); /* For the moment we set the primary group for every user to be the Domain Users group. There are serious problems with determining @@ -117,10 +106,14 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, This should really be made into a 'winbind force group' smb.conf parameter or something like that. */ - (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS; + (*info)[i].group_sid + = rid_to_talloced_sid(domain, + mem_ctx, + DOMAIN_GROUP_RID_USERS); } talloc_destroy(ctx2); + } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)); done: @@ -263,11 +256,11 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, /* convert a single name to a sid in a domain */ static NTSTATUS name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, const char *name, DOM_SID *sid, enum SID_NAME_USE *type) { - TALLOC_CTX *mem_ctx; CLI_POLICY_HND *hnd; NTSTATUS status; DOM_SID *sids = NULL; @@ -277,23 +270,16 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, DEBUG(3,("rpc: name_to_sid name=%s\n", name)); - if (!(mem_ctx = talloc_init("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) { - DEBUG(0, ("talloc_init failed!\n")); - return NT_STATUS_NO_MEMORY; - } - full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name); if (!full_name) { DEBUG(0, ("talloc_asprintf failed!\n")); - talloc_destroy(mem_ctx); return NT_STATUS_NO_MEMORY; } retry = 0; do { if (!(hnd = cm_get_lsa_handle(domain->name))) { - talloc_destroy(mem_ctx); return NT_STATUS_UNSUCCESSFUL; } @@ -308,7 +294,6 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, *type = types[0]; } - talloc_destroy(mem_ctx); return status; } @@ -356,17 +341,22 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, /* Lookup user information from a rid or username. */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, + DOM_SID *user_sid, WINBIND_USERINFO *user_info) { - CLI_POLICY_HND *hnd; - NTSTATUS result; + CLI_POLICY_HND *hnd = NULL; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; POLICY_HND dom_pol, user_pol; BOOL got_dom_pol = False, got_user_pol = False; SAM_USERINFO_CTR *ctr; int retry; + fstring sid_string; + uint32 user_rid; - DEBUG(3,("rpc: query_user rid=%u\n", user_rid)); + DEBUG(3,("rpc: query_user rid=%s\n", sid_to_string(sid_string, user_sid))); + if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) { + goto done; + } retry = 0; do { @@ -405,8 +395,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain, cli_samr_close(hnd->cli, mem_ctx, &user_pol); got_user_pol = False; - user_info->user_rid = user_rid; - user_info->group_rid = ctr->info.id21->group_rid; + user_info->user_sid = rid_to_talloced_sid(domain, mem_ctx, user_rid); + user_info->group_sid = rid_to_talloced_sid(domain, mem_ctx, ctr->info.id21->group_rid); user_info->acct_name = unistr2_tdup(mem_ctx, &ctr->info.id21->uni_user_name); user_info->full_name = unistr2_tdup(mem_ctx, @@ -426,8 +416,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain, /* Lookup groups a user is a member of. I wish Unix had a call like this! */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 user_rid, - uint32 *num_groups, uint32 **user_gids) + DOM_SID *user_sid, + uint32 *num_groups, DOM_SID ***user_gids) { CLI_POLICY_HND *hnd; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; @@ -435,15 +425,17 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; BOOL got_dom_pol = False, got_user_pol = False; DOM_GID *user_groups; - int i; - int retry; + unsigned int i; + unsigned int retry; + fstring sid_string; + uint32 user_rid; - DEBUG(3,("rpc: lookup_usergroups rid=%u\n", user_rid)); + DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid))); *num_groups = 0; /* First try cached universal groups from logon */ - *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups); + *user_gids = uni_group_cache_fetch(&domain->sid, user_sid, mem_ctx, num_groups); if((*num_groups > 0) && *user_gids) { return NT_STATUS_OK; } else { @@ -459,7 +451,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, /* Get domain handle */ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, - des_access, &domain->sid, &dom_pol); + des_access, &domain->sid, &dom_pol); } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1); if (!NT_STATUS_IS_OK(result)) @@ -467,6 +459,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, got_dom_pol = True; + + if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) { + goto done; + } + /* Get user handle */ result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, des_access, user_rid, &user_pol); @@ -484,8 +481,13 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, goto done; (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups)); + if (!(*user_gids)) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + for (i=0;i<(*num_groups);i++) { - (*user_gids)[i] = user_groups[i].g_rid; + (*user_gids)[i] = rid_to_talloced_sid(domain, mem_ctx, user_groups[i].g_rid); } done: @@ -503,19 +505,27 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, /* Lookup group membership given a rid. */ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - uint32 group_rid, uint32 *num_names, - uint32 **rid_mem, char ***names, + DOM_SID *group_sid, uint32 *num_names, + DOM_SID ***sid_mem, char ***names, uint32 **name_types) { - CLI_POLICY_HND *hnd; + CLI_POLICY_HND *hnd = NULL; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; uint32 i, total_names = 0; POLICY_HND dom_pol, group_pol; uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; BOOL got_dom_pol = False, got_group_pol = False; + uint32 *rid_mem = NULL; + uint32 group_rid; int retry; + unsigned int j; + fstring sid_string; - DEBUG(10,("rpc: lookup_groupmem %s rid=%u\n", domain->name, group_rid)); + DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name, sid_to_string(sid_string, group_sid))); + + if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid)) { + goto done; + } *num_names = 0; @@ -550,7 +560,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, group. */ result = cli_samr_query_groupmem(hnd->cli, mem_ctx, - &group_pol, num_names, rid_mem, + &group_pol, num_names, &rid_mem, name_types); if (!NT_STATUS_IS_OK(result)) @@ -565,6 +575,16 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, *names = talloc_zero(mem_ctx, *num_names * sizeof(char *)); *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32)); + *sid_mem = talloc_zero(mem_ctx, *num_names * sizeof(DOM_SID *)); + + for (j=0;j<(*num_names);j++) { + (*sid_mem)[j] = rid_to_talloced_sid(domain, mem_ctx, (rid_mem)[j]); + } + + if (!*names || !*name_types) { + result = NT_STATUS_NO_MEMORY; + goto done; + } for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) { int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS); @@ -577,7 +597,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, result = cli_samr_lookup_rids(hnd->cli, mem_ctx, &dom_pol, 1000, /* flags */ num_lookup_rids, - &(*rid_mem)[i], + &rid_mem[i], &tmp_num_names, &tmp_names, &tmp_types); @@ -592,7 +612,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) * tmp_num_names); - + total_names += tmp_num_names; } diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 6c544d7cf2..d2bd231918 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -29,29 +29,30 @@ /* Fill a pwent structure with information we have obtained */ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, - uint32 user_rid, uint32 group_rid, + DOM_SID *user_sid, DOM_SID *group_sid, char *full_name, struct winbindd_pw *pw) { extern userdom_struct current_user_info; fstring output_username; pstring homedir; + fstring sid_string; if (!pw || !dom_name || !user_name) return False; /* Resolve the uid number */ - if (!winbindd_idmap_get_uid_from_rid(dom_name, user_rid, + if (!winbindd_idmap_get_uid_from_sid(user_sid, &pw->pw_uid)) { - DEBUG(1, ("error getting user id for rid %d\n", user_rid)); + DEBUG(1, ("error getting user id for sid %s\n", sid_to_string(sid_string, user_sid))); return False; } /* Resolve the gid number */ - if (!winbindd_idmap_get_gid_from_rid(dom_name, group_rid, + if (!winbindd_idmap_get_gid_from_sid(group_sid, &pw->pw_gid)) { - DEBUG(1, ("error getting group id for rid %d\n", group_rid)); + DEBUG(1, ("error getting group id for sid %s\n", sid_to_string(sid_string, group_sid))); return False; } @@ -95,7 +96,6 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) { - uint32 user_rid; WINBIND_USERINFO user_info; DOM_SID user_sid; NTSTATUS status; @@ -144,9 +144,7 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - sid_split_rid(&user_sid, &user_rid); - - status = domain->methods->query_user(domain, mem_ctx, user_rid, + status = domain->methods->query_user(domain, mem_ctx, &user_sid, &user_info); if (!NT_STATUS_IS_OK(status)) { @@ -158,7 +156,7 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) /* Now take all this information and fill in a passwd structure */ if (!winbindd_fill_pwent(name_domain, name_user, - user_rid, user_info.group_rid, + user_info.user_sid, user_info.group_sid, user_info.full_name, &state->response.data.pw)) { talloc_destroy(mem_ctx); @@ -176,7 +174,6 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) { DOM_SID user_sid; struct winbindd_domain *domain; - uint32 user_rid; fstring dom_name; fstring user_name; enum SID_NAME_USE name_type; @@ -196,18 +193,15 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) /* Get rid from uid */ - if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid, - &user_rid, &domain)) { - DEBUG(1, ("could not convert uid %d to rid\n", + if (!winbindd_idmap_get_sid_from_uid(state->request.data.uid, + &user_sid)) { + DEBUG(1, ("could not convert uid %d to SID\n", state->request.data.uid)); return WINBINDD_ERROR; } /* Get name and name type from rid */ - sid_copy(&user_sid, &domain->sid); - sid_append_rid(&user_sid, user_rid); - if (!winbindd_lookup_name_by_sid(&user_sid, dom_name, user_name, &name_type)) { fstring temp; @@ -216,6 +210,13 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) return WINBINDD_ERROR; } + domain = find_domain_from_sid(&user_sid); + + if (!domain) { + DEBUG(1,("Can't find domain from sid\n")); + return WINBINDD_ERROR; + } + /* Get some user info */ if (!(mem_ctx = talloc_init("winbind_getpwuid(%d)", @@ -225,7 +226,7 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - status = domain->methods->query_user(domain, mem_ctx, user_rid, + status = domain->methods->query_user(domain, mem_ctx, &user_sid, &user_info); if (!NT_STATUS_IS_OK(status)) { @@ -237,7 +238,7 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) /* Resolve gid number */ - if (!winbindd_idmap_get_gid_from_rid(domain->name, user_info.group_rid, &gid)) { + if (!winbindd_idmap_get_gid_from_sid(user_info.group_sid, &gid)) { DEBUG(1, ("error getting group id for user %s\n", user_name)); talloc_destroy(mem_ctx); return WINBINDD_ERROR; @@ -245,7 +246,8 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) /* Fill in password structure */ - if (!winbindd_fill_pwent(domain->name, user_name, user_rid, user_info.group_rid, + if (!winbindd_fill_pwent(domain->name, user_name, user_info.user_sid, + user_info.group_sid, user_info.full_name, &state->response.data.pw)) { talloc_destroy(mem_ctx); return WINBINDD_ERROR; @@ -332,13 +334,13 @@ static BOOL get_sam_user_entries(struct getent_state *ent) TALLOC_CTX *mem_ctx; struct winbindd_domain *domain; struct winbindd_methods *methods; - int i; + unsigned int i; if (ent->num_sam_entries) return False; if (!(mem_ctx = talloc_init("get_sam_user_entries(%s)", - ent->domain_name))) + ent->domain_name))) return False; if (!(domain = find_domain_from_name(ent->domain_name))) { @@ -393,8 +395,8 @@ static BOOL get_sam_user_entries(struct getent_state *ent) } /* User and group ids */ - name_list[ent->num_sam_entries+i].user_rid = info[i].user_rid; - name_list[ent->num_sam_entries+i].group_rid = info[i].group_rid; + sid_copy(&name_list[ent->num_sam_entries+i].user_sid, info[i].user_sid); + sid_copy(&name_list[ent->num_sam_entries+i].group_sid, info[i].group_sid); } ent->num_sam_entries += num_entries; @@ -491,8 +493,8 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state) result = winbindd_fill_pwent( ent->domain_name, name_list[ent->sam_entry_index].name, - name_list[ent->sam_entry_index].user_rid, - name_list[ent->sam_entry_index].group_rid, + &name_list[ent->sam_entry_index].user_sid, + &name_list[ent->sam_entry_index].group_sid, name_list[ent->sam_entry_index].gecos, &user_list[user_list_ndx]); @@ -539,7 +541,7 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state) for (domain = domain_list(); domain; domain = domain->next) { NTSTATUS status; struct winbindd_methods *methods; - int i; + unsigned int i; methods = domain->methods; diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 262d862b8a..b033380206 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -179,7 +179,7 @@ void rescan_trusted_domains(BOOL force) int i; result = domain->methods->trusted_domains(domain, mem_ctx, &num_domains, - &names, &alt_names, &dom_sids); + &names, &alt_names, &dom_sids); if (!NT_STATUS_IS_OK(result)) { continue; } @@ -188,9 +188,12 @@ void rescan_trusted_domains(BOOL force) the access methods of its parent */ for(i = 0; i < num_domains; i++) { DEBUG(10,("Found domain %s\n", names[i])); - add_trusted_domain(names[i], - alt_names?alt_names[i]:NULL, - domain->methods, &dom_sids[i]); + add_trusted_domain(names[i], alt_names?alt_names[i]:NULL, + domain->methods, &dom_sids[i]); + + /* store trusted domain in the cache */ + trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL, + &dom_sids[i], t + WINBINDD_RESCAN_FREQ); } } @@ -268,14 +271,20 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, enum SID_NAME_USE *type) { NTSTATUS result; - + TALLOC_CTX *mem_ctx; /* Don't bother with machine accounts */ - + if (name[strlen(name) - 1] == '$') return False; + mem_ctx = talloc_init("lookup_sid_by_name for %s\n", name); + if (!mem_ctx) + return False; + /* Lookup name */ - result = domain->methods->name_to_sid(domain, name, sid, type); + result = domain->methods->name_to_sid(domain, mem_ctx, name, sid, type); + + talloc_destroy(mem_ctx); /* Return rid and type if lookup successful */ if (!NT_STATUS_IS_OK(result)) { @@ -549,3 +558,20 @@ int winbindd_num_clients(void) { return _num_clients; } + +/* Help with RID -> SID conversion */ + +DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 rid) +{ + DOM_SID *sid; + sid = talloc(mem_ctx, sizeof(*sid)); + if (!sid) { + smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n"); + } + sid_copy(sid, &domain->sid); + sid_append_rid(sid, rid); + return sid; +} + |