From 0af1500fc0bafe61019f1b2ab1d9e1d369221240 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 3 Feb 2006 22:19:41 +0000 Subject: r13316: Let the carnage begin.... Sync with trunk as off r13315 (This used to be commit 17e63ac4ed8325c0d44fe62b2442449f3298559f) --- source3/passdb/lookup_sid.c | 831 ++++++++++++++++----- source3/passdb/machine_sid.c | 3 +- source3/passdb/passdb.c | 621 +++++----------- source3/passdb/pdb_get_set.c | 12 +- source3/passdb/pdb_interface.c | 444 ++++++++++-- source3/passdb/pdb_ldap.c | 1530 +++++++++++++++++++++++++-------------- source3/passdb/pdb_nds.c | 9 +- source3/passdb/pdb_smbpasswd.c | 22 +- source3/passdb/pdb_tdb.c | 96 ++- source3/passdb/secrets.c | 164 ++--- source3/passdb/util_builtin.c | 2 +- source3/passdb/util_unixsids.c | 94 +++ source3/passdb/util_wellknown.c | 15 + 13 files changed, 2489 insertions(+), 1354 deletions(-) create mode 100644 source3/passdb/util_unixsids.c (limited to 'source3/passdb') diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 4640eb6ae5..6266aa9cab 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -3,6 +3,7 @@ uid/user handling Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Gerald (Jerry) Carter 2003 + Copyright (C) Volker Lendecke 2005 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 @@ -67,7 +68,7 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, if (strequal(domain, get_global_sam_name())) { /* It's our own domain, lookup the name in passdb */ - if (lookup_global_sam_name(name, &rid, &type)) { + if (lookup_global_sam_name(name, flags, &rid, &type)) { sid_copy(&sid, get_global_sam_sid()); sid_append_rid(&sid, rid); goto ok; @@ -87,16 +88,31 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, goto failed; } - if (domain[0] != '\0') { - /* An explicit domain name was given, here our last resort is - * winbind. */ - if (winbind_lookup_name(domain, name, &sid, &type)) { + /* Try the explicit winbind lookup first, don't let it guess the + * domain yet at this point yet. This comes later. */ + + if ((domain[0] != '\0') && + (winbind_lookup_name(domain, name, &sid, &type))) { + goto ok; + } + + if (strequal(domain, unix_users_domain_name())) { + if (lookup_unix_user_name(name, &sid)) { + type = SID_NAME_USER; + goto ok; + } + goto failed; + } + + if (strequal(domain, unix_groups_domain_name())) { + if (lookup_unix_group_name(name, &sid)) { + type = SID_NAME_DOM_GRP; goto ok; } goto failed; } - if (!(flags & LOOKUP_NAME_ISOLATED)) { + if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) { goto failed; } @@ -176,7 +192,7 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, /* Both cases are done by looking at our passdb */ - if (lookup_global_sam_name(name, &rid, &type)) { + if (lookup_global_sam_name(name, flags, &rid, &type)) { domain = talloc_strdup(tmp_ctx, get_global_sam_name()); sid_copy(&sid, get_global_sam_sid()); sid_append_rid(&sid, rid); @@ -232,6 +248,22 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, } /* 10. Don't translate */ + + /* 11. Ok, windows would end here. Samba has two more options: + Unmapped users and unmapped groups */ + + if (lookup_unix_user_name(name, &sid)) { + domain = talloc_strdup(tmp_ctx, unix_users_domain_name()); + type = SID_NAME_USER; + goto ok; + } + + if (lookup_unix_group_name(name, &sid)) { + domain = talloc_strdup(tmp_ctx, unix_groups_domain_name()); + type = SID_NAME_DOM_GRP; + goto ok; + } + failed: talloc_free(tmp_ctx); return False; @@ -265,113 +297,513 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, return True; } -/***************************************************************** - *THE CANONICAL* convert SID to name function. - Tries local lookup first - for local sids, then tries winbind. -*****************************************************************/ +static BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx, + const DOM_SID *domain_sid, + int num_rids, uint32 *rids, + const char **domain_name, + const char **names, uint32 *types) +{ + /* Unless the winbind interface is upgraded, fall back to ask for + * individual sids. I imagine introducing a lookuprids operation that + * directly proxies to lsa_lookupsids to the correct DC. -- vl */ + + int i; + for (i=0; inum_auths != 4) { + /* This can't be a domain */ + return False; } - if (sid_check_is_in_builtin(sid)) { - uint32 rid; + if (IS_DC) { + uint32 i, num_domains; + struct trustdom_info **domains; - SMB_ASSERT(sid_peek_rid(sid, &rid)); + /* This is relatively expensive, but it happens only on DCs + * and for SIDs that have 4 sub-authorities and thus look like + * domains */ - if (!lookup_builtin_rid(tmp_ctx, rid, &name)) { - goto failed; + if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx, + &num_domains, + &domains))) { + return False; } - /* There's only aliases in S-1-5-32 */ - type = SID_NAME_ALIAS; - domain = talloc_strdup(tmp_ctx, builtin_domain_name()); + for (i=0; isid)) { + *name = talloc_strdup(mem_ctx, + domains[i]->name); + return True; + } + } + return False; + } - goto ok; + if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) && + (type == SID_NAME_DOMAIN)) { + *name = tmp; + return True; } - if (winbind_lookup_sid(tmp_ctx, sid, &domain, &name, &type)) { - goto ok; + return False; +} + +/* + * This tries to implement the rather weird rules for the lsa_lookup level + * parameter. + * + * This is as close as we can get to what W2k3 does. With this we survive the + * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more + * different, but I assume that's just being too liberal. For example, W2k3 + * replies to everything else but the levels 1-6 with INVALID_PARAMETER + * whereas NT4 does the same as level 1 (I think). I did not fully test that + * with NT4, this is what w2k3 does. + * + * Level 1: Ask everywhere + * Level 2: Ask domain and trusted domains, no builtin and wkn + * Level 3: Only ask domain + * Level 4: W2k3ad: Only ask AD trusts + * Level 5: Don't lookup anything + * Level 6: Like 4 + */ + +static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level) +{ + int ret = False; + + switch(level) { + case 1: + ret = True; + break; + case 2: + ret = (!sid_check_is_builtin(sid) && + !sid_check_is_wellknown_domain(sid, NULL)); + break; + case 3: + case 4: + case 6: + ret = sid_check_is_domain(sid); + break; + case 5: + ret = False; + break; } - DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying " - "special SIDs.\n", sid_string_static(sid))); + DEBUG(10, ("%s SID %s in level %d\n", + ret ? "Accepting" : "Rejecting", + sid_string_static(sid), level)); + return ret; +} - if (lookup_wellknown_sid(tmp_ctx, sid, &domain, &name)) { - type = SID_NAME_WKN_GRP; - goto ok; +/* + * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with + * references to domains, it is explicitly made for this. + * + * This attempts to be as efficient as possible: It collects all SIDs + * belonging to a domain and hands them in bulk to the appropriate lookup + * function. In particular pdb_lookup_rids with ldapsam_trusted benefits + * *hugely* from this. Winbind is going to be extended with a lookup_rids + * interface as well, so on a DC we can do a bulk lsa_lookuprids to the + * appropriate DC. + */ + +NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, + const DOM_SID **sids, int level, + struct lsa_dom_info **ret_domains, + struct lsa_name_info **ret_names) +{ + TALLOC_CTX *tmp_ctx; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_name_info *name_infos; + struct lsa_dom_info *dom_infos; + + int i, j; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } - failed: - DEBUG(10, ("Failed to lookup sid %s\n", sid_string_static(sid))); + name_infos = TALLOC_ARRAY(tmp_ctx, struct lsa_name_info, num_sids); + dom_infos = TALLOC_ZERO_ARRAY(tmp_ctx, struct lsa_dom_info, + MAX_REF_DOMAINS); + if ((name_infos == NULL) || (dom_infos == NULL)) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + /* First build up the data structures: + * + * dom_infos is a list of domains referenced in the list of + * SIDs. Later we will walk the list of domains and look up the RIDs + * in bulk. + * + * name_infos is a shadow-copy of the SIDs array to collect the real + * data. + * + * dom_info->idxs is an index into the name_infos array. The + * difficulty we have here is that we need to keep the SIDs the client + * asked for in the same order for the reply + */ + + for (i=0; ivalid) { + /* No domains left, we're done */ + break; + } + + rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs); + + if (rids == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + for (j=0; jnum_idxs; j++) { + rids[j] = name_infos[dom->idxs[j]].rid; + } + + if (!lookup_rids(tmp_ctx, &dom->sid, + dom->num_idxs, rids, &dom->name, + &names, &types)) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + talloc_steal(dom_infos, dom->name); + + for (j=0; jnum_idxs; j++) { + int idx = dom->idxs[j]; + name_infos[idx].type = types[j]; + if (types[j] != SID_NAME_UNKNOWN) { + name_infos[idx].name = + talloc_steal(name_infos, names[j]); + } else { + name_infos[idx].name = NULL; + } + } + } + + *ret_domains = talloc_steal(mem_ctx, dom_infos); + *ret_names = talloc_steal(mem_ctx, name_infos); + result = NT_STATUS_OK; + + done: talloc_free(tmp_ctx); - return False; + return result; +} - ok: +/***************************************************************** + *THE CANONICAL* convert SID to name function. +*****************************************************************/ - if ((domain == NULL) || (name == NULL)) { - DEBUG(0, ("talloc failed\n")); - talloc_free(tmp_ctx); +BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, + const char **ret_domain, const char **ret_name, + enum SID_NAME_USE *ret_type) +{ + struct lsa_dom_info *domain; + struct lsa_name_info *name; + TALLOC_CTX *tmp_ctx; + BOOL ret = False; + + tmp_ctx = talloc_new(mem_ctx); + + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); return False; } + if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1, + &domain, &name))) { + goto done; + } + + if (name->type == SID_NAME_UNKNOWN) { + goto done; + } + if (ret_domain != NULL) { - *ret_domain = talloc_steal(mem_ctx, domain); + *ret_domain = talloc_steal(mem_ctx, domain->name); } if (ret_name != NULL) { - *ret_name = talloc_steal(mem_ctx, name); + *ret_name = talloc_steal(mem_ctx, name->name); } if (ret_type != NULL) { - *ret_type = type; + *ret_type = name->type; } + ret = True; + + done: + if (ret) { + DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", + sid_string_static(sid), domain->name, + name->name, name->type)); + } else { + DEBUG(10, ("failed to lookup sid %s\n", + sid_string_static(sid))); + } talloc_free(tmp_ctx); - return True; + return ret; } /***************************************************************** @@ -448,7 +880,7 @@ static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) Store uid to SID mapping in cache. *****************************************************************/ -static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) +void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) { struct uid_sid_cache *pc; @@ -520,7 +952,7 @@ static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) Store gid to SID mapping in cache. *****************************************************************/ -static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) +void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) { struct gid_sid_cache *pc; @@ -552,200 +984,255 @@ static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) *THE CANONICAL* convert uid_t to SID function. *****************************************************************/ -NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid) +void uid_to_sid(DOM_SID *psid, uid_t uid) { uid_t low, high; + uint32 rid; ZERO_STRUCTP(psid); if (fetch_sid_from_uid_cache(psid, uid)) - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + return; - /* DC's never use winbindd to resolve users outside the - defined idmap range */ + if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) && + winbind_uid_to_sid(psid, uid)) { - if ( lp_server_role()==ROLE_DOMAIN_MEMBER - || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) ) - { - if (winbind_uid_to_sid(psid, uid)) { - - DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", - (unsigned int)uid, sid_string_static(psid))); + DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", + (unsigned int)uid, sid_string_static(psid))); + goto done; + } - if (psid) - store_uid_sid_cache(psid, uid); - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); - } + if (pdb_uid_to_rid(uid, &rid)) { + /* This is a mapped user */ + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, rid); + goto done; } - if (!local_uid_to_sid(psid, uid)) { - DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid )); - return NT_STATUS_UNSUCCESSFUL; + if (pdb_rid_algorithm() && (uid < max_algorithmic_uid())) { + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, algorithmic_pdb_uid_to_user_rid(uid)); + goto done; + } else { + sid_copy(psid, &global_sid_Unix_Users); + sid_append_rid(psid, uid); + goto done; } - + + done: DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_string_static(psid))); store_uid_sid_cache(psid, uid); - return NT_STATUS_OK; + return; } /***************************************************************** *THE CANONICAL* convert gid_t to SID function. *****************************************************************/ -NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid) +void gid_to_sid(DOM_SID *psid, gid_t gid) { gid_t low, high; ZERO_STRUCTP(psid); if (fetch_sid_from_gid_cache(psid, gid)) - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + return; - /* DC's never use winbindd to resolve groups outside the - defined idmap range */ + if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) && + winbind_gid_to_sid(psid, gid)) { - if ( lp_server_role()==ROLE_DOMAIN_MEMBER - || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) ) - { - if (winbind_gid_to_sid(psid, gid)) { + DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", + (unsigned int)gid, sid_string_static(psid))); + goto done; + } - DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", - (unsigned int)gid, sid_string_static(psid))); - - if (psid) - store_gid_sid_cache(psid, gid); - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); - } + if (pdb_gid_to_sid(gid, psid)) { + /* This is a mapped group */ + goto done; } - if (!local_gid_to_sid(psid, gid)) { - DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid )); - return NT_STATUS_UNSUCCESSFUL; + if (pdb_rid_algorithm() && (gid < max_algorithmic_gid())) { + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, pdb_gid_to_group_rid(gid)); + goto done; + } else { + sid_copy(psid, &global_sid_Unix_Groups); + sid_append_rid(psid, gid); + goto done; } - + + done: DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_string_static(psid))); store_gid_sid_cache(psid, gid); - return NT_STATUS_OK; + return; } /***************************************************************** *THE CANONICAL* convert SID to uid function. *****************************************************************/ -NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid) +BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid) { - enum SID_NAME_USE name_type; + enum SID_NAME_USE type; + uint32 rid; + gid_t gid; if (fetch_uid_from_cache(puid, psid)) - return NT_STATUS_OK; + return True; - /* if this is our SID then go straight to a local lookup */ - - if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) { - DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n", - sid_string_static(psid) )); - - if ( local_sid_to_uid(puid, psid, &name_type) ) - goto success; - - DEBUG(10,("sid_to_uid: local lookup failed\n")); - - return NT_STATUS_UNSUCCESSFUL; + if (fetch_gid_from_cache(&gid, psid)) { + return False; } - - /* If it is not our local domain, only hope is winbindd */ - if ( !winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type) ) { - DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n", - sid_string_static(psid) )); - - return NT_STATUS_UNSUCCESSFUL; + if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) { + uid_t uid = rid; + *puid = uid; + goto done; } - /* If winbindd does know the SID, ensure this is a user */ + if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) { + union unid_t id; + + if (pdb_sid_to_id(psid, &id, &type)) { + if (type != SID_NAME_USER) { + DEBUG(5, ("sid %s is a %s, expected a user\n", + sid_string_static(psid), + sid_type_lookup(type))); + return False; + } + *puid = id.uid; + goto done; + } + if (pdb_rid_algorithm() && + algorithmic_pdb_rid_is_user(rid)) { + *puid = algorithmic_pdb_user_rid_to_uid(rid); + goto done; + } - if (name_type != SID_NAME_USER) { - DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n", - (unsigned int)name_type )); - return NT_STATUS_INVALID_PARAMETER; + /* This was ours, but it was neither mapped nor + * algorithmic. Fail */ + return False; } - /* get the uid. Has to work or else we are dead in the water */ + if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) { + + if (type != SID_NAME_USER) { + DEBUG(10, ("sid_to_uid: sid %s is a %s\n", + sid_string_static(psid), + sid_type_lookup(type))); + return False; + } - if ( !winbind_sid_to_uid(puid, psid) ) { - DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n", - sid_string_static(psid))); - return NT_STATUS_UNSUCCESSFUL; + if (!winbind_sid_to_uid(puid, psid)) { + DEBUG(5, ("sid_to_uid: winbind failed to allocate a " + "new uid for sid %s\n", + sid_string_static(psid))); + return False; + } + goto done; } -success: + /* TODO: Here would be the place to allocate both a gid and a uid for + * the SID in question */ + + return False; + + done: DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid), (unsigned int)*puid )); store_uid_sid_cache(psid, *puid); - - return NT_STATUS_OK; + return True; } + /***************************************************************** *THE CANONICAL* convert SID to gid function. Group mapping is used for gids that maps to Wellknown SIDs *****************************************************************/ -NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid) +BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid) { - enum SID_NAME_USE name_type; + uint32 rid; + GROUP_MAP map; + union unid_t id; + enum SID_NAME_USE type; + uid_t uid; if (fetch_gid_from_cache(pgid, psid)) - return NT_STATUS_OK; + return True; - /* - * First we must look up the name and decide if this is a group sid. - * Group mapping can deal with foreign SIDs - */ + if (fetch_uid_from_cache(&uid, psid)) + return False; + + if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) { + gid_t gid = rid; + *pgid = gid; + goto done; + } + + if (sid_check_is_in_builtin(psid) && pdb_getgrsid(&map, *psid)) { + *pgid = map.gid; + goto done; + } - if ( local_sid_to_gid(pgid, psid, &name_type) ) - goto success; + if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) { + if (pdb_sid_to_id(psid, &id, &type)) { + if ((type != SID_NAME_DOM_GRP) && + (type != SID_NAME_ALIAS)) { + DEBUG(5, ("sid %s is a %s, expected a group\n", + sid_string_static(psid), + sid_type_lookup(type))); + return False; + } + *pgid = id.gid; + goto done; + } + if (pdb_rid_algorithm() && + !algorithmic_pdb_rid_is_user(rid)) { + /* This must be a group, presented as alias */ + *pgid = pdb_group_rid_to_gid(rid); + goto done; + } + /* This was ours, but it was neither mapped nor + * algorithmic. Fail. */ + return False; + } - if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type)) { - DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then " - "winbind)\n", sid_string_static(psid))); + if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) { + DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, " + "then winbind)\n", sid_string_static(psid))); - return NT_STATUS_UNSUCCESSFUL; + return False; } /* winbindd knows it; Ensure this is a group sid */ - if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) - && (name_type != SID_NAME_WKN_GRP)) - { - DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n", - (unsigned int)name_type )); - - /* winbindd is running and knows about this SID. Just the wrong type. - Don't fallback to a local lookup here */ - - return NT_STATUS_INVALID_PARAMETER; + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is " + "a %s\n", sid_type_lookup(type))); + return False; } /* winbindd knows it and it is a type of group; sid_to_gid must succeed or we are dead in the water */ if ( !winbind_sid_to_gid(pgid, psid) ) { - DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n", - sid_string_static(psid))); - return NT_STATUS_UNSUCCESSFUL; + DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid " + "for sid %s\n", sid_string_static(psid))); + return False; } -success: + done: DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid), (unsigned int)*pgid )); store_gid_sid_cache(psid, *pgid); - return NT_STATUS_OK; + return True; } diff --git a/source3/passdb/machine_sid.c b/source3/passdb/machine_sid.c index 074a516bcb..d7cae06749 100644 --- a/source3/passdb/machine_sid.c +++ b/source3/passdb/machine_sid.c @@ -35,13 +35,14 @@ static DOM_SID *global_sam_sid=NULL; Read a SID from a file. This is for compatibility with the old MACHINE.SID style of SID storage ****************************************************************************/ + static BOOL read_sid_from_file(const char *fname, DOM_SID *sid) { char **lines; int numlines; BOOL ret; - lines = file_lines_load(fname, &numlines); + lines = file_lines_load(fname, &numlines,0); if (!lines || numlines < 1) { if (lines) file_lines_free(lines); diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index f9f6021d81..90a51d1cbd 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -350,34 +350,129 @@ NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd) on the UNIX user. Pass in a RID if you have one ************************************************************/ -NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username, - uint32 rid) +NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username) { - NTSTATUS nt_status = NT_STATUS_NO_MEMORY; + NTSTATUS result; struct passwd *pwd; - BOOL ret; - - pwd = Get_Pwnam(username); + uint32 user_rid; + DOM_SID user_sid, group_sid; + TALLOC_CTX *mem_ctx; + enum SID_NAME_USE type; - if (!pwd) - return NT_STATUS_NO_SUCH_USER; - - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) { - *new_sam_acct = NULL; - return nt_status; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } - /* see if we need to generate a new rid using the 2.2 algorithm */ - if ( rid == 0 && lp_enable_rid_algorithm() ) { - DEBUG(10,("pdb_init_sam_new: no RID specified. Generating one via old algorithm\n")); - rid = algorithmic_pdb_uid_to_user_rid(pwd->pw_uid); + pwd = Get_Pwnam_alloc(mem_ctx, username); + + if (pwd == NULL) { + DEBUG(10, ("Could not find user %s\n", username)); + result = NT_STATUS_NO_SUCH_USER; + goto done; } - - /* set the new SID */ - - ret = pdb_set_user_sid_from_rid( *new_sam_acct, rid, PDB_SET ); - - return (ret ? NT_STATUS_OK : NT_STATUS_NO_SUCH_USER); + + result = pdb_init_sam_pw(new_sam_acct, pwd); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_init_sam_pw failed: %s\n", nt_errstr(result))); + goto done; + } + + if (pdb_rid_algorithm()) { + if (!pdb_set_user_sid_from_rid( + *new_sam_acct, + algorithmic_pdb_uid_to_user_rid(pwd->pw_uid), + PDB_SET)) { + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + if (!pdb_set_group_sid_from_rid( + *new_sam_acct, pdb_gid_to_group_rid(pwd->pw_gid), + PDB_SET)) { + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + result = NT_STATUS_OK; + goto done; + } + + /* No algorithmic mapping, meaning that we have to figure out the + * primary group SID according to group mapping and the user SID must + * be a newly allocated one */ + + if (!pdb_gid_to_sid(pwd->pw_gid, &group_sid)) { + struct group *grp; + GROUP_MAP map; + + grp = getgrgid(pwd->pw_gid); + if (grp == NULL) { + DEBUG(1, ("Primary group %d of user %s does not " + "exist.\n", pwd->pw_gid, username)); + result = NT_STATUS_INVALID_PRIMARY_GROUP; + goto done; + } + + DEBUG(5, ("Primary group %s of user %s is not mapped to " + "a domain group, auto-mapping it\n", + grp->gr_name, username)); + result = map_unix_group(grp, &map); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(1, ("Failed to map group %s\n", grp->gr_name)); + goto done; + } + sid_copy(&group_sid, &map.sid); + DEBUG(5, ("Mapped unix group %s to SID %s\n", + grp->gr_name, sid_string_static(&group_sid))); + } + + /* Now check that it's actually a domain group and not something + * else */ + + if (!lookup_sid(mem_ctx, &group_sid, NULL, NULL, &type)) { + DEBUG(3, ("Could not lookup %s's primary group sid %s\n", + username, sid_string_static(&group_sid))); + result = NT_STATUS_INVALID_PRIMARY_GROUP; + goto done; + } + + if (type != SID_NAME_DOM_GRP) { + DEBUG(3, ("Primary group for user %s is a %s and not a domain " + "group\n", username, sid_type_lookup(type))); + result = NT_STATUS_INVALID_PRIMARY_GROUP; + goto done; + } + + if (!pdb_set_group_sid(*new_sam_acct, &group_sid, PDB_SET)) { + DEBUG(3, ("Could not set group SID\n")); + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + if (!pdb_new_rid(&user_rid)) { + DEBUG(3, ("Could not allocate a new RID\n")); + result = NT_STATUS_ACCESS_DENIED; + goto done; + } + + sid_copy(&user_sid, get_global_sam_sid()); + sid_append_rid(&user_sid, user_rid); + + if (!pdb_set_user_sid(*new_sam_acct, &user_sid, PDB_SET)) { + DEBUG(3, ("pdb_set_user_sid failed\n")); + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + result = NT_STATUS_OK; + + done: + if (!NT_STATUS_IS_OK(result) && (*new_sam_acct != NULL)) { + pdb_free_sam(new_sam_acct); + } + + talloc_free(mem_ctx); + return result; } @@ -666,6 +761,11 @@ uid_t algorithmic_pdb_user_rid_to_uid(uint32 user_rid) return (uid_t)(((user_rid & (~USER_RID_TYPE)) - rid_offset)/RID_MULTIPLIER); } +uid_t max_algorithmic_uid(void) +{ + return algorithmic_pdb_user_rid_to_uid(0xfffffffe); +} + /******************************************************************* converts UNIX uid to an NT User RID. ********************************************************************/ @@ -686,6 +786,11 @@ gid_t pdb_group_rid_to_gid(uint32 group_rid) return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- rid_offset)/RID_MULTIPLIER); } +gid_t max_algorithmic_gid(void) +{ + return pdb_group_rid_to_gid(0xffffffff); +} + /******************************************************************* converts NT Group RID to a UNIX uid. @@ -731,130 +836,12 @@ BOOL algorithmic_pdb_rid_is_user(uint32 rid) return False; } -/******************************************************************* - Look up a rid in the SAM we're responsible for (i.e. passdb) - ********************************************************************/ - -BOOL lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid, const char **name, - enum SID_NAME_USE *psid_name_use) -{ - SAM_ACCOUNT *sam_account = NULL; - GROUP_MAP map; - BOOL ret; - DOM_SID sid; - - *psid_name_use = SID_NAME_UNKNOWN; - - DEBUG(5,("lookup_global_sam_rid: looking up RID %u.\n", - (unsigned int)rid)); - - sid_copy(&sid, get_global_sam_sid()); - sid_append_rid(&sid, rid); - - /* see if the passdb can help us with the name of the user */ - if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) { - return False; - } - - /* BEING ROOT BLLOCK */ - become_root(); - if (pdb_getsampwsid(sam_account, &sid)) { - unbecome_root(); /* -----> EXIT BECOME_ROOT() */ - *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account)); - *psid_name_use = SID_NAME_USER; - - pdb_free_sam(&sam_account); - - return True; - } - pdb_free_sam(&sam_account); - - ret = pdb_getgrsid(&map, sid); - unbecome_root(); - /* END BECOME_ROOT BLOCK */ - - if ( ret ) { - if (map.gid!=(gid_t)-1) { - DEBUG(5,("lookup_global_sam_rid: mapped group %s to " - "gid %u\n", map.nt_name, - (unsigned int)map.gid)); - } else { - DEBUG(5,("lookup_global_sam_rid: mapped group %s to " - "no unix gid. Returning name.\n", - map.nt_name)); - } - - *name = talloc_strdup(mem_ctx, map.nt_name); - *psid_name_use = map.sid_name_use; - return True; - } - - if (rid == DOMAIN_USER_RID_ADMIN) { - *psid_name_use = SID_NAME_USER; - *name = talloc_strdup(mem_ctx, "Administrator"); - return True; - } - - if (algorithmic_pdb_rid_is_user(rid)) { - uid_t uid; - struct passwd *pw = NULL; - - DEBUG(5, ("assuming RID %u is a user\n", (unsigned)rid)); - - uid = algorithmic_pdb_user_rid_to_uid(rid); - pw = sys_getpwuid( uid ); - - DEBUG(5,("lookup_global_sam_rid: looking up uid %u %s\n", - (unsigned int)uid, pw ? "succeeded" : "failed" )); - - if ( !pw ) { - *name = talloc_asprintf(mem_ctx, "unix_user.%u", - (unsigned int)uid); - } else { - *name = talloc_strdup(mem_ctx, pw->pw_name ); - } - - DEBUG(5,("lookup_global_sam_rid: found user %s for rid %u\n", - *name, (unsigned int)rid )); - - *psid_name_use = SID_NAME_USER; - - return ( pw != NULL ); - } else { - gid_t gid; - struct group *gr; - - DEBUG(5, ("assuming RID %u is a group\n", (unsigned)rid)); - - gid = pdb_group_rid_to_gid(rid); - gr = getgrgid(gid); - - DEBUG(5,("lookup_global_sam_rid: looking up gid %u %s\n", - (unsigned int)gid, gr ? "succeeded" : "failed" )); - - if( !gr ) { - *name = talloc_asprintf(mem_ctx, "unix_group.%u", - (unsigned int)gid); - } else { - *name = talloc_strdup(mem_ctx, gr->gr_name); - } - - DEBUG(5,("lookup_global_sam_rid: found group %s for rid %u\n", - *name, (unsigned int)rid )); - - /* assume algorithmic groups are domain global groups */ - - *psid_name_use = SID_NAME_DOM_GRP; - - return ( gr != NULL ); - } -} - /******************************************************************* Convert a name into a SID. Used in the lookup name rpc. ********************************************************************/ -BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE *type) +BOOL lookup_global_sam_name(const char *c_user, int flags, uint32_t *rid, + enum SID_NAME_USE *type) { fstring user; SAM_ACCOUNT *sam_account = NULL; @@ -877,7 +864,13 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE /* BEGIN ROOT BLOCK */ become_root(); - if (pdb_getsampwnam(sam_account, user)) { + + /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work + * correctly in the case where foo also exists as a user. If the flag + * is set, don't look for users at all. */ + + if (((flags & LOOKUP_NAME_GROUP) == 0) && + pdb_getsampwnam(sam_account, user)) { const DOM_SID *user_sid; unbecome_root(); @@ -891,15 +884,7 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE } sid_peek_rid(user_sid, rid); - - if (pdb_get_acct_ctrl(sam_account) & - (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST)) { - /* We have to filter them out in lsa_lookupnames, - * indicate that this is not a real user. */ - *type = SID_NAME_COMPUTER; - } else { - *type = SID_NAME_USER; - } + *type = SID_NAME_USER; pdb_free_sam(&sam_account); return True; } @@ -929,6 +914,8 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE return True; } + return False; + /* it's not a mapped group */ grp = getgrnam(user); if(!grp) { @@ -965,13 +952,14 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE Change a password entry in the local smbpasswd file. *************************************************************/ -BOOL local_password_change(const char *user_name, int local_flags, +NTSTATUS local_password_change(const char *user_name, int local_flags, const char *new_passwd, char *err_str, size_t err_str_len, char *msg_str, size_t msg_str_len) { SAM_ACCOUNT *sam_pass=NULL; uint16 other_acb; + NTSTATUS result; *err_str = '\0'; *msg_str = '\0'; @@ -985,14 +973,30 @@ BOOL local_password_change(const char *user_name, int local_flags, pdb_free_sam(&sam_pass); if ((local_flags & LOCAL_ADD_USER) || (local_flags & LOCAL_DELETE_USER)) { - /* Might not exist in /etc/passwd. Use rid algorithm here */ - if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pass, user_name, 0))) { - slprintf(err_str, err_str_len-1, "Failed to initialise SAM_ACCOUNT for user %s. Does this user exist in the UNIX password database ?\n", user_name); - return False; + int tmp_debug = DEBUGLEVEL; + + /* Might not exist in /etc/passwd. */ + + if (tmp_debug < 1) { + DEBUGLEVEL = 1; + } + + result = pdb_init_sam_new(&sam_pass, user_name); + DEBUGLEVEL = tmp_debug; + if (NT_STATUS_EQUAL(result, + NT_STATUS_INVALID_PRIMARY_GROUP)) { + return result; + } + + if (!NT_STATUS_IS_OK(result)) { + slprintf(err_str, err_str_len-1, "Failed to " + "initialize account for user %s: %s\n", + user_name, nt_errstr(result)); + return result; } } else { slprintf(err_str, err_str_len-1,"Failed to find entry for user %s.\n", user_name); - return False; + return NT_STATUS_NO_SUCH_USER; } } else { unbecome_root(); @@ -1006,19 +1010,19 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl(sam_pass, ACB_WSTRUST | other_acb, PDB_CHANGED) ) { slprintf(err_str, err_str_len - 1, "Failed to set 'trusted workstation account' flags for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) { if (!pdb_set_acct_ctrl(sam_pass, ACB_DOMTRUST | other_acb, PDB_CHANGED)) { slprintf(err_str, err_str_len - 1, "Failed to set 'domain trust account' flags for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else { if (!pdb_set_acct_ctrl(sam_pass, ACB_NORMAL | other_acb, PDB_CHANGED)) { slprintf(err_str, err_str_len - 1, "Failed to set 'normal account' flags for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } @@ -1031,13 +1035,13 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_DISABLED, PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to set 'disabled' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_ENABLE_USER) { if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } @@ -1045,7 +1049,7 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_PWNOTREQ, PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to set 'no password required' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_SET_PASSWORD) { /* @@ -1061,19 +1065,19 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_PWNOTREQ), PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to unset 'no password required' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } if (!pdb_set_plaintext_passwd (sam_pass, new_passwd)) { slprintf(err_str, err_str_len-1, "Failed to set password for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } @@ -1081,24 +1085,25 @@ BOOL local_password_change(const char *user_name, int local_flags, if (pdb_add_sam_account(sam_pass)) { slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name); pdb_free_sam(&sam_pass); - return True; + return NT_STATUS_OK; } else { slprintf(err_str, err_str_len-1, "Failed to add entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_DELETE_USER) { if (!pdb_delete_sam_account(sam_pass)) { slprintf(err_str,err_str_len-1, "Failed to delete entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } slprintf(msg_str, msg_str_len-1, "Deleted user %s.\n", user_name); } else { - if(!pdb_update_sam_account(sam_pass)) { + result = pdb_update_sam_account(sam_pass); + if(!NT_STATUS_IS_OK(result)) { slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return result; } if(local_flags & LOCAL_DISABLE_USER) slprintf(msg_str, msg_str_len-1, "Disabled user %s.\n", user_name); @@ -1109,232 +1114,7 @@ BOOL local_password_change(const char *user_name, int local_flags, } pdb_free_sam(&sam_pass); - return True; -} - -/**************************************************************************** - Convert a uid to SID - algorithmic. -****************************************************************************/ - -DOM_SID *algorithmic_uid_to_sid(DOM_SID *psid, uid_t uid) -{ - if ( !lp_enable_rid_algorithm() ) - return NULL; - - DEBUG(8,("algorithmic_uid_to_sid: falling back to RID algorithm\n")); - sid_copy( psid, get_global_sam_sid() ); - sid_append_rid( psid, algorithmic_pdb_uid_to_user_rid(uid) ); - DEBUG(10,("algorithmic_uid_to_sid: uid (%d) -> SID %s.\n", - (unsigned int)uid, sid_string_static(psid) )); - - return psid; -} - -/**************************************************************************** - Convert a uid to SID - locally. -****************************************************************************/ - -DOM_SID *local_uid_to_sid(DOM_SID *psid, uid_t uid) -{ - SAM_ACCOUNT *sampw = NULL; - struct passwd *unix_pw; - BOOL ret; - - unix_pw = sys_getpwuid( uid ); - - if ( !unix_pw ) { - DEBUG(4,("local_uid_to_sid: host has no idea of uid %lu\n", (unsigned long)uid)); - return algorithmic_uid_to_sid( psid, uid); - } - - if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { - DEBUG(0,("local_uid_to_sid: failed to allocate SAM_ACCOUNT object\n")); - return NULL; - } - - become_root(); - ret = pdb_getsampwnam( sampw, unix_pw->pw_name ); - unbecome_root(); - - if ( ret ) - sid_copy( psid, pdb_get_user_sid(sampw) ); - else { - DEBUG(4,("local_uid_to_sid: User %s [uid == %lu] has no samba account\n", - unix_pw->pw_name, (unsigned long)uid)); - - algorithmic_uid_to_sid( psid, uid); - } - - pdb_free_sam(&sampw); - - DEBUG(10,("local_uid_to_sid: uid (%d) -> SID %s (%s).\n", - (unsigned int)uid, sid_string_static(psid), unix_pw->pw_name)); - - return psid; -} - -/**************************************************************************** - Convert a SID to uid - locally. -****************************************************************************/ - -BOOL local_sid_to_uid(uid_t *puid, const DOM_SID *psid, enum SID_NAME_USE *name_type) -{ - SAM_ACCOUNT *sampw = NULL; - struct passwd *unix_pw; - const char *user_name; - - *name_type = SID_NAME_UNKNOWN; - - /* - * We can only convert to a uid if this is our local - * Domain SID (ie. we are the controling authority). - */ - if (!sid_check_is_in_our_domain(psid) ) { - DEBUG(5,("local_sid_to_uid: this SID (%s) is not from our domain\n", sid_string_static(psid))); - return False; - } - - /* lookup the user account */ - - if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { - DEBUG(0,("local_sid_to_uid: Failed to allocate memory for SAM_ACCOUNT object\n")); - return False; - } - - become_root(); - if ( !pdb_getsampwsid(sampw, psid) ) { - unbecome_root(); - pdb_free_sam(&sampw); - DEBUG(8,("local_sid_to_uid: Could not find SID %s in passdb\n", - sid_string_static(psid))); - return False; - } - unbecome_root(); - - user_name = pdb_get_username(sampw); - - unix_pw = sys_getpwnam( user_name ); - - if ( !unix_pw ) { - DEBUG(0,("local_sid_to_uid: %s found in passdb but getpwnam() return NULL!\n", - user_name)); - pdb_free_sam( &sampw ); - return False; - } - - *puid = unix_pw->pw_uid; - - DEBUG(10,("local_sid_to_uid: SID %s -> uid (%u) (%s).\n", sid_string_static(psid), - (unsigned int)*puid, user_name )); - - *name_type = SID_NAME_USER; - pdb_free_sam( &sampw ); - return True; -} - -/**************************************************************************** - Convert a gid to SID - locally. -****************************************************************************/ - -DOM_SID *local_gid_to_sid(DOM_SID *psid, gid_t gid) -{ - GROUP_MAP group; - BOOL ret; - - /* we don't need to disable winbindd since the gid is stored in - the GROUP_MAP object */ - - /* done as root since ldap backend requires root to open a connection */ - - become_root(); - ret = pdb_getgrgid( &group, gid ); - unbecome_root(); - - if ( !ret ) { - - /* fallback to rid mapping if enabled */ - - if ( lp_enable_rid_algorithm() ) { - sid_copy(psid, get_global_sam_sid()); - sid_append_rid(psid, pdb_gid_to_group_rid(gid)); - - DEBUG(10,("local_gid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", - (unsigned int)gid, sid_string_static(psid))); - - return psid; - } - else - return NULL; - } - - sid_copy( psid, &group.sid ); - - DEBUG(10,("local_gid_to_sid: gid (%d) -> SID %s.\n", - (unsigned int)gid, sid_string_static(psid))); - - return psid; -} - -/**************************************************************************** - Convert a SID to gid - locally. -****************************************************************************/ - -BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_type) -{ - uint32 rid; - GROUP_MAP group; - BOOL ret; - - *name_type = SID_NAME_UNKNOWN; - - /* This call can enumerate group mappings for foreign sids as well. - So don't check for a match against our domain SID */ - - /* we don't need to disable winbindd since the gid is stored in - the GROUP_MAP object */ - - become_root(); - ret = pdb_getgrsid(&group, *psid); - unbecome_root(); - - if ( !ret ) { - - /* Fallback to algorithmic rid mapping if enabled */ - - if ( lp_enable_rid_algorithm() ) { - - if (!sid_check_is_in_our_domain(psid) ) { - DEBUG(5,("local_sid_to_gid: RID algorithm only supported for our domain (%s is not)\n", sid_string_static(psid))); - return False; - } - - if (!sid_peek_rid(psid, &rid)) { - DEBUG(10,("local_sid_to_gid: invalid SID!\n")); - return False; - } - - DEBUG(10,("local_sid_to_gid: Fall back to algorithmic mapping\n")); - - if (algorithmic_pdb_rid_is_user(rid)) { - DEBUG(3, ("local_sid_to_gid: SID %s is *NOT* a group\n", sid_string_static(psid))); - return False; - } else { - *pgid = pdb_group_rid_to_gid(rid); - DEBUG(10,("local_sid_to_gid: mapping: %s -> %u\n", sid_string_static(psid), (unsigned int)(*pgid))); - return True; - } - } - - return False; - } - - *pgid = group.gid; - *name_type = group.sid_name_use; - - DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u)\n", sid_string_static(psid), - (unsigned int)*pgid)); - - return True; + return NT_STATUS_OK; } /********************************************************************** @@ -2251,51 +2031,6 @@ BOOL pdb_copy_sam_account(const SAM_ACCOUNT *src, SAM_ACCOUNT **dst) return result; } -/********************************************************************** -**********************************************************************/ - -static BOOL get_free_ugid_range(uint32 *low, uint32 *high) -{ - uid_t u_low, u_high; - gid_t g_low, g_high; - - if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) { - return False; - } - - *low = (u_low < g_low) ? u_low : g_low; - *high = (u_high < g_high) ? u_high : g_high; - - return True; -} - -/****************************************************************** - Get the the non-algorithmic RID range if idmap range are defined -******************************************************************/ - -BOOL get_free_rid_range(uint32 *low, uint32 *high) -{ - uint32 id_low, id_high; - - if (!lp_enable_rid_algorithm()) { - *low = BASE_RID; - *high = (uint32)-1; - } - - if (!get_free_ugid_range(&id_low, &id_high)) { - return False; - } - - *low = algorithmic_pdb_uid_to_user_rid(id_low); - if (algorithmic_pdb_user_rid_to_uid((uint32)-1) < id_high) { - *high = (uint32)-1; - } else { - *high = algorithmic_pdb_uid_to_user_rid(id_high); - } - - return True; -} - /********************************************************************* Update the bad password count checking the AP_RESET_COUNT_TIME *********************************************************************/ diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c index 783e9e23fa..71fb36e0d5 100644 --- a/source3/passdb/pdb_get_set.c +++ b/source3/passdb/pdb_get_set.c @@ -958,7 +958,8 @@ BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[NT_HASH_LEN], enum data_blob_clear_free(&sampass->private_u.nt_pw); if (pwd) { - sampass->private_u.nt_pw = data_blob(pwd, NT_HASH_LEN); + sampass->private_u.nt_pw = + data_blob_talloc(sampass->mem_ctx, pwd, NT_HASH_LEN); } else { sampass->private_u.nt_pw = data_blob(NULL, 0); } @@ -978,7 +979,8 @@ BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[LM_HASH_LEN], data_blob_clear_free(&sampass->private_u.lm_pw); if (pwd) { - sampass->private_u.lm_pw = data_blob(pwd, LM_HASH_LEN); + sampass->private_u.lm_pw = + data_blob_talloc(sampass->mem_ctx, pwd, LM_HASH_LEN); } else { sampass->private_u.lm_pw = data_blob(NULL, 0); } @@ -1093,8 +1095,10 @@ BOOL pdb_set_backend_private_data (SAM_ACCOUNT *sampass, void *private_data, if (!sampass) return False; - if (sampass->private_u.backend_private_data && sampass->private_u.backend_private_data_free_fn) { - sampass->private_u.backend_private_data_free_fn(&sampass->private_u.backend_private_data); + if (sampass->private_u.backend_private_data && + sampass->private_u.backend_private_data_free_fn) { + sampass->private_u.backend_private_data_free_fn( + &sampass->private_u.backend_private_data); } sampass->private_u.backend_private_data = private_data; diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index 4808af3908..d8afff2111 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -36,7 +36,10 @@ static void lazy_initialize_passdb(void) } static struct pdb_init_function_entry *pdb_find_backend_entry(const char *name); - +static BOOL lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid, + const char **name, + enum SID_NAME_USE *psid_name_use, + union unid_t *unix_id); /******************************************************************* Clean up uninitialised passwords. The only way to tell that these values are not 'real' is that they do not @@ -526,9 +529,10 @@ static NTSTATUS context_enum_group_members(struct pdb_context *context, } static NTSTATUS context_enum_group_memberships(struct pdb_context *context, - const char *username, - gid_t primary_gid, - DOM_SID **pp_sids, gid_t **pp_gids, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, + DOM_SID **pp_sids, + gid_t **pp_gids, size_t *p_num_groups) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; @@ -539,8 +543,8 @@ static NTSTATUS context_enum_group_memberships(struct pdb_context *context, } return context->pdb_methods-> - enum_group_memberships(context->pdb_methods, username, - primary_gid, pp_sids, pp_gids, p_num_groups); + enum_group_memberships(context->pdb_methods, mem_ctx, user, + pp_sids, pp_gids, p_num_groups); } static NTSTATUS context_find_alias(struct pdb_context *context, @@ -757,6 +761,63 @@ static NTSTATUS context_get_seq_num(struct pdb_context *context, time_t *seq_num return context->pdb_methods->get_seq_num(context->pdb_methods, seq_num); } + +static BOOL context_uid_to_rid(struct pdb_context *context, uid_t uid, + uint32 *rid) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->uid_to_rid(context->pdb_methods, uid, + rid); +} + +static BOOL context_gid_to_sid(struct pdb_context *context, gid_t gid, + DOM_SID *sid) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->gid_to_sid(context->pdb_methods, gid, + sid); +} + +static BOOL context_sid_to_id(struct pdb_context *context, + const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->sid_to_id(context->pdb_methods, sid, + id, type); +} + +static BOOL context_rid_algorithm(struct pdb_context *context) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->rid_algorithm(context->pdb_methods); +} + +static BOOL context_new_rid(struct pdb_context *context, uint32 *rid) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->new_rid(context->pdb_methods, rid); +} /****************************************************************** Free and cleanup a pdb context, any associated data and anything @@ -936,6 +997,13 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*context)->pdb_search_groups = context_search_groups; (*context)->pdb_search_aliases = context_search_aliases; + (*context)->pdb_uid_to_rid = context_uid_to_rid; + (*context)->pdb_gid_to_sid = context_gid_to_sid; + (*context)->pdb_sid_to_id = context_sid_to_id; + + (*context)->pdb_rid_algorithm = context_rid_algorithm; + (*context)->pdb_new_rid = context_new_rid; + (*context)->free_fn = free_pdb_context; return NT_STATUS_OK; @@ -1126,12 +1194,12 @@ BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct) return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, sam_acct)); } -BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct) +NTSTATUS pdb_update_sam_account(SAM_ACCOUNT *sam_acct) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } if (sam_account_cache != NULL) { @@ -1139,7 +1207,7 @@ BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct) sam_account_cache = NULL; } - return NT_STATUS_IS_OK(pdb_context->pdb_update_sam_account(pdb_context, sam_acct)); + return pdb_context->pdb_update_sam_account(pdb_context, sam_acct); } BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) @@ -1221,28 +1289,26 @@ BOOL pdb_getgrnam(GROUP_MAP *map, const char *name) pdb_getgrnam(pdb_context, map, name)); } -BOOL pdb_add_group_mapping_entry(GROUP_MAP *map) +NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_add_group_mapping_entry(pdb_context, map)); + return pdb_context->pdb_add_group_mapping_entry(pdb_context, map); } -BOOL pdb_update_group_mapping_entry(GROUP_MAP *map) +NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_update_group_mapping_entry(pdb_context, map)); + return pdb_context->pdb_update_group_mapping_entry(pdb_context, map); } BOOL pdb_delete_group_mapping_entry(DOM_SID sid) @@ -1286,7 +1352,7 @@ NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx, pp_member_rids, p_num_members); } -NTSTATUS pdb_enum_group_memberships(const char *username, gid_t primary_gid, +NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, SAM_ACCOUNT *user, DOM_SID **pp_sids, gid_t **pp_gids, size_t *p_num_groups) { @@ -1296,9 +1362,9 @@ NTSTATUS pdb_enum_group_memberships(const char *username, gid_t primary_gid, return NT_STATUS_UNSUCCESSFUL; } - return pdb_context->pdb_enum_group_memberships(pdb_context, username, - primary_gid, pp_sids, pp_gids, - p_num_groups); + return pdb_context->pdb_enum_group_memberships( + pdb_context, mem_ctx, user, + pp_sids, pp_gids, p_num_groups); } BOOL pdb_find_alias(const char *name, DOM_SID *sid) @@ -1361,60 +1427,58 @@ BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info) info)); } -BOOL pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member) +NTSTATUS pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_add_aliasmem(pdb_context, alias, member)); + return pdb_context->pdb_add_aliasmem(pdb_context, alias, member); } -BOOL pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member) +NTSTATUS pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_del_aliasmem(pdb_context, alias, member)); + return pdb_context->pdb_del_aliasmem(pdb_context, alias, member); } -BOOL pdb_enum_aliasmem(const DOM_SID *alias, - DOM_SID **pp_members, size_t *p_num_members) +NTSTATUS pdb_enum_aliasmem(const DOM_SID *alias, + DOM_SID **pp_members, size_t *p_num_members) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_enum_aliasmem(pdb_context, alias, - pp_members, p_num_members)); + return pdb_context->pdb_enum_aliasmem(pdb_context, alias, + pp_members, p_num_members); } -BOOL pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, - const DOM_SID *members, size_t num_members, - uint32 **pp_alias_rids, size_t *p_num_alias_rids) +NTSTATUS pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx, + const DOM_SID *domain_sid, + const DOM_SID *members, size_t num_members, + uint32 **pp_alias_rids, + size_t *p_num_alias_rids) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_NOT_IMPLEMENTED; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_enum_alias_memberships(pdb_context, mem_ctx, - domain_sid, - members, num_members, - pp_alias_rids, - p_num_alias_rids)); + return pdb_context->pdb_enum_alias_memberships(pdb_context, mem_ctx, + domain_sid, + members, num_members, + pp_alias_rids, + p_num_alias_rids); } NTSTATUS pdb_lookup_rids(const DOM_SID *domain_sid, @@ -1484,6 +1548,78 @@ BOOL pdb_get_seq_num(time_t *seq_num) return NT_STATUS_IS_OK(pdb_context-> pdb_get_seq_num(pdb_context, seq_num)); } + +BOOL pdb_uid_to_rid(uid_t uid, uint32 *rid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_uid_to_rid(pdb_context, uid, rid); +} + +BOOL pdb_gid_to_sid(gid_t gid, DOM_SID *sid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_gid_to_sid(pdb_context, gid, sid); +} + +BOOL pdb_sid_to_id(const DOM_SID *sid, union unid_t *id, + enum SID_NAME_USE *type) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_sid_to_id(pdb_context, sid, id, type); +} + +BOOL pdb_rid_algorithm(void) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_rid_algorithm(pdb_context); +} + +BOOL pdb_new_rid(uint32 *rid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + if (pdb_rid_algorithm()) { + DEBUG(0, ("Trying to allocate a RID when algorithmic RIDs " + "are active\n")); + return False; + } + + if (algorithmic_rid_base() != BASE_RID) { + DEBUG(0, ("'algorithmic rid base' is set but a passdb backend " + "without algorithmic RIDs is chosen.\n")); + DEBUGADD(0, ("Please map all used groups using 'net groupmap " + "add', set the maximum used RID using\n")); + DEBUGADD(0, ("'net setmaxrid' and remove the parameter\n")); + return False; + } + + return pdb_context->pdb_new_rid(pdb_context, rid); +} + /*************************************************************** Initialize the static context (at smbd startup etc). @@ -1567,6 +1703,117 @@ static NTSTATUS pdb_default_get_seq_num(struct pdb_methods *methods, time_t *seq return NT_STATUS_OK; } +static BOOL pdb_default_uid_to_rid(struct pdb_methods *methods, uid_t uid, + uint32 *rid) +{ + SAM_ACCOUNT *sampw = NULL; + struct passwd *unix_pw; + BOOL ret; + + unix_pw = sys_getpwuid( uid ); + + if ( !unix_pw ) { + DEBUG(4,("pdb_default_uid_to_rid: host has no idea of uid " + "%lu\n", (unsigned long)uid)); + return False; + } + + if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { + DEBUG(0,("pdb_default_uid_to_rid: failed to allocate " + "SAM_ACCOUNT object\n")); + return False; + } + + become_root(); + ret = NT_STATUS_IS_OK( + methods->getsampwnam(methods, sampw, unix_pw->pw_name )); + unbecome_root(); + + if (!ret) { + DEBUG(5, ("pdb_default_uid_to_rid: Did not find user " + "%s (%d)\n", unix_pw->pw_name, uid)); + pdb_free_sam(&sampw); + return False; + } + + ret = sid_peek_check_rid(get_global_sam_sid(), + pdb_get_user_sid(sampw), rid); + + if (!ret) { + DEBUG(1, ("Could not peek rid out of sid %s\n", + sid_string_static(pdb_get_user_sid(sampw)))); + } + + pdb_free_sam(&sampw); + return ret; +} + +static BOOL pdb_default_gid_to_sid(struct pdb_methods *methods, gid_t gid, + DOM_SID *sid) +{ + GROUP_MAP map; + + if (!NT_STATUS_IS_OK(methods->getgrgid(methods, &map, gid))) { + return False; + } + + sid_copy(sid, &map.sid); + return True; +} + +static BOOL pdb_default_sid_to_id(struct pdb_methods *methods, + const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type) +{ + TALLOC_CTX *mem_ctx; + BOOL ret = False; + const char *name; + uint32 rid; + + mem_ctx = talloc_new(NULL); + + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + if (sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) { + /* Here we might have users as well as groups and aliases */ + ret = lookup_global_sam_rid(mem_ctx, rid, &name, type, id); + goto done; + } + + if (sid_peek_check_rid(&global_sid_Builtin, sid, &rid)) { + /* Here we only have aliases */ + GROUP_MAP map; + if (!NT_STATUS_IS_OK(methods->getgrsid(methods, &map, *sid))) { + DEBUG(10, ("Could not find map for sid %s\n", + sid_string_static(sid))); + goto done; + } + if ((map.sid_name_use != SID_NAME_ALIAS) && + (map.sid_name_use != SID_NAME_WKN_GRP)) { + DEBUG(10, ("Map for sid %s is a %s, expected an " + "alias\n", sid_string_static(sid), + sid_type_lookup(map.sid_name_use))); + goto done; + } + + id->gid = map.gid; + *type = SID_NAME_ALIAS; + ret = True; + goto done; + } + + DEBUG(5, ("Sid %s is neither ours nor builtin, don't know it\n", + sid_string_static(sid))); + + done: + + talloc_free(mem_ctx); + return ret; +} + static void add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid, uid_t **pp_uids, size_t *p_num) { @@ -1644,7 +1891,7 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, *pp_member_rids = NULL; *p_num_members = 0; - if (!NT_STATUS_IS_OK(sid_to_gid(group, &gid))) + if (!sid_to_gid(group, &gid)) return NT_STATUS_NO_SUCH_GROUP; if(!get_memberuids(mem_ctx, gid, &uids, &num_uids)) @@ -1658,10 +1905,7 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, for (i=0; i EXIT BECOME_ROOT() */ + *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account)); + *psid_name_use = SID_NAME_USER; + + pdb_free_sam(&sam_account); + + if (unix_id == NULL) { + return True; + } + + pw = Get_Pwnam(*name); + if (pw == NULL) { + return False; + } + unix_id->uid = pw->pw_uid; + return True; + } + pdb_free_sam(&sam_account); + + ret = pdb_getgrsid(&map, sid); + unbecome_root(); + /* END BECOME_ROOT BLOCK */ + + if ( ret ) { + if (map.gid!=(gid_t)-1) { + DEBUG(5,("lookup_global_sam_rid: mapped group %s to " + "gid %u\n", map.nt_name, + (unsigned int)map.gid)); + } else { + DEBUG(5,("lookup_global_sam_rid: mapped group %s to " + "no unix gid. Returning name.\n", + map.nt_name)); + } + + *name = talloc_strdup(mem_ctx, map.nt_name); + *psid_name_use = map.sid_name_use; + + if (unix_id == NULL) { + return True; + } + + if (map.gid == (gid_t)-1) { + DEBUG(5, ("Can't find a unix id for an unmapped " + "group\n")); + return False; + } + + unix_id->gid = map.gid; + return True; + } + + return False; +} + NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, const DOM_SID *domain_sid, int num_rids, @@ -1715,7 +2045,8 @@ NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, for (i = 0; i < num_rids; i++) { const char *name; - if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i])) { + if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i], + NULL)) { names[i] = name; DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i])); have_mapped = True; @@ -1772,11 +2103,9 @@ NTSTATUS pdb_default_lookup_names(struct pdb_methods *methods, } for (i = 0; i < num_names; i++) { - const char *name; - - if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i])) { - names[i] = name; - DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i])); + if (lookup_global_sam_name(names[i], 0, &rids[i], &attrs[i])) { + DEBUG(5,("lookup_names: %s-> %d:%d\n", names[i], + rids[i], attrs[i])); have_mapped = True; } else { have_unmapped = True; @@ -2157,6 +2486,9 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) (*methods)->get_account_policy = pdb_default_get_account_policy; (*methods)->set_account_policy = pdb_default_set_account_policy; (*methods)->get_seq_num = pdb_default_get_seq_num; + (*methods)->uid_to_rid = pdb_default_uid_to_rid; + (*methods)->gid_to_sid = pdb_default_gid_to_sid; + (*methods)->sid_to_id = pdb_default_sid_to_id; (*methods)->search_users = pdb_default_search_users; (*methods)->search_groups = pdb_default_search_groups; diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index b35ce18eee..a21e976803 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -84,13 +84,12 @@ #include "smbldap.h" /********************************************************************** - Free a LDAPMessage (one is stored on the SAM_ACCOUNT). + Simple helper function to make stuff better readable **********************************************************************/ - -void private_data_free_fn(void **result) + +static LDAP *priv2ld(struct ldapsam_privates *priv) { - ldap_msgfree(*result); - *result = NULL; + return priv->smbldap_state->ldap_struct; } /********************************************************************** @@ -117,14 +116,14 @@ static const char* get_userattr_key2string( int schema_ver, int key ) Return the list of attribute names given a user schema version. **********************************************************************/ -const char** get_userattr_list( int schema_ver ) +const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver ) { switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: - return get_attr_list( attrib_map_v22 ); + return get_attr_list( mem_ctx, attrib_map_v22 ); case SCHEMAVER_SAMBASAMACCOUNT: - return get_attr_list( attrib_map_v30 ); + return get_attr_list( mem_ctx, attrib_map_v30 ); default: DEBUG(0,("get_userattr_list: unknown schema version specified!\n")); break; @@ -137,14 +136,17 @@ const char** get_userattr_list( int schema_ver ) Return the list of attribute names to delete given a user schema version. **************************************************************************/ -static const char** get_userattr_delete_list( int schema_ver ) +static const char** get_userattr_delete_list( TALLOC_CTX *mem_ctx, + int schema_ver ) { switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: - return get_attr_list( attrib_map_to_delete_v22 ); + return get_attr_list( mem_ctx, + attrib_map_to_delete_v22 ); case SCHEMAVER_SAMBASAMACCOUNT: - return get_attr_list( attrib_map_to_delete_v30 ); + return get_attr_list( mem_ctx, + attrib_map_to_delete_v30 ); default: DEBUG(0,("get_userattr_delete_list: unknown schema version specified!\n")); break; @@ -250,13 +252,6 @@ static NTSTATUS ldapsam_get_seq_num(struct pdb_methods *my_methods, time_t *seq_ LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg); if (rc != LDAP_SUCCESS) { - - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(0,("ldapsam_get_seq_num: Failed search for suffix: %s, error: %s (%s)\n", - suffix,ldap_err2string(rc), ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); goto done; } @@ -399,58 +394,37 @@ static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state, object found in search_result depending on lp_ldap_delete_dn ******************************************************************/ -static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, - LDAPMessage *result, - const char *objectclass, - const char **attrs) +static int ldapsam_delete_entry(struct ldapsam_privates *priv, + TALLOC_CTX *mem_ctx, + LDAPMessage *entry, + const char *objectclass, + const char **attrs) { - int rc; - LDAPMessage *entry = NULL; LDAPMod **mods = NULL; - char *name, *dn; + char *name; + const char *dn; BerElement *ptr = NULL; - rc = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); - - if (rc != 1) { - DEBUG(0, ("ldapsam_delete_entry: Entry must exist exactly once!\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!dn) { - return NT_STATUS_UNSUCCESSFUL; + dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry); + if (dn == NULL) { + return LDAP_NO_MEMORY; } if (lp_ldap_delete_dn()) { - NTSTATUS ret = NT_STATUS_OK; - rc = smbldap_delete(ldap_state->smbldap_state, dn); - - if (rc != LDAP_SUCCESS) { - DEBUG(0, ("ldapsam_delete_entry: Could not delete object %s\n", dn)); - ret = NT_STATUS_UNSUCCESSFUL; - } - SAFE_FREE(dn); - return ret; + return smbldap_delete(priv->smbldap_state, dn); } /* Ok, delete only the SAM attributes */ - for (name = ldap_first_attribute(ldap_state->smbldap_state->ldap_struct, entry, &ptr); + for (name = ldap_first_attribute(priv2ld(priv), entry, &ptr); name != NULL; - name = ldap_next_attribute(ldap_state->smbldap_state->ldap_struct, entry, ptr)) { + name = ldap_next_attribute(priv2ld(priv), entry, ptr)) { const char **attrib; /* We are only allowed to delete the attributes that really exist. */ for (attrib = attrs; *attrib != NULL; attrib++) { - /* Don't delete LDAP_ATTR_MOD_TIMESTAMP attribute. */ - if (strequal(*attrib, get_userattr_key2string(ldap_state->schema_ver, - LDAP_ATTR_MOD_TIMESTAMP))) { - continue; - } if (strequal(*attrib, name)) { DEBUG(10, ("ldapsam_delete_entry: deleting " "attribute %s\n", name)); @@ -458,33 +432,17 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, NULL); } } - ldap_memfree(name); } - + if (ptr != NULL) { ber_free(ptr, 0); } smbldap_set_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass); - - rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - ldap_mods_free(mods, True); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - - DEBUG(0, ("ldapsam_delete_entry: Could not delete attributes for %s, error: %s (%s)\n", - dn, ldap_err2string(rc), ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); - SAFE_FREE(dn); - return NT_STATUS_UNSUCCESSFUL; - } - - SAFE_FREE(dn); - return NT_STATUS_OK; + talloc_autofree_ldapmod(mem_ctx, mods); + + return smbldap_modify(priv->smbldap_state, dn, mods); } /* New Interface is being implemented here */ @@ -627,13 +585,16 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, return False; } - if (ldap_state->smbldap_state->ldap_struct == NULL) { - DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->ldap_struct is NULL!\n")); + if (priv2ld(ldap_state) == NULL) { + DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->" + "ldap_struct is NULL!\n")); return False; } - if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, "uid", username)) { - DEBUG(1, ("init_sam_from_ldap: No uid attribute found for this user!\n")); + if (!smbldap_get_single_pstring(priv2ld(ldap_state), entry, "uid", + username)) { + DEBUG(1, ("init_sam_from_ldap: No uid attribute found for " + "this user!\n")); return False; } @@ -992,6 +953,15 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, ZERO_STRUCT(hours); } + if (lp_parm_bool(-1, "ldapsam", "trusted", False)) { + if (smbldap_get_single_pstring(priv2ld(ldap_state), entry, + "uidNumber", temp)) { + /* We've got a uid, feed the cache */ + uid_t uid = strtoul(temp, NULL, 10); + store_uid_sid_cache(pdb_get_user_sid(sampass), uid); + } + } + /* check the timestamp of the cache vs ldap entry */ if (!(ldap_entry_time = ldapsam_get_entry_timestamp(ldap_state, entry))) @@ -1380,10 +1350,10 @@ static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update, DEBUG(10,("ldapsam_setsampwent: LDAP Query for acb_mask 0x%x will use suffix %s\n", acb_mask, suffix)); - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, ldap_state->schema_ver); rc = smbldap_search(ldap_state->smbldap_state, suffix, LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &ldap_state->result); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { DEBUG(0, ("ldapsam_setsampwent: LDAP search failed: %s\n", ldap_err2string(rc))); @@ -1421,10 +1391,12 @@ static void ldapsam_endsampwent(struct pdb_methods *my_methods) Get the next entry in the LDAP password database. *********************************************************************/ -static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user) +static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, + SAM_ACCOUNT *user) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)my_methods->private_data; BOOL bret = False; while (!bret) { @@ -1434,14 +1406,15 @@ static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT ldap_state->index++; bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry); - ldap_state->entry = ldap_next_entry(ldap_state->smbldap_state->ldap_struct, - ldap_state->entry); + ldap_state->entry = ldap_next_entry(priv2ld(ldap_state), + ldap_state->entry); } return NT_STATUS_OK; } -static void append_attr(const char ***attr_list, const char *new_attr) +static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list, + const char *new_attr) { int i; @@ -1453,9 +1426,10 @@ static void append_attr(const char ***attr_list, const char *new_attr) ; } - (*attr_list) = SMB_REALLOC_ARRAY((*attr_list), const char *, i+2); + (*attr_list) = TALLOC_REALLOC_ARRAY(mem_ctx, (*attr_list), + const char *, i+2); SMB_ASSERT((*attr_list) != NULL); - (*attr_list)[i] = SMB_STRDUP(new_attr); + (*attr_list)[i] = talloc_strdup((*attr_list), new_attr); (*attr_list)[i+1] = NULL; } @@ -1473,10 +1447,14 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT const char ** attr_list; int rc; - attr_list = get_userattr_list( ldap_state->schema_ver ); - append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP)); - rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); - free_attr_list( attr_list ); + attr_list = get_userattr_list( user->mem_ctx, ldap_state->schema_ver ); + append_attr(user->mem_ctx, &attr_list, + get_userattr_key2string(ldap_state->schema_ver, + LDAP_ATTR_MOD_TIMESTAMP)); + append_attr(user->mem_ctx, &attr_list, "uidNumber"); + rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, + attr_list); + talloc_free( attr_list ); if ( rc != LDAP_SUCCESS ) return NT_STATUS_NO_SUCH_USER; @@ -1500,9 +1478,9 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT ldap_msgfree(result); return NT_STATUS_NO_SUCH_USER; } - pdb_set_backend_private_data(user, result, - private_data_free_fn, + pdb_set_backend_private_data(user, result, NULL, my_methods, PDB_CHANGED); + talloc_autofree_ldapmsg(user->mem_ctx, result); ret = NT_STATUS_OK; } else { ldap_msgfree(result); @@ -1518,24 +1496,37 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, uint32 rid; switch ( ldap_state->schema_ver ) { - case SCHEMAVER_SAMBASAMACCOUNT: - attr_list = get_userattr_list(ldap_state->schema_ver); - append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP)); - rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list); - free_attr_list( attr_list ); + case SCHEMAVER_SAMBASAMACCOUNT: { + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return LDAP_NO_MEMORY; + } + + attr_list = get_userattr_list(tmp_ctx, + ldap_state->schema_ver); + append_attr(tmp_ctx, &attr_list, + get_userattr_key2string( + ldap_state->schema_ver, + LDAP_ATTR_MOD_TIMESTAMP)); + append_attr(tmp_ctx, &attr_list, "uidNumber"); + rc = ldapsam_search_suffix_by_sid(ldap_state, sid, + result, attr_list); + talloc_free(tmp_ctx); if ( rc != LDAP_SUCCESS ) return rc; break; + } case SCHEMAVER_SAMBAACCOUNT: if (!sid_peek_check_rid(&ldap_state->domain_sid, sid, &rid)) { return rc; } - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, + ldap_state->schema_ver); rc = ldapsam_search_suffix_by_rid(ldap_state, rid, result, attr_list ); - free_attr_list( attr_list ); + talloc_free( attr_list ); if ( rc != LDAP_SUCCESS ) return rc; @@ -1588,9 +1579,9 @@ static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT return NT_STATUS_NO_SUCH_USER; } - pdb_set_backend_private_data(user, result, - private_data_free_fn, + pdb_set_backend_private_data(user, result, NULL, my_methods, PDB_CHANGED); + talloc_autofree_ldapmsg(user->mem_ctx, result); return NT_STATUS_OK; } @@ -1639,14 +1630,6 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, } if (rc!=LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(1, ("ldapsam_modify_entry: Failed to %s user dn= %s with: %s\n\t%s\n", - ldap_op == LDAP_MOD_ADD ? "add" : "modify", - dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); return NT_STATUS_UNSUCCESSFUL; } } @@ -1747,15 +1730,17 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, Delete entry from LDAP for username. *********************************************************************/ -static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct) +static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, + SAM_ACCOUNT * sam_acct) { - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *priv = + (struct ldapsam_privates *)my_methods->private_data; const char *sname; int rc; - LDAPMessage *result = NULL; - NTSTATUS ret; + LDAPMessage *msg, *entry; + NTSTATUS result = NT_STATUS_NO_MEMORY; const char **attr_list; - fstring objclass; + TALLOC_CTX *mem_ctx; if (!sam_acct) { DEBUG(0, ("ldapsam_delete_sam_account: sam_acct was NULL!\n")); @@ -1764,35 +1749,42 @@ static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_A sname = pdb_get_username(sam_acct); - DEBUG (3, ("ldapsam_delete_sam_account: Deleting user %s from LDAP.\n", sname)); + DEBUG(3, ("ldapsam_delete_sam_account: Deleting user %s from " + "LDAP.\n", sname)); - attr_list= get_userattr_delete_list( ldap_state->schema_ver ); - rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + goto done; + } - if (rc != LDAP_SUCCESS) { - free_attr_list( attr_list ); - return NT_STATUS_NO_SUCH_USER; + attr_list = get_userattr_delete_list(mem_ctx, priv->schema_ver ); + if (attr_list == NULL) { + goto done; } - - switch ( ldap_state->schema_ver ) { - case SCHEMAVER_SAMBASAMACCOUNT: - fstrcpy( objclass, LDAP_OBJ_SAMBASAMACCOUNT ); - break; - - case SCHEMAVER_SAMBAACCOUNT: - fstrcpy( objclass, LDAP_OBJ_SAMBAACCOUNT ); - break; - default: - fstrcpy( objclass, "UNKNOWN" ); - DEBUG(0,("ldapsam_delete_sam_account: Unknown schema version specified!\n")); - break; + + rc = ldapsam_search_suffix_by_name(priv, sname, &msg, attr_list); + + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(priv2ld(priv), msg) != 1) || + ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) { + DEBUG(5, ("Could not find user %s\n", sname)); + result = NT_STATUS_NO_SUCH_USER; + goto done; } + + rc = ldapsam_delete_entry( + priv, mem_ctx, entry, + priv->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ? + LDAP_OBJ_SAMBASAMACCOUNT : LDAP_OBJ_SAMBAACCOUNT, + attr_list); - ret = ldapsam_delete_entry(ldap_state, result, objclass, attr_list ); - ldap_msgfree(result); - free_attr_list( attr_list ); + result = (rc == LDAP_SUCCESS) ? + NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; - return ret; + done: + talloc_free(mem_ctx); + return result; } /********************************************************************** @@ -1823,13 +1815,15 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A result = pdb_get_backend_private_data(newpwd, my_methods); if (!result) { - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, ldap_state->schema_ver); rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list ); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; } - pdb_set_backend_private_data(newpwd, result, private_data_free_fn, my_methods, PDB_CHANGED); + pdb_set_backend_private_data(newpwd, result, NULL, + my_methods, PDB_CHANGED); + talloc_autofree_ldapmsg(newpwd->mem_ctx, result); } if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { @@ -1866,12 +1860,6 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A SAFE_FREE(dn); if (!NT_STATUS_IS_OK(ret)) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0,("ldapsam_update_sam_account: failed to modify user with uid = %s, error: %s (%s)\n", - pdb_get_username(newpwd), ld_error?ld_error:"(unknwon)", ldap_err2string(rc))); - SAFE_FREE(ld_error); return ret; } @@ -1966,12 +1954,12 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO } /* free this list after the second search or in case we exit on failure */ - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, ldap_state->schema_ver); rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list); if (rc != LDAP_SUCCESS) { - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } @@ -1979,7 +1967,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO DEBUG(0,("ldapsam_add_sam_account: User '%s' already in the base, with samba attributes\n", username)); ldap_msgfree(result); - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } ldap_msgfree(result); @@ -1992,7 +1980,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) { DEBUG(0,("ldapsam_add_sam_account: SID '%s' already in the base, with samba attributes\n", sid_to_string(sid_string, sid))); - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2011,7 +1999,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, attr_list, &result); if ( rc != LDAP_SUCCESS ) { - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } @@ -2019,7 +2007,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO if (num_result > 1) { DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n")); - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2033,7 +2021,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result); tmp = smbldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry); if (!tmp) { - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2059,7 +2047,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO filter, attr_list, &result); if ( rc != LDAP_SUCCESS ) { - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } @@ -2067,7 +2055,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO if (num_result > 1) { DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n")); - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2081,7 +2069,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result); tmp = smbldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry); if (!tmp) { - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2090,7 +2078,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO } } - free_attr_list( attr_list ); + talloc_free( attr_list ); if (num_result == 0) { /* Check if we need to add an entry */ @@ -2155,23 +2143,11 @@ static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state, int rc; const char **attr_list; - attr_list = get_attr_list(groupmap_attr_list); + attr_list = get_attr_list(NULL, groupmap_attr_list); rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix (), scope, filter, attr_list, 0, result); - free_attr_list( attr_list ); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, ("ldapsam_search_one_group: " - "Problem during the LDAP search: LDAP error: %s (%s)\n", - ld_error?ld_error:"(unknown)", ldap_err2string(rc))); - DEBUGADD(3, ("ldapsam_search_one_group: Query was: %s, %s\n", - lp_ldap_group_suffix(), filter)); - SAFE_FREE(ld_error); - } + talloc_free(attr_list); return rc; } @@ -2245,39 +2221,10 @@ for gidNumber(%lu)\n",(unsigned long)map->gid)); } fstrcpy(map->comment, temp); - return True; -} - -/********************************************************************** - *********************************************************************/ - -static BOOL init_ldap_from_group(LDAP *ldap_struct, - LDAPMessage *existing, - LDAPMod ***mods, - const GROUP_MAP *map) -{ - pstring tmp; - - if (mods == NULL || map == NULL) { - DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n")); - return False; + if (lp_parm_bool(-1, "ldapsam", "trusted", False)) { + store_gid_sid_cache(&map->sid, map->gid); } - *mods = NULL; - - sid_to_string(tmp, &map->sid); - - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID), tmp); - pstr_sprintf(tmp, "%i", map->sid_name_use); - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), tmp); - - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), map->nt_name); - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), map->comment); - return True; } @@ -2299,7 +2246,7 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, return NT_STATUS_NO_SUCH_GROUP; } - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + count = ldap_count_entries(priv2ld(ldap_state), result); if (count < 1) { DEBUG(4, ("ldapsam_getgroup: Did not find group\n")); @@ -2308,13 +2255,13 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, } if (count > 1) { - DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: count=%d\n", - filter, count)); + DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: " + "count=%d\n", filter, count)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_GROUP; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + entry = ldap_first_entry(priv2ld(ldap_state), result); if (!entry) { ldap_msgfree(result); @@ -2322,8 +2269,8 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, } if (!init_group_from_ldap(ldap_state, map, entry)) { - DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for group filter %s\n", - filter)); + DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for " + "group filter %s\n", filter)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_GROUP; } @@ -2458,11 +2405,6 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, char *tmp; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - if (!lp_parm_bool(-1, "ldapsam", "trusted", False)) - return pdb_default_enum_group_members(methods, mem_ctx, group, - pp_member_rids, - p_num_members); - *pp_member_rids = NULL; *p_num_members = 0; @@ -2618,9 +2560,10 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, } static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, - const char *username, - gid_t primary_gid, - DOM_SID **pp_sids, gid_t **pp_gids, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, + DOM_SID **pp_sids, + gid_t **pp_gids, size_t *p_num_groups) { struct ldapsam_privates *ldap_state = @@ -2634,23 +2577,24 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, LDAPMessage *entry; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; size_t num_sids, num_gids; - - if (!lp_parm_bool(-1, "ldapsam", "trusted", False)) - return pdb_default_enum_group_memberships(methods, username, - primary_gid, pp_sids, - pp_gids, p_num_groups); + gid_t primary_gid; *pp_sids = NULL; num_sids = 0; - escape_name = escape_ldap_string_alloc(username); + if (!sid_to_gid(pdb_get_group_sid(user), &primary_gid)) { + DEBUG(1, ("sid_to_gid failed for user's primary group\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + escape_name = escape_ldap_string_alloc(pdb_get_username(user)); if (escape_name == NULL) return NT_STATUS_NO_MEMORY; pstr_sprintf(filter, "(&(objectClass=posixGroup)" "(|(memberUid=%s)(gidNumber=%d)))", - username, primary_gid); + escape_name, primary_gid); rc = smbldap_search(conn, lp_ldap_group_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg); @@ -2666,11 +2610,11 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, /* We need to add the primary group as the first gid/sid */ - add_gid_to_array_unique(NULL, primary_gid, pp_gids, &num_gids); + add_gid_to_array_unique(mem_ctx, primary_gid, pp_gids, &num_gids); /* This sid will be replaced later */ - add_sid_to_array_unique(NULL, &global_sid_NULL, pp_sids, &num_sids); + add_sid_to_array_unique(mem_ctx, &global_sid_NULL, pp_sids, &num_sids); for (entry = ldap_first_entry(conn->ldap_struct, msg); entry != NULL; @@ -2702,13 +2646,16 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, if (gid == primary_gid) { sid_copy(&(*pp_sids)[0], &sid); } else { - add_gid_to_array_unique(NULL, gid, pp_gids, &num_gids); - add_sid_to_array_unique(NULL, &sid, pp_sids, &num_sids); + add_gid_to_array_unique(mem_ctx, gid, pp_gids, + &num_gids); + add_sid_to_array_unique(mem_ctx, &sid, pp_sids, + &num_sids); } } if (sid_compare(&global_sid_NULL, &(*pp_sids)[0]) == 0) { - DEBUG(3, ("primary group of [%s] not found\n", username)); + DEBUG(3, ("primary group of [%s] not found\n", + pdb_get_username(user))); goto done; } @@ -2726,143 +2673,203 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, } /********************************************************************** + * Augment a posixGroup object with a sambaGroupMapping domgroup *********************************************************************/ -static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state, - gid_t gid, - LDAPMessage **result) +static NTSTATUS ldapsam_map_posixgroup(TALLOC_CTX *mem_ctx, + struct ldapsam_privates *ldap_state, + GROUP_MAP *map) { - pstring filter; + const char *filter, *dn; + LDAPMessage *msg, *entry; + LDAPMod **mods; + int rc; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%lu))", - LDAP_OBJ_POSIXGROUP, LDAP_OBJ_IDMAP_ENTRY, - get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), - (unsigned long)gid); + filter = talloc_asprintf(mem_ctx, + "(&(objectClass=posixGroup)(gidNumber=%u))", + map->gid); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; + } - return ldapsam_search_one_group(ldap_state, filter, result); -} + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, + get_attr_list(mem_ctx, groupmap_attr_list), + &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); -/********************************************************************** - *********************************************************************/ + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) || + ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) { + return NT_STATUS_NO_SUCH_GROUP; + } + + dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry); + if (dn == NULL) { + return NT_STATUS_NO_MEMORY; + } + + mods = NULL; + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", + "sambaGroupMapping"); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaSid", + sid_string_static(&map->sid)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaGroupType", + talloc_asprintf(mem_ctx, "%d", map->sid_name_use)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName", + map->nt_name); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "description", + map->comment); + talloc_autofree_ldapmod(mem_ctx, mods); + + rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); + if (rc != LDAP_SUCCESS) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods, GROUP_MAP *map) { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; - LDAPMessage *result = NULL; + LDAPMessage *msg = NULL; LDAPMod **mods = NULL; - int count; + const char *attrs[] = { NULL }; + char *filter; - char *tmp; - pstring dn; - LDAPMessage *entry; + char *dn; + TALLOC_CTX *mem_ctx; + NTSTATUS result; - GROUP_MAP dummy; + DOM_SID sid; int rc; - if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy, - map->gid))) { - DEBUG(0, ("ldapsam_add_group_mapping_entry: Group %ld already exists in LDAP\n", (unsigned long)map->gid)); - return NT_STATUS_UNSUCCESSFUL; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } - rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result); - if (rc != LDAP_SUCCESS) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + filter = talloc_asprintf(mem_ctx, "(sambaSid=%s)", + sid_string_static(&map->sid)); + if (filter == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(), + LDAP_SCOPE_SUBTREE, filter, attrs, True, &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); - if ( count == 0 ) { - /* There's no posixGroup account, let's try to find an - * appropriate idmap entry for aliases */ - - pstring suffix; - pstring filter; - const char **attr_list; - - ldap_msgfree(result); + if ((rc == LDAP_SUCCESS) && + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) > 0)) { - pstrcpy( suffix, lp_ldap_idmap_suffix() ); - pstr_sprintf(filter, "(&(objectClass=%s)(%s=%u))", - LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_GIDNUMBER, - map->gid); - - attr_list = get_attr_list( sidmap_attr_list ); - rc = smbldap_search(ldap_state->smbldap_state, suffix, - LDAP_SCOPE_SUBTREE, filter, attr_list, - 0, &result); + DEBUG(3, ("SID %s already present in LDAP, refusing to add " + "group mapping entry\n", + sid_string_static(&map->sid))); + result = NT_STATUS_GROUP_EXISTS; + goto done; + } - free_attr_list(attr_list); + switch (map->sid_name_use) { - if (rc != LDAP_SUCCESS) { - DEBUG(3,("Failure looking up entry (%s)\n", - ldap_err2string(rc) )); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + case SID_NAME_DOM_GRP: + /* To map a domain group we need to have a posix group + to attach to. */ + result = ldapsam_map_posixgroup(mem_ctx, ldap_state, map); + goto done; + break; + + case SID_NAME_ALIAS: + if (!sid_check_is_in_our_domain(&map->sid)) { + DEBUG(3, ("Refusing to map sid %s as an alias, not " + "in our domain\n", + sid_string_static(&map->sid))); + result = NT_STATUS_INVALID_PARAMETER; + goto done; } - } - - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); - if ( count == 0 ) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; - } + break; + + case SID_NAME_WKN_GRP: + if (!sid_check_is_in_builtin(&map->sid)) { + DEBUG(3, ("Refusing to map sid %s as an alias, not " + "in builtin domain\n", + sid_string_static(&map->sid))); + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + break; - if (count > 1) { - DEBUG(2, ("ldapsam_add_group_mapping_entry: Group %lu must exist exactly once in LDAP\n", - (unsigned long)map->gid)); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + default: + DEBUG(3, ("Got invalid use '%s' for mapping\n", + sid_type_lookup(map->sid_name_use))); + result = NT_STATUS_INVALID_PARAMETER; + goto done; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); - tmp = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!tmp) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + /* Domain groups have been mapped in a separate routine, we have to + * create an alias now */ + + if (map->gid == -1) { + DEBUG(10, ("Refusing to map gid==-1\n")); + result = NT_STATUS_INVALID_PARAMETER; + goto done; } - pstrcpy(dn, tmp); - SAFE_FREE(tmp); - if (!init_ldap_from_group(ldap_state->smbldap_state->ldap_struct, - result, &mods, map)) { - DEBUG(0, ("ldapsam_add_group_mapping_entry: init_ldap_from_group failed!\n")); - ldap_mods_free(mods, True); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + if (pdb_gid_to_sid(map->gid, &sid)) { + DEBUG(3, ("Gid %d is already mapped to SID %s, refusing to " + "add\n", map->gid, sid_string_static(&sid))); + result = NT_STATUS_GROUP_EXISTS; + goto done; } - ldap_msgfree(result); + /* Ok, enough checks done. It's still racy to go ahead now, but that's + * the best we can get out of LDAP. */ - if (mods == NULL) { - DEBUG(0, ("ldapsam_add_group_mapping_entry: mods is empty\n")); - return NT_STATUS_UNSUCCESSFUL; + dn = talloc_asprintf(mem_ctx, "sambaSid=%s,%s", + sid_string_static(&map->sid), + lp_ldap_group_suffix()); + if (dn == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } - smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP ); + mods = NULL; - rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - ldap_mods_free(mods, True); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "objectClass", + "sambaSidEntry"); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "objectClass", + "sambaGroupMapping"); - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, ("ldapsam_add_group_mapping_entry: failed to add group %lu error: %s (%s)\n", (unsigned long)map->gid, - ld_error ? ld_error : "(unknown)", ldap_err2string(rc))); - SAFE_FREE(ld_error); - return NT_STATUS_UNSUCCESSFUL; - } + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "sambaSid", + sid_string_static(&map->sid)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "sambaGroupType", + talloc_asprintf(mem_ctx, "%d", map->sid_name_use)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "displayName", + map->nt_name); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "description", + map->comment); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "gidNumber", + talloc_asprintf(mem_ctx, "%u", map->gid)); + talloc_autofree_ldapmod(mem_ctx, mods); - DEBUG(2, ("ldapsam_add_group_mapping_entry: successfully modified group %lu in LDAP\n", (unsigned long)map->gid)); - return NT_STATUS_OK; + rc = smbldap_add(ldap_state->smbldap_state, dn, mods); + + result = (rc == LDAP_SUCCESS) ? + NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + + done: + talloc_free(mem_ctx); + return result; } /********************************************************************** + * Update a group mapping entry. We're quite strict about what can be changed: + * Only the description and displayname may be changed. It simply does not + * make any sense to change the SID, gid or the type in a mapping. *********************************************************************/ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods, @@ -2871,63 +2878,80 @@ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods, struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; int rc; - char *dn = NULL; - LDAPMessage *result = NULL; + const char *filter, *dn; + LDAPMessage *msg = NULL; LDAPMessage *entry = NULL; LDAPMod **mods = NULL; + TALLOC_CTX *mem_ctx; + NTSTATUS result; - rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } - if (rc != LDAP_SUCCESS) { - return NT_STATUS_UNSUCCESSFUL; + /* Make 100% sure that sid, gid and type are not changed by looking up + * exactly the values we're given in LDAP. */ + + filter = talloc_asprintf(mem_ctx, "(&(objectClass=sambaGroupMapping)" + "(sambaSid=%s)(gidNumber=%u)" + "(sambaGroupType=%d))", + sid_string_static(&map->sid), map->gid, + map->sid_name_use); + if (filter == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } - if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { - DEBUG(0, ("ldapsam_update_group_mapping_entry: No group to modify!\n")); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, + get_attr_list(mem_ctx, groupmap_attr_list), + &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); + + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) || + ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) { + result = NT_STATUS_NO_SUCH_GROUP; + goto done; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry); - if (!init_ldap_from_group(ldap_state->smbldap_state->ldap_struct, - result, &mods, map)) { - DEBUG(0, ("ldapsam_update_group_mapping_entry: init_ldap_from_group failed\n")); - ldap_msgfree(result); - if (mods != NULL) - ldap_mods_free(mods,True); - return NT_STATUS_UNSUCCESSFUL; + if (dn == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } + mods = NULL; + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName", + map->nt_name); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "description", + map->comment); + talloc_autofree_ldapmod(mem_ctx, mods); + if (mods == NULL) { - DEBUG(4, ("ldapsam_update_group_mapping_entry: mods is empty: nothing to do\n")); - ldap_msgfree(result); - return NT_STATUS_OK; + DEBUG(4, ("ldapsam_update_group_mapping_entry: mods is empty: " + "nothing to do\n")); + result = NT_STATUS_OK; + goto done; } - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!dn) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; - } rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - SAFE_FREE(dn); - - ldap_mods_free(mods, True); - ldap_msgfree(result); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, ("ldapsam_update_group_mapping_entry: failed to modify group %lu error: %s (%s)\n", (unsigned long)map->gid, - ld_error ? ld_error : "(unknown)", ldap_err2string(rc))); - SAFE_FREE(ld_error); - return NT_STATUS_UNSUCCESSFUL; + result = NT_STATUS_ACCESS_DENIED; + goto done; } - DEBUG(2, ("ldapsam_update_group_mapping_entry: successfully modified group %lu in LDAP\n", (unsigned long)map->gid)); - return NT_STATUS_OK; + DEBUG(2, ("ldapsam_update_group_mapping_entry: successfully modified " + "group %lu in LDAP\n", (unsigned long)map->gid)); + + result = NT_STATUS_OK; + + done: + talloc_free(mem_ctx); + return result; } /********************************************************************** @@ -2936,53 +2960,103 @@ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods, static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods, DOM_SID sid) { - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; - pstring sidstring, filter; - LDAPMessage *result = NULL; + struct ldapsam_privates *priv = + (struct ldapsam_privates *)methods->private_data; + LDAPMessage *msg, *entry; int rc; - NTSTATUS ret; - const char **attr_list; + NTSTATUS result; + TALLOC_CTX *mem_ctx; + char *filter; - sid_to_string(sidstring, &sid); - - pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", - LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, sidstring); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } - rc = ldapsam_search_one_group(ldap_state, filter, &result); + filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))", + LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, + sid_string_static(&sid)); + if (filter == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + rc = smbldap_search_suffix(priv->smbldap_state, filter, + get_attr_list(mem_ctx, groupmap_attr_list), + &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); - if (rc != LDAP_SUCCESS) { - return NT_STATUS_NO_SUCH_GROUP; + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(priv2ld(priv), msg) != 1) || + ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) { + result = NT_STATUS_NO_SUCH_GROUP; + goto done; + } + + rc = ldapsam_delete_entry(priv, mem_ctx, entry, LDAP_OBJ_GROUPMAP, + get_attr_list(mem_ctx, + groupmap_attr_list_to_delete)); + + if ((rc == LDAP_NAMING_VIOLATION) || + (rc == LDAP_OBJECT_CLASS_VIOLATION)) { + const char *attrs[] = { "sambaGroupType", "description", + "displayName", "sambaSIDList", + NULL }; + + /* Second try. Don't delete the sambaSID attribute, this is + for "old" entries that are tacked on a winbind + sambaIdmapEntry. */ + + rc = ldapsam_delete_entry(priv, mem_ctx, entry, + LDAP_OBJ_GROUPMAP, attrs); } - attr_list = get_attr_list( groupmap_attr_list_to_delete ); - ret = ldapsam_delete_entry(ldap_state, result, LDAP_OBJ_GROUPMAP, attr_list); - free_attr_list ( attr_list ); + if ((rc == LDAP_NAMING_VIOLATION) || + (rc == LDAP_OBJECT_CLASS_VIOLATION)) { + const char *attrs[] = { "sambaGroupType", "description", + "displayName", "sambaSIDList", + "gidNumber", NULL }; - ldap_msgfree(result); + /* Third try. This is a post-3.0.21 alias (containing only + * sambaSidEntry and sambaGroupMapping classes), we also have + * to delete the gidNumber attribute, only the sambaSidEntry + * remains */ - return ret; -} + rc = ldapsam_delete_entry(priv, mem_ctx, entry, + LDAP_OBJ_GROUPMAP, attrs); + } + + result = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + + done: + talloc_free(mem_ctx); + return result; + } /********************************************************************** *********************************************************************/ -static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, BOOL update) +static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, + BOOL update) { - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)my_methods->private_data; fstring filter; int rc; const char **attr_list; pstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_GROUPMAP); - attr_list = get_attr_list( groupmap_attr_list ); + attr_list = get_attr_list( NULL, groupmap_attr_list ); rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(), LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &ldap_state->result); - free_attr_list( attr_list ); + talloc_free(attr_list); if (rc != LDAP_SUCCESS) { - DEBUG(0, ("ldapsam_setsamgrent: LDAP search failed: %s\n", ldap_err2string(rc))); - DEBUG(3, ("ldapsam_setsamgrent: Query was: %s, %s\n", lp_ldap_group_suffix(), filter)); + DEBUG(0, ("ldapsam_setsamgrent: LDAP search failed: %s\n", + ldap_err2string(rc))); + DEBUG(3, ("ldapsam_setsamgrent: Query was: %s, %s\n", + lp_ldap_group_suffix(), filter)); ldap_msgfree(ldap_state->result); ldap_state->result = NULL; return NT_STATUS_UNSUCCESSFUL; @@ -2992,7 +3066,9 @@ static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, BOOL update) ldap_count_entries(ldap_state->smbldap_state->ldap_struct, ldap_state->result))); - ldap_state->entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, ldap_state->result); + ldap_state->entry = + ldap_first_entry(ldap_state->smbldap_state->ldap_struct, + ldap_state->result); ldap_state->index = 0; return NT_STATUS_OK; @@ -3013,7 +3089,8 @@ static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods, GROUP_MAP *map) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)my_methods->private_data; BOOL bret = False; while (!bret) { @@ -3021,10 +3098,12 @@ static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods, return ret; ldap_state->index++; - bret = init_group_from_ldap(ldap_state, map, ldap_state->entry); + bret = init_group_from_ldap(ldap_state, map, + ldap_state->entry); - ldap_state->entry = ldap_next_entry(ldap_state->smbldap_state->ldap_struct, - ldap_state->entry); + ldap_state->entry = + ldap_next_entry(ldap_state->smbldap_state->ldap_struct, + ldap_state->entry); } return NT_STATUS_OK; @@ -3035,7 +3114,8 @@ static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods, static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods, enum SID_NAME_USE sid_name_use, - GROUP_MAP **pp_rmap, size_t *p_num_entries, + GROUP_MAP **pp_rmap, + size_t *p_num_entries, BOOL unix_only) { GROUP_MAP map; @@ -3046,24 +3126,28 @@ static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods, *pp_rmap = NULL; if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) { - DEBUG(0, ("ldapsam_enum_group_mapping: Unable to open passdb\n")); + DEBUG(0, ("ldapsam_enum_group_mapping: Unable to open " + "passdb\n")); return NT_STATUS_ACCESS_DENIED; } while (NT_STATUS_IS_OK(ldapsam_getsamgrent(methods, &map))) { if (sid_name_use != SID_NAME_UNKNOWN && sid_name_use != map.sid_name_use) { - DEBUG(11,("ldapsam_enum_group_mapping: group %s is not of the requested type\n", map.nt_name)); + DEBUG(11,("ldapsam_enum_group_mapping: group %s is " + "not of the requested type\n", map.nt_name)); continue; } if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) { - DEBUG(11,("ldapsam_enum_group_mapping: group %s is non mapped\n", map.nt_name)); + DEBUG(11,("ldapsam_enum_group_mapping: group %s is " + "non mapped\n", map.nt_name)); continue; } mapt=SMB_REALLOC_ARRAY((*pp_rmap), GROUP_MAP, entries+1); if (!mapt) { - DEBUG(0,("ldapsam_enum_group_mapping: Unable to enlarge group map!\n")); + DEBUG(0,("ldapsam_enum_group_mapping: Unable to " + "enlarge group map!\n")); SAFE_FREE(*pp_rmap); return NT_STATUS_UNSUCCESSFUL; } @@ -3095,14 +3179,28 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, int count; LDAPMod **mods = NULL; int rc; + enum SID_NAME_USE type = SID_NAME_USE_NONE; pstring filter; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%s))", - LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY, - get_attr_key2string(groupmap_attr_list, - LDAP_ATTR_GROUP_SID), - sid_string_static(alias)); + if (sid_check_is_in_builtin(alias)) { + type = SID_NAME_WKN_GRP; + } + + if (sid_check_is_in_our_domain(alias)) { + type = SID_NAME_ALIAS; + } + + if (type == SID_NAME_USE_NONE) { + DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n", + sid_string_static(alias))); + return NT_STATUS_NO_SUCH_ALIAS; + } + + pstr_sprintf(filter, + "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))", + LDAP_OBJ_GROUPMAP, sid_string_static(alias), + type); if (ldapsam_search_one_group(ldap_state, filter, &result) != LDAP_SUCCESS) @@ -3118,8 +3216,8 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, } if (count > 1) { - DEBUG(1, ("ldapsam_modify_aliasmem: Duplicate entries for filter %s: " - "count=%d\n", filter, count)); + DEBUG(1, ("ldapsam_modify_aliasmem: Duplicate entries for " + "filter %s: count=%d\n", filter, count)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_ALIAS; } @@ -3147,22 +3245,20 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, ldap_mods_free(mods, True); ldap_msgfree(result); + SAFE_FREE(dn); + + if (rc == LDAP_TYPE_OR_VALUE_EXISTS) { + return NT_STATUS_MEMBER_IN_ALIAS; + } + + if (rc == LDAP_NO_SUCH_ATTRIBUTE) { + return NT_STATUS_MEMBER_NOT_IN_ALIAS; + } if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING,&ld_error); - - DEBUG(0, ("ldapsam_modify_aliasmem: Could not modify alias " - "for %s, error: %s (%s)\n", dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); - SAFE_FREE(dn); return NT_STATUS_UNSUCCESSFUL; } - SAFE_FREE(dn); - return NT_STATUS_OK; } @@ -3182,7 +3278,8 @@ static NTSTATUS ldapsam_del_aliasmem(struct pdb_methods *methods, } static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods, - const DOM_SID *alias, DOM_SID **pp_members, + const DOM_SID *alias, + DOM_SID **pp_members, size_t *p_num_members) { struct ldapsam_privates *ldap_state = @@ -3194,15 +3291,29 @@ static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods, int i; pstring filter; size_t num_members = 0; + enum SID_NAME_USE type = SID_NAME_USE_NONE; *pp_members = NULL; *p_num_members = 0; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%s))", - LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY, - get_attr_key2string(groupmap_attr_list, - LDAP_ATTR_GROUP_SID), - sid_string_static(alias)); + if (sid_check_is_in_builtin(alias)) { + type = SID_NAME_WKN_GRP; + } + + if (sid_check_is_in_our_domain(alias)) { + type = SID_NAME_ALIAS; + } + + if (type == SID_NAME_USE_NONE) { + DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n", + sid_string_static(alias))); + return NT_STATUS_NO_SUCH_ALIAS; + } + + pstr_sprintf(filter, + "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))", + LDAP_OBJ_GROUPMAP, sid_string_static(alias), + type); if (ldapsam_search_one_group(ldap_state, filter, &result) != LDAP_SUCCESS) @@ -3218,8 +3329,8 @@ static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods, } if (count > 1) { - DEBUG(1, ("ldapsam_enum_aliasmem: Duplicate entries for filter %s: " - "count=%d\n", filter, count)); + DEBUG(1, ("ldapsam_enum_aliasmem: Duplicate entries for " + "filter %s: count=%d\n", filter, count)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_ALIAS; } @@ -3279,14 +3390,25 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods, int i; int rc; char *filter; + enum SID_NAME_USE type = SID_NAME_USE_NONE; + + if (sid_check_is_builtin(domain_sid)) { + type = SID_NAME_WKN_GRP; + } - /* This query could be further optimized by adding a - (&(sambaSID=*)) so that only those aliases that are - asked for in the getuseraliases are returned. */ + if (sid_check_is_domain(domain_sid)) { + type = SID_NAME_ALIAS; + } + + if (type == SID_NAME_USE_NONE) { + DEBUG(5, ("SID %s is neither builtin nor domain!\n", + sid_string_static(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } filter = talloc_asprintf(mem_ctx, - "(&(|(objectclass=%s)(objectclass=%s))(|", - LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY); + "(&(|(objectclass=%s)(sambaGroupType=%d))(|", + LDAP_OBJ_GROUPMAP, type); for (i=0; ismbldap_state, ldap_state->domain_dn, mods); + rc = smbldap_modify(ldap_state->smbldap_state, ldap_state->domain_dn, + mods); ldap_mods_free(mods, True); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING,&ld_error); - - DEBUG(0, ("ldapsam_set_account_policy_in_ldap: Could not set account policy " - "for %s, error: %s (%s)\n", ldap_state->domain_dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); return ntstatus; } if (!cache_account_policy_set(policy_index, value)) { - DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to update local tdb cache\n")); + DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to " + "update local tdb cache\n")); return ntstatus; } return NT_STATUS_OK; } -static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods, int policy_index, uint32 value) +static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods, + int policy_index, uint32 value) { if (!account_policy_migrated(False)) { - return (account_policy_set(policy_index, value)) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return (account_policy_set(policy_index, value)) ? + NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } - return ldapsam_set_account_policy_in_ldap(methods, policy_index, value); + return ldapsam_set_account_policy_in_ldap(methods, policy_index, + value); } -static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods, int policy_index, uint32 *value) +static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods, + int policy_index, + uint32 *value) { NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; LDAPMessage *result = NULL; @@ -3419,7 +3543,8 @@ static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods policy_attr = get_account_policy_attr(policy_index); if (!policy_attr) { - DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid policy index: %d\n", policy_index)); + DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid " + "policy index: %d\n", policy_index)); return ntstatus; } @@ -3427,31 +3552,24 @@ static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods attrs[1] = NULL; rc = smbldap_search(ldap_state->smbldap_state, ldap_state->domain_dn, - LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &result); + LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, + &result); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING,&ld_error); - - DEBUG(3, ("ldapsam_get_account_policy_from_ldap: Could not get account policy " - "for %s, error: %s (%s)\n", ldap_state->domain_dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); return ntstatus; } - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + count = ldap_count_entries(priv2ld(ldap_state), result); if (count < 1) { goto out; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + entry = ldap_first_entry(priv2ld(ldap_state), result); if (entry == NULL) { goto out; } - vals = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, policy_attr); + vals = ldap_get_values(priv2ld(ldap_state), entry, policy_attr); if (vals == NULL) { goto out; } @@ -3470,7 +3588,8 @@ out: /* wrapper around ldapsam_get_account_policy_from_ldap(), handles tdb as cache - - if user hasn't decided to use account policies inside LDAP just reuse the old tdb values + - if user hasn't decided to use account policies inside LDAP just reuse the + old tdb values - if there is a valid cache entry, return that - if there is an LDAP entry, update cache and return @@ -3478,32 +3597,38 @@ out: Guenther */ -static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, int policy_index, uint32 *value) +static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, + int policy_index, uint32 *value) { NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; if (!account_policy_migrated(False)) { - return (account_policy_get(policy_index, value)) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return (account_policy_get(policy_index, value)) + ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } if (cache_account_policy_get(policy_index, value)) { - DEBUG(11,("ldapsam_get_account_policy: got valid value from cache\n")); + DEBUG(11,("ldapsam_get_account_policy: got valid value from " + "cache\n")); return NT_STATUS_OK; } - ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index, value); + ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index, + value); if (NT_STATUS_IS_OK(ntstatus)) { goto update_cache; } - DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from ldap\n")); + DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from " + "ldap\n")); #if 0 /* should we automagically migrate old tdb value here ? */ if (account_policy_get(policy_index, value)) goto update_ldap; - DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying default\n", policy_index)); + DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying " + "default\n", policy_index)); #endif if (!account_policy_get_default(policy_index, value)) { @@ -3520,7 +3645,8 @@ static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, int poli update_cache: if (!cache_account_policy_set(policy_index, *value)) { - DEBUG(0,("ldapsam_get_account_policy: failed to update local tdb as a cache\n")); + DEBUG(0,("ldapsam_get_account_policy: failed to update local " + "tdb as a cache\n")); return NT_STATUS_UNSUCCESSFUL; } @@ -3536,39 +3662,44 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; - LDAP *ldap_struct = ldap_state->smbldap_state->ldap_struct; LDAPMessage *msg = NULL; LDAPMessage *entry; char *allsids = NULL; - char *tmp; int i, rc, num_mapped; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + NTSTATUS result = NT_STATUS_NO_MEMORY; + TALLOC_CTX *mem_ctx; + LDAP *ld; + BOOL is_builtin; - if (!lp_parm_bool(-1, "ldapsam", "trusted", False)) - return pdb_default_lookup_rids(methods, domain_sid, - num_rids, rids, names, attrs); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + goto done; + } - if (!sid_equal(domain_sid, get_global_sam_sid())) { - /* TODO: Sooner or later we need to look up BUILTIN rids as - * well. -- vl */ + if (!sid_check_is_builtin(domain_sid) && + !sid_check_is_domain(domain_sid)) { + result = NT_STATUS_INVALID_PARAMETER; goto done; } for (i=0; ismbldap_state, lp_ldap_user_suffix(), LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0, &msg); - - SAFE_FREE(filter); + talloc_autofree_ldapmsg(mem_ctx, msg); } if (rc != LDAP_SUCCESS) goto done; + ld = ldap_state->smbldap_state->ldap_struct; num_mapped = 0; - for (entry = ldap_first_entry(ldap_struct, msg); + for (entry = ldap_first_entry(ld, msg); entry != NULL; - entry = ldap_next_entry(ldap_struct, entry)) - { + entry = ldap_next_entry(ld, entry)) { uint32 rid; int rid_index; - fstring str; + const char *name; - if (!ldapsam_extract_rid_from_entry(ldap_struct, entry, - get_global_sam_sid(), + if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid, &rid)) { DEBUG(2, ("Could not find sid from ldap entry\n")); continue; } - if (!smbldap_get_single_attribute(ldap_struct, entry, - "uid", str, sizeof(str)-1)) { + name = smbldap_talloc_single_attribute(ld, entry, "uid", + names); + if (name == NULL) { DEBUG(2, ("Could not retrieve uid attribute\n")); continue; } @@ -3626,9 +3760,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, } attrs[rid_index] = SID_NAME_USER; - names[rid_index] = talloc_strdup(names, str); - if (names[rid_index] == NULL) return NT_STATUS_NO_MEMORY; - + names[rid_index] = name; num_mapped += 1; } @@ -3638,49 +3770,83 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, goto done; } - if (msg != NULL) { - ldap_msgfree(msg); - } - /* Same game for groups */ { char *filter; - const char *ldap_attrs[] = { "cn", "sambaSid", NULL }; + const char *ldap_attrs[] = { "cn", "displayName", "sambaSid", + "sambaGroupType", NULL }; - asprintf(&filter, ("(&(objectClass=sambaGroupMapping)(|%s))"), - allsids); - if (filter == NULL) return NT_STATUS_NO_MEMORY; + filter = talloc_asprintf( + mem_ctx, "(&(objectClass=sambaGroupMapping)(|%s))", + allsids); + if (filter == NULL) { + goto done; + } rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(), LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0, &msg); - - SAFE_FREE(filter); + talloc_autofree_ldapmsg(mem_ctx, msg); } if (rc != LDAP_SUCCESS) goto done; - for (entry = ldap_first_entry(ldap_struct, msg); + /* ldap_struct might have changed due to a reconnect */ + + ld = ldap_state->smbldap_state->ldap_struct; + + /* For consistency checks, we already checked we're only domain or builtin */ + + is_builtin = sid_check_is_builtin(domain_sid); + + for (entry = ldap_first_entry(ld, msg); entry != NULL; - entry = ldap_next_entry(ldap_struct, entry)) + entry = ldap_next_entry(ld, entry)) { uint32 rid; int rid_index; - fstring str; + const char *attr; + enum SID_NAME_USE type; + const char *dn = smbldap_talloc_dn(mem_ctx, ld, entry); + + attr = smbldap_talloc_single_attribute(ld, entry, "sambaGroupType", + mem_ctx); + if (attr == NULL) { + DEBUG(2, ("Could not extract type from ldap entry %s\n", + dn)); + continue; + } - if (!ldapsam_extract_rid_from_entry(ldap_struct, entry, - get_global_sam_sid(), + type = atol(attr); + + /* Consistency checks */ + if ((is_builtin && (type != SID_NAME_WKN_GRP)) || + (!is_builtin && ((type != SID_NAME_ALIAS) && + (type != SID_NAME_DOM_GRP)))) { + DEBUG(2, ("Rejecting invalid group mapping entry %s\n", dn)); + } + + if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid, &rid)) { - DEBUG(2, ("Could not find sid from ldap entry\n")); + DEBUG(2, ("Could not find sid from ldap entry %s\n", dn)); continue; } - if (!smbldap_get_single_attribute(ldap_struct, entry, - "cn", str, sizeof(str)-1)) { - DEBUG(2, ("Could not retrieve cn attribute\n")); + attr = smbldap_talloc_single_attribute(ld, entry, "cn", names); + + if (attr == NULL) { + DEBUG(10, ("Could not retrieve 'cn' attribute from %s\n", + dn)); + attr = smbldap_talloc_single_attribute( + ld, entry, "displayName", names); + } + + if (attr == NULL) { + DEBUG(2, ("Could not retrieve naming attribute from %s\n", + dn)); continue; } @@ -3694,9 +3860,8 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, continue; } - attrs[rid_index] = SID_NAME_DOM_GRP; - names[rid_index] = talloc_strdup(names, str); - if (names[rid_index] == NULL) return NT_STATUS_NO_MEMORY; + attrs[rid_index] = type; + names[rid_index] = attr; num_mapped += 1; } @@ -3706,11 +3871,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, result = (num_mapped == num_rids) ? NT_STATUS_OK : STATUS_SOME_UNMAPPED; done: - SAFE_FREE(allsids); - - if (msg != NULL) - ldap_msgfree(msg); - + talloc_free(mem_ctx); return result; } @@ -3833,7 +3994,6 @@ static BOOL ldapsam_search_firstpage(struct pdb_search *search) static BOOL ldapsam_search_nextpage(struct pdb_search *search) { struct ldap_search_state *state = search->private_data; - LDAP *ld = state->connection->ldap_struct; int rc; if (!state->connection->paged_results) { @@ -3850,7 +4010,7 @@ static BOOL ldapsam_search_nextpage(struct pdb_search *search) if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) return False; - state->current_entry = ldap_first_entry(ld, state->entries); + state->current_entry = ldap_first_entry(state->connection->ldap_struct, state->entries); if (state->current_entry == NULL) { ldap_msgfree(state->entries); @@ -3864,7 +4024,6 @@ static BOOL ldapsam_search_next_entry(struct pdb_search *search, struct samr_displayentry *entry) { struct ldap_search_state *state = search->private_data; - LDAP *ld = state->connection->ldap_struct; BOOL result; retry: @@ -3875,17 +4034,17 @@ static BOOL ldapsam_search_next_entry(struct pdb_search *search, !ldapsam_search_nextpage(search)) return False; - result = state->ldap2displayentry(state, search->mem_ctx, ld, + result = state->ldap2displayentry(state, search->mem_ctx, state->connection->ldap_struct, state->current_entry, entry); if (!result) { char *dn; - dn = ldap_get_dn(ld, state->current_entry); + dn = ldap_get_dn(state->connection->ldap_struct, state->current_entry); DEBUG(5, ("Skipping entry %s\n", dn != NULL ? dn : "")); if (dn != NULL) ldap_memfree(dn); } - state->current_entry = ldap_next_entry(ld, state->current_entry); + state->current_entry = ldap_next_entry(state->connection->ldap_struct, state->current_entry); if (state->current_entry == NULL) { ldap_msgfree(state->entries); @@ -4002,7 +4161,8 @@ static BOOL ldapuser2displayentry(struct ldap_search_state *state, ldap_value_free(vals); if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) { - DEBUG(0, ("sid %s does not belong to our domain\n", sid_string_static(&sid))); + DEBUG(0, ("sid %s does not belong to our domain\n", + sid_string_static(&sid))); return False; } @@ -4102,10 +4262,14 @@ static BOOL ldapgroup2displayentry(struct ldap_search_state *state, DEBUG(5, ("\"cn\" not found\n")); return False; } - pull_utf8_talloc(mem_ctx, CONST_DISCARD(char **, &result->account_name), vals[0]); + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->account_name), + vals[0]); } else { - pull_utf8_talloc(mem_ctx, CONST_DISCARD(char **, &result->account_name), vals[0]); + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->account_name), + vals[0]); } ldap_value_free(vals); @@ -4146,17 +4310,21 @@ static BOOL ldapgroup2displayentry(struct ldap_search_state *state, case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: - if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) { - DEBUG(0, ("%s is not in our domain\n", sid_string_static(&sid))); + if (!sid_peek_check_rid(get_global_sam_sid(), &sid, + &result->rid)) { + DEBUG(0, ("%s is not in our domain\n", + sid_string_static(&sid))); return False; } break; case SID_NAME_WKN_GRP: - if (!sid_peek_check_rid(&global_sid_Builtin, &sid, &result->rid)) { + if (!sid_peek_check_rid(&global_sid_Builtin, &sid, + &result->rid)) { - DEBUG(0, ("%s is not in builtin sid\n", sid_string_static(&sid))); + DEBUG(0, ("%s is not in builtin sid\n", + sid_string_static(&sid))); return False; } break; @@ -4191,7 +4359,8 @@ static BOOL ldapsam_search_grouptype(struct pdb_methods *methods, "(&(objectclass=sambaGroupMapping)" "(sambaGroupType=%d))", type); state->attrs = talloc_attrs(search->mem_ctx, "cn", "sambaSid", - "displayName", "description", "sambaGroupType", NULL); + "displayName", "description", + "sambaGroupType", NULL); state->attrsonly = 0; state->pagedresults_cookie = NULL; state->entries = NULL; @@ -4232,6 +4401,214 @@ static BOOL ldapsam_search_aliases(struct pdb_methods *methods, return False; } +static BOOL ldapsam_rid_algorithm(struct pdb_methods *methods) +{ + return False; +} + +static NTSTATUS ldapsam_get_new_rid(struct ldapsam_privates *priv, + uint32 *rid) +{ + struct smbldap_state *smbldap_state = priv->smbldap_state; + + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + LDAPMod **mods = NULL; + NTSTATUS status; + char *value; + int rc; + uint32 nextRid = 0; + + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } + + status = smbldap_search_domain_info(smbldap_state, &result, + get_global_sam_name(), False); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not get domain info: %s\n", + nt_errstr(status))); + goto done; + } + + talloc_autofree_ldapmsg(mem_ctx, result); + + entry = ldap_first_entry(priv2ld(priv), result); + if (entry == NULL) { + DEBUG(0, ("Could not get domain info entry\n")); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + /* Find the largest of the three attributes "sambaNextRid", + "sambaNextGroupRid" and "sambaNextUserRid". I gave up on the + concept of differentiating between user and group rids, and will + use only "sambaNextRid" in the future. But for compatibility + reasons I look if others have chosen different strategies -- VL */ + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaNextRid", mem_ctx); + if (value != NULL) { + uint32 tmp = (uint32)strtoul(value, NULL, 10); + nextRid = MAX(nextRid, tmp); + } + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaNextUserRid", mem_ctx); + if (value != NULL) { + uint32 tmp = (uint32)strtoul(value, NULL, 10); + nextRid = MAX(nextRid, tmp); + } + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaNextGroupRid", mem_ctx); + if (value != NULL) { + uint32 tmp = (uint32)strtoul(value, NULL, 10); + nextRid = MAX(nextRid, tmp); + } + + if (nextRid == 0) { + nextRid = BASE_RID-1; + } + + nextRid += 1; + + smbldap_make_mod(priv2ld(priv), entry, &mods, "sambaNextRid", + talloc_asprintf(mem_ctx, "%d", nextRid)); + talloc_autofree_ldapmod(mem_ctx, mods); + + rc = smbldap_modify(smbldap_state, + smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry), + mods); + + /* ACCESS_DENIED is used as a placeholder for "the modify failed, + * please retry" */ + + status = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + + done: + if (NT_STATUS_IS_OK(status)) { + *rid = nextRid; + } + + talloc_free(mem_ctx); + return status; +} + +static BOOL ldapsam_new_rid(struct pdb_methods *methods, uint32 *rid) +{ + int i; + + for (i=0; i<10; i++) { + NTSTATUS result = ldapsam_get_new_rid(methods->private_data, + rid); + if (NT_STATUS_IS_OK(result)) { + return True; + } + + if (!NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) { + return False; + } + + /* The ldap update failed (maybe a race condition), retry */ + } + + /* Tried 10 times, fail. */ + return False; +} + +static BOOL ldapsam_sid_to_id(struct pdb_methods *methods, + const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type) +{ + struct ldapsam_privates *priv = methods->private_data; + char *filter; + const char *attrs[] = { "sambaGroupType", "gidNumber", "uidNumber", + NULL }; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + BOOL ret = False; + char *value; + int rc; + + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + filter = talloc_asprintf(mem_ctx, + "(&(sambaSid=%s)" + "(|(objectClass=sambaGroupMapping)" + "(objectClass=sambaSamAccount)))", + sid_string_static(sid)); + if (filter == NULL) { + DEBUG(5, ("talloc_asprintf failed\n")); + goto done; + } + + rc = smbldap_search_suffix(priv->smbldap_state, filter, + attrs, &result); + if (rc != LDAP_SUCCESS) { + goto done; + } + talloc_autofree_ldapmsg(mem_ctx, result); + + if (ldap_count_entries(priv2ld(priv), result) != 1) { + DEBUG(10, ("Got %d entries, expected one\n", + ldap_count_entries(priv2ld(priv), result))); + goto done; + } + + entry = ldap_first_entry(priv2ld(priv), result); + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaGroupType", mem_ctx); + + if (value != NULL) { + const char *gid_str; + /* It's a group */ + + gid_str = smbldap_talloc_single_attribute( + priv2ld(priv), entry, "gidNumber", mem_ctx); + if (gid_str == NULL) { + DEBUG(1, ("%s has sambaGroupType but no gidNumber\n", + smbldap_talloc_dn(mem_ctx, priv2ld(priv), + entry))); + goto done; + } + + id->gid = strtoul(gid_str, NULL, 10); + *type = strtoul(value, NULL, 10); + ret = True; + goto done; + } + + /* It must be a user */ + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "uidNumber", mem_ctx); + if (value == NULL) { + DEBUG(1, ("Could not find uidNumber in %s\n", + smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry))); + goto done; + } + + id->uid = strtoul(value, NULL, 10); + *type = SID_NAME_USER; + + ret = True; + done: + talloc_free(mem_ctx); + return ret; +} + /********************************************************************** Housekeeping *********************************************************************/ @@ -4288,15 +4665,15 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS ** (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry; (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry; (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping; - (*pdb_method)->enum_group_members = ldapsam_enum_group_members; - (*pdb_method)->enum_group_memberships = ldapsam_enum_group_memberships; - (*pdb_method)->lookup_rids = ldapsam_lookup_rids; (*pdb_method)->get_account_policy = ldapsam_get_account_policy; (*pdb_method)->set_account_policy = ldapsam_set_account_policy; (*pdb_method)->get_seq_num = ldapsam_get_seq_num; + (*pdb_method)->rid_algorithm = ldapsam_rid_algorithm; + (*pdb_method)->new_rid = ldapsam_new_rid; + /* TODO: Setup private data and free */ ldap_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct ldapsam_privates); @@ -4377,7 +4754,8 @@ NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, co pstring domain_sid_string; char *dn; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) { + nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -4391,27 +4769,41 @@ NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, co (*pdb_method)->search_groups = ldapsam_search_groups; (*pdb_method)->search_aliases = ldapsam_search_aliases; + if (lp_parm_bool(-1, "ldapsam", "trusted", False)) { + (*pdb_method)->enum_group_members = ldapsam_enum_group_members; + (*pdb_method)->enum_group_memberships = + ldapsam_enum_group_memberships; + (*pdb_method)->lookup_rids = ldapsam_lookup_rids; + (*pdb_method)->sid_to_id = ldapsam_sid_to_id; + } + ldap_state = (*pdb_method)->private_data; ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT; /* Try to setup the Domain Name, Domain SID, algorithmic rid base */ - nt_status = smbldap_search_domain_info(ldap_state->smbldap_state, &result, + nt_status = smbldap_search_domain_info(ldap_state->smbldap_state, + &result, ldap_state->domain_name, True); if ( !NT_STATUS_IS_OK(nt_status) ) { - DEBUG(2, ("pdb_init_ldapsam: WARNING: Could not get domain info, nor add one to the domain\n")); - DEBUGADD(2, ("pdb_init_ldapsam: Continuing on regardless, will be unable to allocate new users/groups, \ -and will risk BDCs having inconsistant SIDs\n")); + DEBUG(2, ("pdb_init_ldapsam: WARNING: Could not get domain " + "info, nor add one to the domain\n")); + DEBUGADD(2, ("pdb_init_ldapsam: Continuing on regardless, " + "will be unable to allocate new users/groups, " + "and will risk BDCs having inconsistant SIDs\n")); sid_copy(&ldap_state->domain_sid, get_global_sam_sid()); return NT_STATUS_OK; } - /* Given that the above might fail, everything below this must be optional */ + /* Given that the above might fail, everything below this must be + * optional */ - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, + result); if (!entry) { - DEBUG(0, ("pdb_init_ldapsam: Could not get domain info entry\n")); + DEBUG(0, ("pdb_init_ldapsam: Could not get domain info " + "entry\n")); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -4424,35 +4816,51 @@ and will risk BDCs having inconsistant SIDs\n")); ldap_state->domain_dn = smb_xstrdup(dn); ldap_memfree(dn); - if (smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), - domain_sid_string)) { + if (smbldap_get_single_pstring( + ldap_state->smbldap_state->ldap_struct, + entry, + get_userattr_key2string(ldap_state->schema_ver, + LDAP_ATTR_USER_SID), + domain_sid_string)) { BOOL found_sid; if (!string_to_sid(&ldap_domain_sid, domain_sid_string)) { - DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be read as a valid SID\n", domain_sid_string)); + DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be " + "read as a valid SID\n", domain_sid_string)); return NT_STATUS_INVALID_PARAMETER; } - found_sid = secrets_fetch_domain_sid(ldap_state->domain_name, &secrets_domain_sid); - if (!found_sid || !sid_equal(&secrets_domain_sid, &ldap_domain_sid)) { + found_sid = secrets_fetch_domain_sid(ldap_state->domain_name, + &secrets_domain_sid); + if (!found_sid || !sid_equal(&secrets_domain_sid, + &ldap_domain_sid)) { fstring new_sid_str, old_sid_str; - DEBUG(1, ("pdb_init_ldapsam: Resetting SID for domain %s based on pdb_ldap results %s -> %s\n", - ldap_state->domain_name, - sid_to_string(old_sid_str, &secrets_domain_sid), - sid_to_string(new_sid_str, &ldap_domain_sid))); + DEBUG(1, ("pdb_init_ldapsam: Resetting SID for domain " + "%s based on pdb_ldap results %s -> %s\n", + ldap_state->domain_name, + sid_to_string(old_sid_str, + &secrets_domain_sid), + sid_to_string(new_sid_str, + &ldap_domain_sid))); /* reset secrets.tdb sid */ - secrets_store_domain_sid(ldap_state->domain_name, &ldap_domain_sid); - DEBUG(1, ("New global sam SID: %s\n", sid_to_string(new_sid_str, get_global_sam_sid()))); + secrets_store_domain_sid(ldap_state->domain_name, + &ldap_domain_sid); + DEBUG(1, ("New global sam SID: %s\n", + sid_to_string(new_sid_str, + get_global_sam_sid()))); } sid_copy(&ldap_state->domain_sid, &ldap_domain_sid); } - if (smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_attr_key2string( dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE ), - alg_rid_base_string)) { + if (smbldap_get_single_pstring( + ldap_state->smbldap_state->ldap_struct, + entry, + get_attr_key2string( dominfo_attr_list, + LDAP_ATTR_ALGORITHMIC_RID_BASE ), + alg_rid_base_string)) { alg_rid_base = (uint32)atol(alg_rid_base_string); if (alg_rid_base != algorithmic_rid_base()) { - DEBUG(0, ("The value of 'algorithmic RID base' has changed since the LDAP\n" + DEBUG(0, ("The value of 'algorithmic RID base' has " + "changed since the LDAP\n" "database was initialised. Aborting. \n")); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; diff --git a/source3/passdb/pdb_nds.c b/source3/passdb/pdb_nds.c index cf2d1d7c8a..49c3c9db06 100644 --- a/source3/passdb/pdb_nds.c +++ b/source3/passdb/pdb_nds.c @@ -771,13 +771,16 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, result = pdb_get_backend_private_data(sam_acct, methods); if (!result) { - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, + ldap_state->schema_ver); rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list ); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - pdb_set_backend_private_data(sam_acct, result, private_data_free_fn, methods, PDB_CHANGED); + pdb_set_backend_private_data(sam_acct, result, NULL, + methods, PDB_CHANGED); + talloc_autofree_ldapmsg(sam_acct->mem_ctx, result); } if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c index 487df96e95..06a3f4f4a1 100644 --- a/source3/passdb/pdb_smbpasswd.c +++ b/source3/passdb/pdb_smbpasswd.c @@ -594,7 +594,6 @@ static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, str size_t new_entry_length; char *new_entry; SMB_OFF_T offpos; - uint32 max_found_uid = 0; /* Open the smbpassword file - for update. */ fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth); @@ -619,11 +618,6 @@ static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, str endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); return False; } - - /* Look for a free uid for use in non-unix accounts */ - if (pwd->smb_userid > max_found_uid) { - max_found_uid = pwd->smb_userid; - } } /* Ok - entry doesn't exist. We can add it */ @@ -1161,14 +1155,13 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas /* If the user specified a RID, make sure its able to be both stored and retreived */ if (rid == DOMAIN_USER_RID_GUEST) { - struct passwd *passwd = getpwnam_alloc(lp_guestaccount()); + struct passwd *passwd = getpwnam_alloc(NULL, lp_guestaccount()); if (!passwd) { DEBUG(0, ("Could not find gest account via getpwnam()! (%s)\n", lp_guestaccount())); return False; } smb_pw->smb_userid=passwd->pw_uid; - passwd_free(&passwd); - + talloc_free(passwd); } else if (algorithmic_pdb_rid_is_user(rid)) { smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid); } else { @@ -1204,7 +1197,7 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, /* verify the user account exists */ - if ( !(pwfile = getpwnam_alloc(pw_buf->smb_name)) ) { + if ( !(pwfile = getpwnam_alloc(NULL, pw_buf->smb_name)) ) { DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid " "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid)); return False; @@ -1213,7 +1206,7 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) return False; - passwd_free(&pwfile); + talloc_free(pwfile); /* set remaining fields */ @@ -1532,6 +1525,11 @@ done: return (ret); } +static BOOL smbpasswd_rid_algorithm(struct pdb_methods *methods) +{ + return True; +} + static void free_private_data(void **vp) { struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp; @@ -1563,6 +1561,8 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account; (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account; + (*pdb_method)->rid_algorithm = smbpasswd_rid_algorithm; + /* Setup private data and free function */ privates = TALLOC_ZERO_P(pdb_context->mem_ctx, struct smbpasswd_privates); diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 370c8adc7d..74f47e70dc 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -864,7 +864,98 @@ done: return (ret); } - + +static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods) +{ + return False; +} + +/* + * Historically, winbind was responsible for allocating RIDs, so the next RID + * value was stored in winbindd_idmap.tdb. It has been moved to passdb now, + * but for compatibility reasons we still keep the the next RID counter in + * winbindd_idmap.tdb. + */ + +/***************************************************************************** + Initialise idmap database. For now (Dec 2005) this is a copy of the code in + sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from + winbind completely and store the RID counter in passdb.tdb. + + Dont' fully initialize with the HWM values, if it's new, we're only + interested in the RID counter. +*****************************************************************************/ + +static BOOL init_idmap_tdb(TDB_CONTEXT *tdb) +{ + int32 version; + + if (tdb_lock_bystring(tdb, "IDMAP_VERSION", 0) != 0) { + DEBUG(0, ("Could not lock IDMAP_VERSION\n")); + return False; + } + + version = tdb_fetch_int32(tdb, "IDMAP_VERSION"); + + if (version == -1) { + /* No key found, must be a new db */ + if (tdb_store_int32(tdb, "IDMAP_VERSION", + IDMAP_VERSION) != 0) { + DEBUG(0, ("Could not store IDMAP_VERSION\n")); + tdb_unlock_bystring(tdb, "IDMAP_VERSION"); + return False; + } + version = IDMAP_VERSION; + } + + if (version != IDMAP_VERSION) { + DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please " + "start winbind once\n", IDMAP_VERSION, version)); + tdb_unlock_bystring(tdb, "IDMAP_VERSION"); + return False; + } + + tdb_unlock_bystring(tdb, "IDMAP_VERSION"); + return True; +} + +static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid) +{ + TDB_CONTEXT *tdb; + uint32 rid; + BOOL ret = False; + + tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0, + TDB_DEFAULT, O_RDWR | O_CREAT, 0644); + + if (tdb == NULL) { + DEBUG(1, ("Could not open idmap: %s\n", strerror(errno))); + goto done; + } + + if (!init_idmap_tdb(tdb)) { + DEBUG(1, ("Could not init idmap\n")); + goto done; + } + + rid = BASE_RID; /* Default if not set */ + + if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) { + DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n")); + goto done; + } + + *prid = rid; + ret = True; + + done: + if ((tdb != NULL) && (tdb_close(tdb) != 0)) { + smb_panic("tdb_close(idmap_tdb) failed\n"); + } + + return ret; +} + static void free_private_data(void **vp) { struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp; @@ -908,6 +999,9 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account; (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account; + (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm; + (*pdb_method)->new_rid = tdbsam_new_rid; + tdb_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct tdbsam_privates); if (!tdb_state) { diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 88dabbd644..69bafc7ce5 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -388,10 +388,11 @@ BOOL secrets_store_trust_account_password(const char *domain, uint8 new_pwd[16]) * @return true if succeeded **/ -BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_dom_name, - size_t uni_name_len, const char* pwd, - DOM_SID sid) -{ +BOOL secrets_store_trusted_domain_password(const char* domain, const char* pwd, + const DOM_SID *sid) +{ + smb_ucs2_t *uni_dom_name; + /* packing structures */ pstring pass_buf; int pass_len = 0; @@ -399,13 +400,15 @@ BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_d struct trusted_dom_pass pass; ZERO_STRUCT(pass); - - /* unicode domain name and its length */ - if (!uni_dom_name) + + if (push_ucs2_allocate(&uni_dom_name, domain) < 0) { + DEBUG(0, ("Could not convert domain name %s to unicode\n", + domain)); return False; - + } + strncpy_w(pass.uni_name, uni_dom_name, sizeof(pass.uni_name) - 1); - pass.uni_name_len = uni_name_len; + pass.uni_name_len = strlen_w(uni_dom_name)+1; /* last change time */ pass.mod_time = time(NULL); @@ -415,7 +418,7 @@ BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_d fstrcpy(pass.pass, pwd); /* domain sid */ - sid_copy(&pass.domain_sid, &sid); + sid_copy(&pass.domain_sid, sid); pass_len = tdb_trusted_dom_pass_pack(pass_buf, pass_buf_len, &pass); @@ -658,138 +661,97 @@ BOOL fetch_ldap_pw(char **dn, char** pw) /** * Get trusted domains info from secrets.tdb. - * - * The linked list is allocated on the supplied talloc context, caller gets to destroy - * when done. - * - * @param ctx Allocation context - * @param enum_ctx Starting index, eg. we can start fetching at third - * or sixth trusted domain entry. Zero is the first index. - * Value it is set to is the enum context for the next enumeration. - * @param num_domains Number of domain entries to fetch at one call - * @param domains Pointer to array of trusted domain structs to be filled up - * - * @return nt status code of rpc response **/ -NTSTATUS secrets_get_trusted_domains(TALLOC_CTX* ctx, int* enum_ctx, unsigned int max_num_domains, - int *num_domains, TRUSTDOM ***domains) +NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32 *num_domains, + struct trustdom_info ***domains) { TDB_LIST_NODE *keys, *k; - TRUSTDOM *dom = NULL; char *pattern; - unsigned int start_idx; - uint32 idx = 0; - size_t size = 0, packed_size = 0; - fstring dom_name; - char *packed_pass; - struct trusted_dom_pass *pass = TALLOC_ZERO_P(ctx, struct trusted_dom_pass); - NTSTATUS status; if (!secrets_init()) return NT_STATUS_ACCESS_DENIED; - if (!pass) { - DEBUG(0, ("talloc_zero failed!\n")); - return NT_STATUS_NO_MEMORY; - } - - *num_domains = 0; - start_idx = *enum_ctx; - /* generate searching pattern */ - if (!(pattern = talloc_asprintf(ctx, "%s/*", SECRETS_DOMTRUST_ACCT_PASS))) { - DEBUG(0, ("secrets_get_trusted_domains: talloc_asprintf() failed!\n")); + pattern = talloc_asprintf(mem_ctx, "%s/*", SECRETS_DOMTRUST_ACCT_PASS); + if (pattern == NULL) { + DEBUG(0, ("secrets_trusted_domains: talloc_asprintf() " + "failed!\n")); return NT_STATUS_NO_MEMORY; } - DEBUG(5, ("secrets_get_trusted_domains: looking for %d domains, starting at index %d\n", - max_num_domains, *enum_ctx)); - - *domains = TALLOC_ZERO_ARRAY(ctx, TRUSTDOM *, max_num_domains); + *domains = NULL; + *num_domains = 0; /* fetching trusted domains' data and collecting them in a list */ keys = tdb_search_keys(tdb, pattern); - /* - * if there's no keys returned ie. no trusted domain, - * return "no more entries" code - */ - status = NT_STATUS_NO_MORE_ENTRIES; - /* searching for keys in secrets db -- way to go ... */ for (k = keys; k; k = k->next) { + char *packed_pass; + size_t size = 0, packed_size = 0; + struct trusted_dom_pass pass; char *secrets_key; + struct trustdom_info *dom_info; /* important: ensure null-termination of the key string */ - secrets_key = SMB_STRNDUP(k->node_key.dptr, k->node_key.dsize); + secrets_key = talloc_strndup(mem_ctx, + k->node_key.dptr, + k->node_key.dsize); if (!secrets_key) { DEBUG(0, ("strndup failed!\n")); return NT_STATUS_NO_MEMORY; } packed_pass = secrets_fetch(secrets_key, &size); - packed_size = tdb_trusted_dom_pass_unpack(packed_pass, size, pass); + packed_size = tdb_trusted_dom_pass_unpack(packed_pass, size, + &pass); /* packed representation isn't needed anymore */ SAFE_FREE(packed_pass); if (size != packed_size) { - DEBUG(2, ("Secrets record %s is invalid!\n", secrets_key)); + DEBUG(2, ("Secrets record %s is invalid!\n", + secrets_key)); continue; } - - pull_ucs2_fstring(dom_name, pass->uni_name); - DEBUG(18, ("Fetched secret record num %d.\nDomain name: %s, SID: %s\n", - idx, dom_name, sid_string_static(&pass->domain_sid))); - - SAFE_FREE(secrets_key); - - if (idx >= start_idx && idx < start_idx + max_num_domains) { - dom = TALLOC_ZERO_P(ctx, TRUSTDOM); - if (!dom) { - /* free returned tdb record */ - return NT_STATUS_NO_MEMORY; - } - - /* copy domain sid */ - SMB_ASSERT(sizeof(dom->sid) == sizeof(pass->domain_sid)); - memcpy(&(dom->sid), &(pass->domain_sid), sizeof(dom->sid)); - - /* copy unicode domain name */ - dom->name = TALLOC_MEMDUP(ctx, pass->uni_name, - (strlen_w(pass->uni_name) + 1) * sizeof(smb_ucs2_t)); - - (*domains)[idx - start_idx] = dom; - - DEBUG(18, ("Secret record is in required range.\n \ - start_idx = %d, max_num_domains = %d. Added to returned array.\n", - start_idx, max_num_domains)); - *enum_ctx = idx + 1; - (*num_domains)++; - - /* set proper status code to return */ - if (k->next) { - /* there are yet some entries to enumerate */ - status = STATUS_MORE_ENTRIES; - } else { - /* this is the last entry in the whole enumeration */ - status = NT_STATUS_OK; - } - } else { - DEBUG(18, ("Secret is outside the required range.\n \ - start_idx = %d, max_num_domains = %d. Not added to returned array\n", - start_idx, max_num_domains)); + if (pass.domain_sid.num_auths != 4) { + DEBUG(0, ("SID %s is not a domain sid, has %d " + "auths instead of 4\n", + sid_string_static(&pass.domain_sid), + pass.domain_sid.num_auths)); + continue; } - - idx++; + + dom_info = TALLOC_P(mem_ctx, struct trustdom_info); + if (dom_info == NULL) { + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } + + if (pull_ucs2_talloc(mem_ctx, &dom_info->name, + pass.uni_name) < 0) { + DEBUG(2, ("pull_ucs2_talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } + + sid_copy(&dom_info->sid, &pass.domain_sid); + + ADD_TO_ARRAY(mem_ctx, struct trustdom_info *, dom_info, + domains, num_domains); + + if (*domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + talloc_steal(*domains, dom_info); } - DEBUG(5, ("secrets_get_trusted_domains: got %d domains\n", *num_domains)); + DEBUG(5, ("secrets_get_trusted_domains: got %d domains\n", + *num_domains)); /* free the results of searching the keys */ tdb_search_list_free(keys); - return status; + return NT_STATUS_OK; } /******************************************************************************* diff --git a/source3/passdb/util_builtin.c b/source3/passdb/util_builtin.c index 12a98d24dd..9c59df1f68 100644 --- a/source3/passdb/util_builtin.c +++ b/source3/passdb/util_builtin.c @@ -105,6 +105,6 @@ BOOL sid_check_is_in_builtin(const DOM_SID *sid) sid_copy(&dom_sid, sid); sid_split_rid(&dom_sid, &rid); - return sid_equal(&dom_sid, &global_sid_Builtin); + return sid_check_is_builtin(&dom_sid); } diff --git a/source3/passdb/util_unixsids.c b/source3/passdb/util_unixsids.c new file mode 100644 index 0000000000..ee8cf2d8f0 --- /dev/null +++ b/source3/passdb/util_unixsids.c @@ -0,0 +1,94 @@ +/* + Unix SMB/CIFS implementation. + Translate unix-defined names to SIDs and vice versa + Copyright (C) Volker Lendecke 2005 + + 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. +*/ + +#include "includes.h" + +BOOL sid_check_is_unix_users(const DOM_SID *sid) +{ + return sid_equal(sid, &global_sid_Unix_Users); +} + +BOOL sid_check_is_in_unix_users(const DOM_SID *sid) +{ + DOM_SID dom_sid; + uint32 rid; + + sid_copy(&dom_sid, sid); + sid_split_rid(&dom_sid, &rid); + + return sid_check_is_unix_users(&dom_sid); +} + +const char *unix_users_domain_name(void) +{ + return "Unix User"; +} + +BOOL lookup_unix_user_name(const char *name, DOM_SID *sid) +{ + struct passwd *pwd; + + pwd = getpwnam_alloc(NULL, name); + if (pwd == NULL) { + return False; + } + + sid_copy(sid, &global_sid_Unix_Users); + sid_append_rid(sid, pwd->pw_uid); /* For 64-bit uid's we have enough + * space ... */ + talloc_free(pwd); + return True; +} + +BOOL sid_check_is_unix_groups(const DOM_SID *sid) +{ + return sid_equal(sid, &global_sid_Unix_Groups); +} + +BOOL sid_check_is_in_unix_groups(const DOM_SID *sid) +{ + DOM_SID dom_sid; + uint32 rid; + + sid_copy(&dom_sid, sid); + sid_split_rid(&dom_sid, &rid); + + return sid_check_is_unix_groups(&dom_sid); +} + +const char *unix_groups_domain_name(void) +{ + return "Unix Group"; +} + +BOOL lookup_unix_group_name(const char *name, DOM_SID *sid) +{ + struct group *grp; + + grp = getgrnam(name); + if (grp == NULL) { + return False; + } + + sid_copy(sid, &global_sid_Unix_Groups); + sid_append_rid(sid, grp->gr_gid); /* For 64-bit uid's we have enough + * space ... */ + return True; +} diff --git a/source3/passdb/util_wellknown.c b/source3/passdb/util_wellknown.c index 8caae3b2a0..be3cf37446 100644 --- a/source3/passdb/util_wellknown.c +++ b/source3/passdb/util_wellknown.c @@ -70,6 +70,21 @@ static struct sid_name_map_info special_domains[] = { { &global_sid_NT_Authority, "NT Authority", nt_authority_users }, { NULL, NULL, NULL }}; +BOOL sid_check_is_wellknown_domain(const DOM_SID *sid, const char **name) +{ + int i; + + for (i=0; special_domains[i].sid != NULL; i++) { + if (sid_equal(sid, special_domains[i].sid)) { + if (name != NULL) { + *name = special_domains[i].name; + } + return True; + } + } + return False; +} + /************************************************************************** Looks up a known username from one of the known domains. ***************************************************************************/ -- cgit