diff options
Diffstat (limited to 'source/passdb')
-rw-r--r-- | source/passdb/login_cache.c | 8 | ||||
-rw-r--r-- | source/passdb/lookup_sid.c | 1130 | ||||
-rw-r--r-- | source/passdb/machine_sid.c | 27 | ||||
-rw-r--r-- | source/passdb/passdb.c | 1614 | ||||
-rw-r--r-- | source/passdb/pdb_compat.c | 10 | ||||
-rw-r--r-- | source/passdb/pdb_get_set.c | 610 | ||||
-rw-r--r-- | source/passdb/pdb_guest.c | 164 | ||||
-rw-r--r-- | source/passdb/pdb_interface.c | 2078 | ||||
-rw-r--r-- | source/passdb/pdb_ldap.c | 2851 | ||||
-rw-r--r-- | source/passdb/pdb_mysql.c | 509 | ||||
-rw-r--r-- | source/passdb/pdb_nds.c | 30 | ||||
-rw-r--r-- | source/passdb/pdb_pgsql.c | 605 | ||||
-rw-r--r-- | source/passdb/pdb_plugin.c | 4 | ||||
-rw-r--r-- | source/passdb/pdb_smbpasswd.c | 116 | ||||
-rw-r--r-- | source/passdb/pdb_sql.c | 571 | ||||
-rw-r--r-- | source/passdb/pdb_tdb.c | 1414 | ||||
-rw-r--r-- | source/passdb/pdb_xml.c | 580 | ||||
-rw-r--r-- | source/passdb/secrets.c | 267 | ||||
-rw-r--r-- | source/passdb/util_builtin.c | 79 | ||||
-rw-r--r-- | source/passdb/util_sam_sid.c | 238 | ||||
-rw-r--r-- | source/passdb/util_unixsids.c | 94 | ||||
-rw-r--r-- | source/passdb/util_wellknown.c | 175 |
22 files changed, 6320 insertions, 6854 deletions
diff --git a/source/passdb/login_cache.c b/source/passdb/login_cache.c index d82cfcc5601..fba5990d811 100644 --- a/source/passdb/login_cache.c +++ b/source/passdb/login_cache.c @@ -1,6 +1,6 @@ /* Unix SMB/CIFS implementation. - SAM_ACCOUNT local cache for + struct samu local cache for Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2004. This program is free software; you can redistribute it and/or modify @@ -64,7 +64,7 @@ BOOL login_cache_shutdown(void) } /* if we can't read the cache, oh well, no need to return anything */ -LOGIN_CACHE * login_cache_read(SAM_ACCOUNT *sampass) +LOGIN_CACHE * login_cache_read(struct samu *sampass) { TDB_DATA keybuf, databuf; LOGIN_CACHE *entry; @@ -108,7 +108,7 @@ LOGIN_CACHE * login_cache_read(SAM_ACCOUNT *sampass) return entry; } -BOOL login_cache_write(const SAM_ACCOUNT *sampass, LOGIN_CACHE entry) +BOOL login_cache_write(const struct samu *sampass, LOGIN_CACHE entry) { TDB_DATA keybuf, databuf; @@ -155,7 +155,7 @@ BOOL login_cache_write(const SAM_ACCOUNT *sampass, LOGIN_CACHE entry) return ret == 0; } -BOOL login_cache_delentry(const SAM_ACCOUNT *sampass) +BOOL login_cache_delentry(const struct samu *sampass) { int ret; TDB_DATA keybuf; diff --git a/source/passdb/lookup_sid.c b/source/passdb/lookup_sid.c index b397e084c33..942d2771782 100644 --- a/source/passdb/lookup_sid.c +++ b/source/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 @@ -22,129 +23,804 @@ #include "includes.h" /***************************************************************** - *THE CANONICAL* convert name to SID function. - Tries local lookup first - for local domains - then uses winbind. + Dissect a user-provided name into domain, name, sid and type. + + If an explicit domain name was given in the form domain\user, it + has to try that. If no explicit domain name was given, we have + to do guesswork. *****************************************************************/ -BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type) +BOOL lookup_name(TALLOC_CTX *mem_ctx, + const char *full_name, int flags, + const char **ret_domain, const char **ret_name, + DOM_SID *ret_sid, enum SID_NAME_USE *ret_type) { - fstring sid; - BOOL local_lookup = False; - - *name_type = SID_NAME_UNKNOWN; + char *p; + const char *tmp; + const char *domain = NULL; + const char *name = NULL; + uint32 rid; + DOM_SID sid; + enum SID_NAME_USE type; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + p = strchr_m(full_name, '\\'); + + if (p != NULL) { + domain = talloc_strndup(tmp_ctx, full_name, + PTR_DIFF(p, full_name)); + name = talloc_strdup(tmp_ctx, p+1); + } else { + domain = talloc_strdup(tmp_ctx, ""); + name = talloc_strdup(tmp_ctx, full_name); + } + + if ((domain == NULL) || (name == NULL)) { + DEBUG(0, ("talloc failed\n")); + return False; + } - /* If we are looking up a domain user, make sure it is - for the local machine only */ - if (strequal(domain, get_global_sam_name())) { - if (local_lookup_name(name, psid, name_type)) { - DEBUG(10, - ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n", - domain, name, sid_to_string(sid,psid), - sid_type_lookup(*name_type), (unsigned int)*name_type)); - return True; + + /* It's our own domain, lookup the name in passdb */ + if (lookup_global_sam_name(name, flags, &rid, &type)) { + sid_copy(&sid, get_global_sam_sid()); + sid_append_rid(&sid, rid); + goto ok; } - } else { - /* Remote */ - if (winbind_lookup_name(domain, name, psid, name_type)) { - - DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n", - domain, name, sid_to_string(sid, psid), - (unsigned int)*name_type)); - return True; + goto failed; + } + + if (strequal(domain, builtin_domain_name())) { + + /* Explicit request for a name in BUILTIN */ + if (lookup_builtin_name(name, &rid)) { + sid_copy(&sid, &global_sid_Builtin); + sid_append_rid(&sid, rid); + type = SID_NAME_ALIAS; + goto ok; } + goto failed; } - - DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n", - local_lookup ? "local" : "winbind", domain, name)); + /* 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 ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) { + goto failed; + } + + /* + * Nasty hack necessary for too common scenarios: + * + * For 'valid users = +users' we know "users" is most probably not + * BUILTIN\users but the unix group users. This hack requires the + * admin to explicitly qualify BUILTIN if BUILTIN\users is meant. + * + * Please note that LOOKUP_NAME_GROUP can not be requested via for + * example lsa_lookupnames, it only comes into this routine via + * the expansion of group names coming in from smb.conf + */ + + if ((flags & LOOKUP_NAME_GROUP) && + (lookup_unix_group_name(name, &sid))) { + domain = talloc_strdup(tmp_ctx, unix_groups_domain_name()); + type = SID_NAME_DOM_GRP; + goto ok; + } + + /* Now the guesswork begins, we haven't been given an explicit + * domain. Try the sequence as documented on + * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp + * November 27, 2005 */ + + /* 1. well-known names */ + + if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) { + type = SID_NAME_WKN_GRP; + goto ok; + } + + /* 2. Builtin domain as such */ + + if (strequal(name, builtin_domain_name())) { + /* Swap domain and name */ + tmp = name; name = domain; domain = tmp; + sid_copy(&sid, &global_sid_Builtin); + type = SID_NAME_DOMAIN; + goto ok; + } + + /* 3. Account domain */ + + if (strequal(name, get_global_sam_name())) { + if (!secrets_fetch_domain_sid(name, &sid)) { + DEBUG(3, ("Could not fetch my SID\n")); + goto failed; + } + /* Swap domain and name */ + tmp = name; name = domain; domain = tmp; + type = SID_NAME_DOMAIN; + goto ok; + } + + /* 4. Primary domain */ + + if (!IS_DC && strequal(name, lp_workgroup())) { + if (!secrets_fetch_domain_sid(name, &sid)) { + DEBUG(3, ("Could not fetch the domain SID\n")); + goto failed; + } + /* Swap domain and name */ + tmp = name; name = domain; domain = tmp; + type = SID_NAME_DOMAIN; + goto ok; + } + + /* 5. Trusted domains as such, to me it looks as if members don't do + this, tested an XP workstation in a NT domain -- vl */ + + if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL, + &sid, NULL))) { + /* Swap domain and name */ + tmp = name; name = domain; domain = tmp; + type = SID_NAME_DOMAIN; + goto ok; + } + + /* 6. Builtin aliases */ + + if (lookup_builtin_name(name, &rid)) { + domain = talloc_strdup(tmp_ctx, builtin_domain_name()); + sid_copy(&sid, &global_sid_Builtin); + sid_append_rid(&sid, rid); + type = SID_NAME_ALIAS; + goto ok; + } + + /* 7. Local systems' SAM (DCs don't have a local SAM) */ + /* 8. Primary SAM (On members, this is the domain) */ + + /* Both cases are done by looking at our passdb */ + + 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); + goto ok; + } + + /* Now our local possibilities are exhausted. */ + + if (!(flags & LOOKUP_NAME_REMOTE)) { + goto failed; + } + + /* If we are not a DC, we have to ask in our primary domain. Let + * winbind do that. */ + + if (!IS_DC && + (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) { + domain = talloc_strdup(tmp_ctx, lp_workgroup()); + goto ok; + } + + /* 9. Trusted domains */ + + /* If we're a DC we have to ask all trusted DC's. Winbind does not do + * that (yet), but give it a chance. */ + + if (IS_DC && winbind_lookup_name("", name, &sid, &type)) { + DOM_SID dom_sid; + uint32 tmp_rid; + enum SID_NAME_USE domain_type; + + if (type == SID_NAME_DOMAIN) { + /* Swap name and type */ + tmp = name; name = domain; domain = tmp; + goto ok; + } + + /* Here we have to cope with a little deficiency in the + * winbind API: We have to ask it again for the name of the + * domain it figured out itself. Maybe fix that later... */ + + sid_copy(&dom_sid, &sid); + sid_split_rid(&dom_sid, &tmp_rid); + + if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL, + &domain_type) || + (domain_type != SID_NAME_DOMAIN)) { + DEBUG(2, ("winbind could not find the domain's name " + "it just looked up for us\n")); + goto failed; + } + goto ok; + } + + /* 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; + + ok: + if ((domain == NULL) || (name == NULL)) { + DEBUG(0, ("talloc failed\n")); + TALLOC_FREE(tmp_ctx); + return False; + } + + if (ret_name != NULL) { + *ret_name = talloc_steal(mem_ctx, name); + } + + if (ret_domain != NULL) { + char *tmp_dom = talloc_strdup(tmp_ctx, domain); + strupper_m(tmp_dom); + *ret_domain = talloc_steal(mem_ctx, tmp_dom); + } + + if (ret_sid != NULL) { + sid_copy(ret_sid, &sid); + } + + if (ret_type != NULL) { + *ret_type = type; + } + + TALLOC_FREE(tmp_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; i<num_rids; i++) { + DOM_SID sid; + + sid_copy(&sid, domain_sid); + sid_append_rid(&sid, rids[i]); + + if (winbind_lookup_sid(mem_ctx, &sid, + *domain_name == NULL ? + domain_name : NULL, + &names[i], &types[i])) { + if ((names[i] == NULL) || ((*domain_name) == NULL)) { + return False; + } + } else { + types[i] = SID_NAME_UNKNOWN; + } + } + return True; +} -BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, - enum SID_NAME_USE *name_type) +static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, + int num_rids, uint32_t *rids, + const char **domain_name, + const char ***names, enum SID_NAME_USE **types) { - if (!name_type) + int i; + + *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids); + *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids); + + if ((*names == NULL) || (*types == NULL)) { return False; + } - *name_type = SID_NAME_UNKNOWN; + if (sid_check_is_domain(domain_sid)) { + NTSTATUS result; - /* Check if this is our own sid. This should perhaps be done by - winbind? For the moment handle it here. */ + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, get_global_sam_name()); + } - if (sid_check_is_domain(sid)) { - fstrcpy(dom_name, get_global_sam_name()); - fstrcpy(name, ""); - *name_type = SID_NAME_DOMAIN; + if (*domain_name == NULL) { + return False; + } + + become_root(); + result = pdb_lookup_rids(domain_sid, num_rids, rids, + *names, *types); + unbecome_root(); + + return (NT_STATUS_IS_OK(result) || + NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) || + NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)); + } + + if (sid_check_is_builtin(domain_sid)) { + + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, builtin_domain_name()); + } + + if (*domain_name == NULL) { + return False; + } + + for (i=0; i<num_rids; i++) { + if (lookup_builtin_rid(*names, rids[i], + &(*names)[i])) { + if ((*names)[i] == NULL) { + return False; + } + (*types)[i] = SID_NAME_ALIAS; + } else { + (*types)[i] = SID_NAME_UNKNOWN; + } + } return True; } - if (sid_check_is_in_our_domain(sid)) { - uint32 rid; - SMB_ASSERT(sid_peek_rid(sid, &rid)); + if (sid_check_is_wellknown_domain(domain_sid, NULL)) { + for (i=0; i<num_rids; i++) { + DOM_SID sid; + sid_copy(&sid, domain_sid); + sid_append_rid(&sid, rids[i]); + if (lookup_wellknown_sid(mem_ctx, &sid, + domain_name, &(*names)[i])) { + if ((*names)[i] == NULL) { + return False; + } + (*types)[i] = SID_NAME_WKN_GRP; + } else { + (*types)[i] = SID_NAME_UNKNOWN; + } + } + return True; + } + + if (sid_check_is_unix_users(domain_sid)) { + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, unix_users_domain_name()); + } + for (i=0; i<num_rids; i++) { + (*names)[i] = talloc_strdup( + (*names), uidtoname(rids[i])); + (*types)[i] = SID_NAME_USER; + } + return True; + } - /* For our own domain passdb is responsible */ - fstrcpy(dom_name, get_global_sam_name()); - return lookup_global_sam_rid(rid, name, name_type); + if (sid_check_is_unix_groups(domain_sid)) { + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, unix_groups_domain_name()); + } + for (i=0; i<num_rids; i++) { + (*names)[i] = talloc_strdup( + (*names), gidtoname(rids[i])); + (*types)[i] = SID_NAME_DOM_GRP; + } + return True; } - if (sid_check_is_builtin(sid)) { + return winbind_lookup_rids(mem_ctx, domain_sid, num_rids, rids, + domain_name, *names, *types); +} - /* Got through map_domain_sid_to_name here so that the mapping - * of S-1-5-32 to the name "BUILTIN" in as few places as - * possible. We might add i18n... */ - SMB_ASSERT(map_domain_sid_to_name(sid, dom_name)); +/* + * Is the SID a domain as such? If yes, lookup its name. + */ - /* Yes, W2k3 returns "BUILTIN" both as domain and name here */ - fstrcpy(name, dom_name); +static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx, + const char **name) +{ + const char *tmp; + enum SID_NAME_USE type; - *name_type = SID_NAME_DOMAIN; + if (sid_check_is_domain(sid)) { + *name = talloc_strdup(mem_ctx, get_global_sam_name()); return True; } - if (sid_check_is_in_builtin(sid)) { - uint32 rid; + if (sid_check_is_builtin(sid)) { + *name = talloc_strdup(mem_ctx, builtin_domain_name()); + return True; + } - SMB_ASSERT(sid_peek_rid(sid, &rid)); + if (sid_check_is_wellknown_domain(sid, &tmp)) { + *name = talloc_strdup(mem_ctx, tmp); + return True; + } - /* Got through map_domain_sid_to_name here so that the mapping - * of S-1-5-32 to the name "BUILTIN" in as few places as - * possible. We might add i18n... */ - SMB_ASSERT(map_domain_sid_to_name(&global_sid_Builtin, - dom_name)); + if (sid->num_auths != 4) { + /* This can't be a domain */ + return False; + } - /* There's only aliases in S-1-5-32 */ - *name_type = SID_NAME_ALIAS; + if (IS_DC) { + uint32 i, num_domains; + struct trustdom_info **domains; - return lookup_builtin_rid(rid, name); + /* This is relatively expensive, but it happens only on DCs + * and for SIDs that have 4 sub-authorities and thus look like + * domains */ + + if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx, + &num_domains, + &domains))) { + return False; + } + + for (i=0; i<num_domains; i++) { + if (sid_equal(sid, &domains[i]->sid)) { + *name = talloc_strdup(mem_ctx, + domains[i]->name); + return True; + } + } + return False; } - if (winbind_lookup_sid(sid, dom_name, name, name_type)) { + if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) && + (type == SID_NAME_DOMAIN)) { + *name = tmp; return True; } - DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying " - "special SIDs.\n", sid_string_static(sid))); + return False; +} - { - const char *dom, *obj_name; - - if (lookup_special_sid(sid, &dom, &obj_name, name_type)) { - DEBUG(10, ("found %s\\%s\n", dom, obj_name)); - fstrcpy(dom_name, dom); - fstrcpy(name, obj_name); - return True; +/* + * 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, ("%s SID %s in level %d\n", + ret ? "Accepting" : "Rejecting", + sid_string_static(sid), level)); + return ret; +} + +/* + * 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; + } + + 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; i<num_sids; i++) { + DOM_SID sid; + uint32 rid; + const char *domain_name = NULL; + + sid_copy(&sid, sids[i]); + name_infos[i].type = SID_NAME_USE_NONE; + + if (lookup_as_domain(&sid, name_infos, &domain_name)) { + /* We can't push that through the normal lookup + * process, as this would reference illegal + * domains. + * + * For example S-1-5-32 would end up referencing + * domain S-1-5- with RID 32 which is clearly wrong. + */ + if (domain_name == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + name_infos[i].rid = 0; + name_infos[i].type = SID_NAME_DOMAIN; + name_infos[i].name = NULL; + + if (sid_check_is_builtin(&sid)) { + /* Yes, W2k3 returns "BUILTIN" both as domain + * and name here */ + name_infos[i].name = talloc_strdup( + name_infos, builtin_domain_name()); + if (name_infos[i].name == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + } + } else { + /* This is a normal SID with rid component */ + if (!sid_split_rid(&sid, &rid)) { + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + } + + if (!check_dom_sid_to_level(&sid, level)) { + name_infos[i].rid = 0; + name_infos[i].type = SID_NAME_UNKNOWN; + name_infos[i].name = NULL; + continue; + } + + for (j=0; j<MAX_REF_DOMAINS; j++) { + if (!dom_infos[j].valid) { + break; + } + if (sid_equal(&sid, &dom_infos[j].sid)) { + break; + } + } + + if (j == MAX_REF_DOMAINS) { + /* TODO: What's the right error message here? */ + result = NT_STATUS_NONE_MAPPED; + goto done; + } + + if (!dom_infos[j].valid) { + /* We found a domain not yet referenced, create a new + * ref. */ + dom_infos[j].valid = True; + sid_copy(&dom_infos[j].sid, &sid); + + if (domain_name != NULL) { + /* This name was being found above in the case + * when we found a domain SID */ + dom_infos[j].name = + talloc_steal(dom_infos, domain_name); + } else { + /* lookup_rids will take care of this */ + dom_infos[j].name = NULL; + } + } + + name_infos[i].dom_idx = j; + + if (name_infos[i].type == SID_NAME_USE_NONE) { + name_infos[i].rid = rid; + + ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs, + &dom_infos[j].num_idxs); + + if (dom_infos[j].idxs == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } } } - DEBUG(10, ("lookup_sid failed\n")); + /* Iterate over the domains found */ - return False; + for (i=0; i<MAX_REF_DOMAINS; i++) { + uint32_t *rids; + const char **names; + enum SID_NAME_USE *types; + struct lsa_dom_info *dom = &dom_infos[i]; + + if (!dom->valid) { + /* 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; j<dom->num_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; j<dom->num_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 result; +} + +/***************************************************************** + *THE CANONICAL* convert SID to name function. +*****************************************************************/ + +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->name); + } + + if (ret_name != NULL) { + *ret_name = talloc_steal(mem_ctx, name->name); + } + + if (ret_type != NULL) { + *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 ret; } /***************************************************************** @@ -187,10 +863,9 @@ static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid) for (pc = uid_sid_cache_head; pc; pc = pc->next) { if (pc->uid == uid) { - fstring sid; *psid = pc->sid; DEBUG(3,("fetch sid from uid cache %u -> %s\n", - (unsigned int)uid, sid_to_string(sid, psid))); + (unsigned int)uid, sid_string_static(psid))); DLIST_PROMOTE(uid_sid_cache_head, pc); return True; } @@ -208,10 +883,9 @@ static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) for (pc = uid_sid_cache_head; pc; pc = pc->next) { if (sid_compare(&pc->sid, psid) == 0) { - fstring sid; *puid = pc->uid; DEBUG(3,("fetch uid from cache %u -> %s\n", - (unsigned int)*puid, sid_to_string(sid, psid))); + (unsigned int)*puid, sid_string_static(psid))); DLIST_PROMOTE(uid_sid_cache_head, pc); return True; } @@ -223,7 +897,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; @@ -261,10 +935,9 @@ static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) for (pc = gid_sid_cache_head; pc; pc = pc->next) { if (pc->gid == gid) { - fstring sid; *psid = pc->sid; DEBUG(3,("fetch sid from gid cache %u -> %s\n", - (unsigned int)gid, sid_to_string(sid, psid))); + (unsigned int)gid, sid_string_static(psid))); DLIST_PROMOTE(gid_sid_cache_head, pc); return True; } @@ -282,10 +955,9 @@ static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) for (pc = gid_sid_cache_head; pc; pc = pc->next) { if (sid_compare(&pc->sid, psid) == 0) { - fstring sid; *pgid = pc->gid; DEBUG(3,("fetch gid from cache %u -> %s\n", - (unsigned int)*pgid, sid_to_string(sid, psid))); + (unsigned int)*pgid, sid_string_static(psid))); DLIST_PROMOTE(gid_sid_cache_head, pc); return True; } @@ -297,7 +969,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; @@ -329,201 +1001,259 @@ 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) { - fstring sid; 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 ); - - /* DC's never use winbindd to resolve users outside the - defined idmap range */ + return; - if ( lp_server_role()==ROLE_DOMAIN_MEMBER - || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) ) - { - if (winbind_uid_to_sid(psid, uid)) { + if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) && + winbind_uid_to_sid(psid, uid)) { - DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", - (unsigned int)uid, sid_to_string(sid, 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; } - - DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid))); + + 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) { - fstring sid; 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_to_string(sid, 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; } - - DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid))); + + 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) { - fstring dom_name, name, sid_str; - 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(psid, dom_name, name, &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_to_string(sid_str, 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: - DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid), + /* 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) { - fstring dom_name, name, sid_str; - 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) || + sid_check_is_in_wellknown_domain(psid))) { + if (pdb_getgrsid(&map, *psid)) { + *pgid = map.gid; + goto done; + } + return False; + } - 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(psid, dom_name, name, &name_type)) { - DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, 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_to_string(sid_str, 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: - DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid), - (unsigned int)*pgid )); + 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/source/passdb/machine_sid.c b/source/passdb/machine_sid.c index 87ec27d34ea..d7cae06749c 100644 --- a/source/passdb/machine_sid.c +++ b/source/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); @@ -198,3 +199,27 @@ void reset_global_sam_sid(void) { SAFE_FREE(global_sam_sid); } + +/***************************************************************** + Check if the SID is our domain SID (S-1-5-21-x-y-z). +*****************************************************************/ + +BOOL sid_check_is_domain(const DOM_SID *sid) +{ + return sid_equal(sid, get_global_sam_sid()); +} + +/***************************************************************** + Check if the SID is our domain SID (S-1-5-21-x-y-z). +*****************************************************************/ + +BOOL sid_check_is_in_our_domain(const DOM_SID *sid) +{ + DOM_SID dom_sid; + uint32 rid; + + sid_copy(&dom_sid, sid); + sid_split_rid(&dom_sid, &rid); + + return sid_equal(&dom_sid, get_global_sam_sid()); +} diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index 2c8ab514f55..876f04bdfe7 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -3,9 +3,10 @@ Password and authentication handling Copyright (C) Jeremy Allison 1996-2001 Copyright (C) Luke Kenneth Casson Leighton 1996-1998 - Copyright (C) Gerald (Jerry) Carter 2000-2001 + Copyright (C) Gerald (Jerry) Carter 2000-2006 Copyright (C) Andrew Bartlett 2001-2002 Copyright (C) Simo Sorce 2003 + Copyright (C) Volker Lendecke 2006 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 @@ -35,7 +36,7 @@ standalone box will map to WKS\user. ******************************************************************/ -const char *get_default_sam_name(void) +const char *my_sam_name(void) { /* standalone servers can only use the local netbios name */ if ( lp_server_role() == ROLE_STANDALONE ) @@ -46,410 +47,204 @@ const char *get_default_sam_name(void) return lp_workgroup(); } -/************************************************************ - Fill the SAM_ACCOUNT with default values. - ***********************************************************/ +/********************************************************************** +***********************************************************************/ -void pdb_fill_default_sam(SAM_ACCOUNT *user) +static int samu_destroy(void *p) { - ZERO_STRUCT(user->private_u); /* Don't touch the talloc context */ - - /* no initial methods */ - user->methods = NULL; - - /* Don't change these timestamp settings without a good reason. - They are important for NT member server compatibility. */ - - user->private_u.logon_time = (time_t)0; - user->private_u.pass_last_set_time = (time_t)0; - user->private_u.pass_can_change_time = (time_t)0; - user->private_u.logoff_time = - user->private_u.kickoff_time = - user->private_u.pass_must_change_time = get_time_t_max(); - user->private_u.fields_present = 0x00ffffff; - user->private_u.logon_divs = 168; /* hours per week */ - user->private_u.hours_len = 21; /* 21 times 8 bits = 168 */ - memset(user->private_u.hours, 0xff, user->private_u.hours_len); /* available at all hours */ - user->private_u.bad_password_count = 0; - user->private_u.logon_count = 0; - user->private_u.unknown_6 = 0x000004ec; /* don't know */ - - /* Some parts of samba strlen their pdb_get...() returns, - so this keeps the interface unchanged for now. */ - - user->private_u.username = ""; - user->private_u.domain = ""; - user->private_u.nt_username = ""; - user->private_u.full_name = ""; - user->private_u.home_dir = ""; - user->private_u.logon_script = ""; - user->private_u.profile_path = ""; - user->private_u.acct_desc = ""; - user->private_u.workstations = ""; - user->private_u.unknown_str = ""; - user->private_u.munged_dial = ""; - - user->private_u.plaintext_pw = NULL; - - /* - Unless we know otherwise have a Account Control Bit - value of 'normal user'. This helps User Manager, which - asks for a filtered list of users. - */ + struct samu *user = p; - user->private_u.acct_ctrl = ACB_NORMAL; -} + data_blob_clear_free( &user->lm_pw ); + data_blob_clear_free( &user->nt_pw ); -static void destroy_pdb_talloc(SAM_ACCOUNT **user) -{ - if (*user) { - data_blob_clear_free(&((*user)->private_u.lm_pw)); - data_blob_clear_free(&((*user)->private_u.nt_pw)); + if ( user->plaintext_pw ) + memset( user->plaintext_pw, 0x0, strlen(user->plaintext_pw) ); - if((*user)->private_u.plaintext_pw!=NULL) - memset((*user)->private_u.plaintext_pw,'\0',strlen((*user)->private_u.plaintext_pw)); - talloc_destroy((*user)->mem_ctx); - *user = NULL; - } + return 0; } - /********************************************************************** - Allocates memory and initialises a struct sam_passwd on supplied mem_ctx. + generate a new struct samuser ***********************************************************************/ -NTSTATUS pdb_init_sam_talloc(TALLOC_CTX *mem_ctx, SAM_ACCOUNT **user) +struct samu* samu_new( TALLOC_CTX *ctx ) { - if (*user != NULL) { - DEBUG(0,("pdb_init_sam_talloc: SAM_ACCOUNT was non NULL\n")); -#if 0 - smb_panic("non-NULL pointer passed to pdb_init_sam\n"); -#endif - return NT_STATUS_UNSUCCESSFUL; - } - - if (!mem_ctx) { - DEBUG(0,("pdb_init_sam_talloc: mem_ctx was NULL!\n")); - return NT_STATUS_UNSUCCESSFUL; + struct samu *user; + + if ( !(user = TALLOC_ZERO_P( ctx, struct samu )) ) { + DEBUG(0,("samuser_new: Talloc failed!\n")); + return NULL; } + + talloc_set_destructor( user, samu_destroy ); + + /* no initial methods */ + + user->methods = NULL; - *user=TALLOC_P(mem_ctx, SAM_ACCOUNT); - - if (*user==NULL) { - DEBUG(0,("pdb_init_sam_talloc: error while allocating memory\n")); - return NT_STATUS_NO_MEMORY; - } + /* Don't change these timestamp settings without a good reason. + They are important for NT member server compatibility. */ - (*user)->mem_ctx = mem_ctx; + user->logon_time = (time_t)0; + user->pass_last_set_time = (time_t)0; + user->pass_can_change_time = (time_t)0; + user->logoff_time = get_time_t_max(); + user->kickoff_time = get_time_t_max(); + user->pass_must_change_time = get_time_t_max(); + user->fields_present = 0x00ffffff; + user->logon_divs = 168; /* hours per week */ + user->hours_len = 21; /* 21 times 8 bits = 168 */ + memset(user->hours, 0xff, user->hours_len); /* available at all hours */ + user->bad_password_count = 0; + user->logon_count = 0; + user->unknown_6 = 0x000004ec; /* don't know */ - (*user)->free_fn = NULL; + /* Some parts of samba strlen their pdb_get...() returns, + so this keeps the interface unchanged for now. */ + + user->username = ""; + user->domain = ""; + user->nt_username = ""; + user->full_name = ""; + user->home_dir = ""; + user->logon_script = ""; + user->profile_path = ""; + user->acct_desc = ""; + user->workstations = ""; + user->unknown_str = ""; + user->munged_dial = ""; + + user->plaintext_pw = NULL; + + /* Unless we know otherwise have a Account Control Bit + value of 'normal user'. This helps User Manager, which + asks for a filtered list of users. */ - pdb_fill_default_sam(*user); + user->acct_ctrl = ACB_NORMAL; - return NT_STATUS_OK; + + return user; } +/********************************************************************* + Initialize a struct samu from a struct passwd including the user + and group SIDs. The *user structure is filled out with the Unix + attributes and a user SID. +*********************************************************************/ -/************************************************************* - Allocates memory and initialises a struct sam_passwd. - ************************************************************/ - -NTSTATUS pdb_init_sam(SAM_ACCOUNT **user) +static NTSTATUS samu_set_unix_internal(struct samu *user, const struct passwd *pwd, BOOL create) { - TALLOC_CTX *mem_ctx; - NTSTATUS nt_status; - - mem_ctx = talloc_init("passdb internal SAM_ACCOUNT allocation"); + const char *guest_account = lp_guestaccount(); + const char *domain = global_myname(); + uint32 urid; - if (!mem_ctx) { - DEBUG(0,("pdb_init_sam: error while doing talloc_init()\n")); - return NT_STATUS_NO_MEMORY; + if ( !pwd ) { + return NT_STATUS_NO_SUCH_USER; } - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(mem_ctx, user))) { - talloc_destroy(mem_ctx); - return nt_status; - } + /* Basic properties based upon the Unix account information */ - (*user)->free_fn = destroy_pdb_talloc; - - return NT_STATUS_OK; -} - -/************************************************************************** - * This function will take care of all the steps needed to correctly - * allocate and set the user SID, please do use this function to create new - * users, messing with SIDs is not good. - * - * account_data must be provided initialized, pwd may be null. - * SSS - ***************************************************************************/ - -static NTSTATUS pdb_set_sam_sids(SAM_ACCOUNT *account_data, const struct passwd *pwd) -{ - const char *guest_account = lp_guestaccount(); - GROUP_MAP map; - BOOL ret; + pdb_set_username(user, pwd->pw_name, PDB_SET); + pdb_set_fullname(user, pwd->pw_gecos, PDB_SET); + pdb_set_domain (user, get_global_sam_name(), PDB_DEFAULT); - if (!account_data || !pwd) { - return NT_STATUS_INVALID_PARAMETER; - } + /* save the password structure for later use */ + + user->unix_pw = tcopy_passwd( user, pwd ); - /* this is a hack this thing should not be set - this way --SSS */ - if (!(guest_account && *guest_account)) { - DEBUG(1, ("NULL guest account!?!?\n")); - return NT_STATUS_UNSUCCESSFUL; - } else { - /* Ensure this *must* be set right */ - if (strcmp(pwd->pw_name, guest_account) == 0) { - if (!pdb_set_user_sid_from_rid(account_data, DOMAIN_USER_RID_GUEST, PDB_DEFAULT)) { - return NT_STATUS_UNSUCCESSFUL; - } - if (!pdb_set_group_sid_from_rid(account_data, DOMAIN_GROUP_RID_GUESTS, PDB_DEFAULT)) { - return NT_STATUS_UNSUCCESSFUL; - } - return NT_STATUS_OK; + /* Special case for the guest account which must have a RID of 501 */ + + if ( strequal( pwd->pw_name, guest_account ) ) { + if ( !pdb_set_user_sid_from_rid(user, DOMAIN_USER_RID_GUEST, PDB_DEFAULT)) { + return NT_STATUS_NO_SUCH_USER; } + return NT_STATUS_OK; } - - if (!pdb_set_user_sid_from_rid(account_data, algorithmic_pdb_uid_to_user_rid(pwd->pw_uid), PDB_SET)) { - DEBUG(0,("Can't set User SID from RID!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* call the mapping code here */ - become_root(); - ret = pdb_getgrgid(&map, pwd->pw_gid); - unbecome_root(); - if( ret ) { - if (!pdb_set_group_sid(account_data, &map.sid, PDB_SET)){ - DEBUG(0,("Can't set Group SID!\n")); - return NT_STATUS_INVALID_PARAMETER; - } + /* Non-guest accounts...Check for a workstation or user account */ + + if (pwd->pw_name[strlen(pwd->pw_name)-1] == '$') { + /* workstation */ + + if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_DEFAULT)) { + DEBUG(1, ("Failed to set 'workstation account' flags for user %s.\n", + pwd->pw_name)); + return NT_STATUS_INVALID_COMPUTER_NAME; + } } else { - if (!pdb_set_group_sid_from_rid(account_data, pdb_gid_to_group_rid(pwd->pw_gid), PDB_SET)) { - DEBUG(0,("Can't set Group SID\n")); - return NT_STATUS_INVALID_PARAMETER; + /* user */ + + if (!pdb_set_acct_ctrl(user, ACB_NORMAL, PDB_DEFAULT)) { + DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n", + pwd->pw_name)); + return NT_STATUS_INVALID_ACCOUNT_NAME; } + + /* set some basic attributes */ + + pdb_set_profile_path(user, talloc_sub_specified(user, + lp_logon_path(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid), + PDB_DEFAULT); + pdb_set_homedir(user, talloc_sub_specified(user, + lp_logon_home(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid), + PDB_DEFAULT); + pdb_set_dir_drive(user, talloc_sub_specified(user, + lp_logon_drive(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid), + PDB_DEFAULT); + pdb_set_logon_script(user, talloc_sub_specified(user, + lp_logon_script(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid), + PDB_DEFAULT); } - - return NT_STATUS_OK; -} - -/************************************************************* - Initialises a struct sam_passwd with sane values. - ************************************************************/ - -NTSTATUS pdb_fill_sam_pw(SAM_ACCOUNT *sam_account, const struct passwd *pwd) -{ - NTSTATUS ret; - - if (!pwd) { - return NT_STATUS_UNSUCCESSFUL; - } - - pdb_fill_default_sam(sam_account); - - pdb_set_username(sam_account, pwd->pw_name, PDB_SET); - pdb_set_fullname(sam_account, pwd->pw_gecos, PDB_SET); - - pdb_set_unix_homedir(sam_account, pwd->pw_dir, PDB_SET); - - pdb_set_domain (sam_account, get_global_sam_name(), PDB_DEFAULT); - /* When we get a proper uid -> SID and SID -> uid allocation - mechinism, we should call it here. - - We can't just set this to 0 or allow it only to be filled - in when added to the backend, because the user's SID - may already be in security descriptors etc. - - -- abartlet 11-May-02 - */ - - ret = pdb_set_sam_sids(sam_account, pwd); - if (!NT_STATUS_IS_OK(ret)) return ret; - - /* check if this is a user account or a machine account */ - if (pwd->pw_name[strlen(pwd->pw_name)-1] != '$') - { - pdb_set_profile_path(sam_account, - talloc_sub_specified((sam_account)->mem_ctx, - lp_logon_path(), - pwd->pw_name, global_myname(), - pwd->pw_uid, pwd->pw_gid), - PDB_DEFAULT); - - pdb_set_homedir(sam_account, - talloc_sub_specified((sam_account)->mem_ctx, - lp_logon_home(), - pwd->pw_name, global_myname(), - pwd->pw_uid, pwd->pw_gid), - PDB_DEFAULT); - - pdb_set_dir_drive(sam_account, - talloc_sub_specified((sam_account)->mem_ctx, - lp_logon_drive(), - pwd->pw_name, global_myname(), - pwd->pw_uid, pwd->pw_gid), - PDB_DEFAULT); + /* Now deal with the user SID. If we have a backend that can generate + RIDs, then do so. But sometimes the caller just wanted a structure + initialized and will fill in these fields later (such as from a + NET_USER_INFO_3 structure) */ + + if ( create && !pdb_rid_algorithm() ) { + uint32 user_rid; + DOM_SID user_sid; - pdb_set_logon_script(sam_account, - talloc_sub_specified((sam_account)->mem_ctx, - lp_logon_script(), - pwd->pw_name, global_myname(), - pwd->pw_uid, pwd->pw_gid), - PDB_DEFAULT); - if (!pdb_set_acct_ctrl(sam_account, ACB_NORMAL, PDB_DEFAULT)) { - DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n", pwd->pw_name)); - return NT_STATUS_UNSUCCESSFUL; - } - } else { - if (!pdb_set_acct_ctrl(sam_account, ACB_WSTRUST, PDB_DEFAULT)) { - DEBUG(1, ("Failed to set 'trusted workstation account' flags for user %s.\n", pwd->pw_name)); - return NT_STATUS_UNSUCCESSFUL; + if ( !pdb_new_rid( &user_rid ) ) { + DEBUG(3, ("Could not allocate a new RID\n")); + return NT_STATUS_ACCESS_DENIED; } - } - return NT_STATUS_OK; -} - - -/************************************************************* - Initialises a struct sam_passwd with sane values. - ************************************************************/ - -NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd) -{ - NTSTATUS nt_status; - if (!pwd) { - new_sam_acct = NULL; - return NT_STATUS_INVALID_PARAMETER; - } - - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(new_sam_acct))) { - new_sam_acct = NULL; - return nt_status; - } + sid_copy( &user_sid, get_global_sam_sid() ); + sid_append_rid( &user_sid, user_rid ); - if (!NT_STATUS_IS_OK(nt_status = pdb_fill_sam_pw(*new_sam_acct, pwd))) { - pdb_free_sam(new_sam_acct); - new_sam_acct = NULL; - return nt_status; + if ( !pdb_set_user_sid(user, &user_sid, PDB_SET) ) { + DEBUG(3, ("pdb_set_user_sid failed\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + return NT_STATUS_OK; } - return NT_STATUS_OK; -} - - -/************************************************************* - Initialises a SAM_ACCOUNT ready to add a new account, based - 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 nt_status = NT_STATUS_NO_MEMORY; - struct passwd *pwd; - BOOL ret; - - pwd = Get_Pwnam(username); - - if (!pwd) - return NT_STATUS_NO_SUCH_USER; + /* generate a SID for the user with the RID algorithm */ - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) { - *new_sam_acct = NULL; - return nt_status; - } - - /* 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); + urid = algorithmic_pdb_uid_to_user_rid( user->unix_pw->pw_uid ); + + if ( !pdb_set_user_sid_from_rid( user, urid, PDB_SET) ) { + return NT_STATUS_INTERNAL_ERROR; } - /* 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); + return NT_STATUS_OK; } +/******************************************************************** + Set the Unix user attributes +********************************************************************/ -/** - * Free the contets of the SAM_ACCOUNT, but not the structure. - * - * Also wipes the LM and NT hashes and plaintext password from - * memory. - * - * @param user SAM_ACCOUNT to free members of. - **/ - -static void pdb_free_sam_contents(SAM_ACCOUNT *user) +NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd) { - - /* Kill off sensitive data. Free()ed by the - talloc mechinism */ - - data_blob_clear_free(&(user->private_u.lm_pw)); - data_blob_clear_free(&(user->private_u.nt_pw)); - if (user->private_u.plaintext_pw!=NULL) - memset(user->private_u.plaintext_pw,'\0',strlen(user->private_u.plaintext_pw)); - - if (user->private_u.backend_private_data && user->private_u.backend_private_data_free_fn) { - user->private_u.backend_private_data_free_fn(&user->private_u.backend_private_data); - } + return samu_set_unix_internal( user, pwd, False ); } - -/************************************************************ - Reset the SAM_ACCOUNT and free the NT/LM hashes. - ***********************************************************/ - -NTSTATUS pdb_reset_sam(SAM_ACCOUNT *user) +NTSTATUS samu_alloc_rid_unix(struct samu *user, const struct passwd *pwd) { - if (user == NULL) { - DEBUG(0,("pdb_reset_sam: SAM_ACCOUNT was NULL\n")); -#if 0 - smb_panic("NULL pointer passed to pdb_free_sam\n"); -#endif - return NT_STATUS_UNSUCCESSFUL; - } - - pdb_free_sam_contents(user); - - pdb_fill_default_sam(user); - - return NT_STATUS_OK; -} - - -/************************************************************ - Free the SAM_ACCOUNT and the member pointers. - ***********************************************************/ - -NTSTATUS pdb_free_sam(SAM_ACCOUNT **user) -{ - if (*user == NULL) { - DEBUG(0,("pdb_free_sam: SAM_ACCOUNT was NULL\n")); -#if 0 - smb_panic("NULL pointer passed to pdb_free_sam\n"); -#endif - return NT_STATUS_UNSUCCESSFUL; - } - - pdb_free_sam_contents(*user); - - if ((*user)->free_fn) { - (*user)->free_fn(user); - } - - return NT_STATUS_OK; + return samu_set_unix_internal( user, pwd, True ); } /********************************************************** @@ -458,7 +253,7 @@ NTSTATUS pdb_free_sam(SAM_ACCOUNT **user) null). length *MUST BE MORE THAN 2* ! **********************************************************/ -char *pdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length) +char *pdb_encode_acct_ctrl(uint32 acct_ctrl, size_t length) { static fstring acct_str; @@ -494,9 +289,9 @@ char *pdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length) Decode the account control bits from a string. **********************************************************/ -uint16 pdb_decode_acct_ctrl(const char *p) +uint32 pdb_decode_acct_ctrl(const char *p) { - uint16 acct_ctrl = 0; + uint32 acct_ctrl = 0; BOOL finished = False; /* @@ -536,7 +331,7 @@ uint16 pdb_decode_acct_ctrl(const char *p) Routine to set 32 hex password characters from a 16 byte array. **************************************************************/ -void pdb_sethexpwd(char *p, const unsigned char *pwd, uint16 acct_ctrl) +void pdb_sethexpwd(char *p, const unsigned char *pwd, uint32 acct_ctrl) { if (pwd != NULL) { int i; @@ -634,6 +429,9 @@ BOOL pdb_gethexhours(const char *p, unsigned char *hours) return (True); } +/******************************************************************** +********************************************************************/ + int algorithmic_rid_base(void) { static int rid_offset = 0; @@ -666,6 +464,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 +489,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. @@ -704,7 +512,7 @@ uint32 pdb_gid_to_group_rid(gid_t gid) Decides if a RID is a well known RID. ********************************************************************/ -static BOOL pdb_rid_is_well_known(uint32 rid) +static BOOL rid_is_well_known(uint32 rid) { /* Not using rid_offset here, because this is the actual NT fixed value (1000) */ @@ -718,7 +526,7 @@ static BOOL pdb_rid_is_well_known(uint32 rid) BOOL algorithmic_pdb_rid_is_user(uint32 rid) { - if(pdb_rid_is_well_known(rid)) { + if ( rid_is_well_known(rid) ) { /* * The only well known user RIDs are DOMAIN_USER_RID_ADMIN * and DOMAIN_USER_RID_GUEST. @@ -732,215 +540,85 @@ BOOL algorithmic_pdb_rid_is_user(uint32 rid) } /******************************************************************* - Look up a rid in the SAM we're responsible for (i.e. passdb) + Convert a name into a SID. Used in the lookup name rpc. ********************************************************************/ -BOOL lookup_global_sam_rid(uint32 rid, fstring name, - enum SID_NAME_USE *psid_name_use) +BOOL lookup_global_sam_name(const char *user, int flags, uint32_t *rid, + enum SID_NAME_USE *type) { - 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() */ - fstrcpy(name, pdb_get_username(sam_account)); - *psid_name_use = SID_NAME_USER; - - pdb_free_sam(&sam_account); - + /* Windows treats "MACHINE\None" as a special name for + rid 513 on non-DCs. You cannot create a user or group + name "None" on Windows. You will get an error that + the group already exists. */ + + if ( strequal( user, "None" ) ) { + *rid = DOMAIN_GROUP_RID_USERS; + *type = SID_NAME_DOM_GRP; + 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)); - } - fstrcpy(name, map.nt_name); - *psid_name_use = map.sid_name_use; - return True; - } + /* 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 (rid == DOMAIN_USER_RID_ADMIN) { - *psid_name_use = SID_NAME_USER; - fstrcpy(name, "Administrator"); - return True; - } + if ((flags & LOOKUP_NAME_GROUP) == 0) { + struct samu *sam_account = NULL; + DOM_SID user_sid; - 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)); + if ( !(sam_account = samu_new( NULL )) ) { + return False; + } + + become_root(); + ret = pdb_getsampwnam(sam_account, user); + unbecome_root(); - 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 ) - fstr_sprintf(name, "unix_user.%u", (unsigned int)uid); - else - fstrcpy( name, 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 ) - fstr_sprintf(name, "unix_group.%u", (unsigned int)gid); - else - fstrcpy( name, 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; + if (ret) { + sid_copy(&user_sid, pdb_get_user_sid(sam_account)); + } - return ( gr != NULL ); - } -} - -/******************************************************************* - Convert a name into a SID. Used in the lookup name rpc. - ********************************************************************/ + TALLOC_FREE(sam_account); -BOOL local_lookup_name(const char *c_user, DOM_SID *psid, enum SID_NAME_USE *psid_name_use) -{ - DOM_SID local_sid; - DOM_SID sid; - fstring user; - SAM_ACCOUNT *sam_account = NULL; - struct group *grp; - GROUP_MAP map; + if (ret) { + if (!sid_check_is_in_our_domain(&user_sid)) { + DEBUG(0, ("User %s with invalid SID %s in passdb\n", + user, sid_string_static(&user_sid))); + return False; + } - *psid_name_use = SID_NAME_UNKNOWN; + sid_peek_rid(&user_sid, rid); + *type = SID_NAME_USER; + return True; + } + } /* - * user may be quoted a const string, and map_username and - * friends can modify it. Make a modifiable copy. JRA. + * Maybe it is a group ? */ - fstrcpy(user, c_user); - - sid_copy(&local_sid, get_global_sam_sid()); - - if (map_name_to_wellknown_sid(&sid, psid_name_use, user)){ - fstring sid_str; - sid_copy( psid, &sid); - sid_to_string(sid_str, &sid); - DEBUG(10,("lookup_name: name %s = SID %s, type = %u\n", user, sid_str, - (unsigned int)*psid_name_use )); - return True; - } - - (void)map_username(user); + become_root(); + ret = pdb_getgrnam(&map, user); + unbecome_root(); - if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) { + if (!ret) { return False; } - - /* BEGIN ROOT BLOCK */ - - become_root(); - if (pdb_getsampwnam(sam_account, user)) { - unbecome_root(); - sid_copy(psid, pdb_get_user_sid(sam_account)); - *psid_name_use = SID_NAME_USER; - - pdb_free_sam(&sam_account); - return True; - } - - pdb_free_sam(&sam_account); - - /* - * Maybe it was a group ? - */ - /* check if it's a mapped group */ - if (pdb_getgrnam(&map, user)) { - /* yes it's a mapped group */ - sid_copy(&local_sid, &map.sid); - *psid_name_use = map.sid_name_use; - } else { - /* it's not a mapped group */ - grp = getgrnam(user); - if(!grp) { - unbecome_root(); /* ---> exit form block */ - return False; - } - - /* - *check if it's mapped, if it is reply it doesn't exist - * - * that's to prevent this case: - * - * unix group ug is mapped to nt group ng - * someone does a lookup on ug - * we must not reply as it doesn't "exist" anymore - * for NT. For NT only ng exists. - * JFM, 30/11/2001 - */ - - if (pdb_getgrgid(&map, grp->gr_gid)){ - unbecome_root(); /* ---> exit form block */ - return False; - } - - sid_append_rid( &local_sid, pdb_gid_to_group_rid(grp->gr_gid)); - *psid_name_use = SID_NAME_ALIAS; + /* BUILTIN groups are looked up elsewhere */ + if (!sid_check_is_in_our_domain(&map.sid)) { + DEBUG(10, ("Found group %s (%s) not in our domain -- " + "ignoring.", user, + sid_string_static(&map.sid))); + return False; } - unbecome_root(); - /* END ROOT BLOCK */ - - sid_copy( psid, &local_sid); + /* yes it's a mapped group */ + sid_peek_rid(&map.sid, rid); + *type = map.sid_name_use; return True; } @@ -948,34 +626,67 @@ BOOL local_lookup_name(const char *c_user, DOM_SID *psid, enum SID_NAME_USE *psi 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; + struct samu *sam_pass=NULL; + uint32 other_acb; + NTSTATUS result; *err_str = '\0'; *msg_str = '\0'; /* Get the smb passwd entry for this user */ - pdb_init_sam(&sam_pass); + + if ( !(sam_pass = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } become_root(); if(!pdb_getsampwnam(sam_pass, user_name)) { unbecome_root(); - pdb_free_sam(&sam_pass); + TALLOC_FREE(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; + struct passwd *pwd; + + /* Might not exist in /etc/passwd. */ + + if (tmp_debug < 1) { + DEBUGLEVEL = 1; + } + + if ( !(pwd = getpwnam_alloc( NULL, user_name)) ) { + return NT_STATUS_NO_SUCH_USER; + } + + /* create the struct samu and initialize the basic Unix properties */ + + if ( !(sam_pass = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } + + result = samu_set_unix( sam_pass, pwd ); + + DEBUGLEVEL = tmp_debug; + + TALLOC_FREE( pwd ); + + 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(); @@ -988,20 +699,20 @@ BOOL local_password_change(const char *user_name, int local_flags, if (local_flags & LOCAL_TRUST_ACCOUNT) { 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; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + return NT_STATUS_UNSUCCESSFUL; } } @@ -1013,22 +724,22 @@ BOOL local_password_change(const char *user_name, int local_flags, if (local_flags & LOCAL_DISABLE_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 set 'disabled' flag for user %s.\n", user_name); - pdb_free_sam(&sam_pass); - return False; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + return NT_STATUS_UNSUCCESSFUL; } } if (local_flags & LOCAL_SET_NO_PASSWORD) { 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; + TALLOC_FREE(sam_pass); + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_SET_PASSWORD) { /* @@ -1043,45 +754,46 @@ BOOL local_password_change(const char *user_name, int local_flags, if ((pdb_get_lanman_passwd(sam_pass)==NULL) && (pdb_get_acct_ctrl(sam_pass)&ACB_DISABLED)) { 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; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + return NT_STATUS_UNSUCCESSFUL; } } if (local_flags & LOCAL_ADD_USER) { - if (pdb_add_sam_account(sam_pass)) { + if (NT_STATUS_IS_OK(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; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_DELETE_USER) { - if (!pdb_delete_sam_account(sam_pass)) { + if (!NT_STATUS_IS_OK(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; + TALLOC_FREE(sam_pass); + 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; + TALLOC_FREE(sam_pass); + return result; } if(local_flags & LOCAL_DISABLE_USER) slprintf(msg_str, msg_str_len-1, "Disabled user %s.\n", user_name); @@ -1091,627 +803,20 @@ BOOL local_password_change(const char *user_name, int local_flags, slprintf(msg_str, msg_str_len-1, "User %s password set to none.\n", user_name); } - 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; -} - -/********************************************************************** - Marshall/unmarshall SAM_ACCOUNT structs. - *********************************************************************/ - -#define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" -#define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" -#define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" - -/********************************************************************** - Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len - *********************************************************************/ - -BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) -{ - return(init_sam_from_buffer_v2(sampass, buf, buflen)); + TALLOC_FREE(sam_pass); + return NT_STATUS_OK; } /********************************************************************** - Intialize a BYTE buffer from a SAM_ACCOUNT struct + Marshall/unmarshall struct samu structs. *********************************************************************/ -uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only) -{ - return(init_buffer_from_sam_v2(buf, sampass, size_only)); -} - - -BOOL init_sam_from_buffer_v0(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) -{ - - /* times are stored as 32bit integer - take care on system with 64bit wide time_t - --SSS */ - uint32 logon_time, - logoff_time, - kickoff_time, - pass_last_set_time, - pass_can_change_time, - pass_must_change_time; - char *username = NULL; - char *domain = NULL; - char *nt_username = NULL; - char *dir_drive = NULL; - char *unknown_str = NULL; - char *munged_dial = NULL; - char *fullname = NULL; - char *homedir = NULL; - char *logon_script = NULL; - char *profile_path = NULL; - char *acct_desc = NULL; - char *workstations = NULL; - uint32 username_len, domain_len, nt_username_len, - dir_drive_len, unknown_str_len, munged_dial_len, - fullname_len, homedir_len, logon_script_len, - profile_path_len, acct_desc_len, workstations_len; - - uint32 user_rid, group_rid, remove_me, hours_len, unknown_6; - uint16 acct_ctrl, logon_divs; - uint16 bad_password_count, logon_count; - uint8 *hours = NULL; - uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL; - uint32 len = 0; - uint32 lm_pw_len, nt_pw_len, hourslen; - BOOL ret = True; - - if(sampass == NULL || buf == NULL) { - DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n")); - return False; - } - -/* TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */ - - /* unpack the buffer into variables */ - len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V0, - &logon_time, /* d */ - &logoff_time, /* d */ - &kickoff_time, /* d */ - &pass_last_set_time, /* d */ - &pass_can_change_time, /* d */ - &pass_must_change_time, /* d */ - &username_len, &username, /* B */ - &domain_len, &domain, /* B */ - &nt_username_len, &nt_username, /* B */ - &fullname_len, &fullname, /* B */ - &homedir_len, &homedir, /* B */ - &dir_drive_len, &dir_drive, /* B */ - &logon_script_len, &logon_script, /* B */ - &profile_path_len, &profile_path, /* B */ - &acct_desc_len, &acct_desc, /* B */ - &workstations_len, &workstations, /* B */ - &unknown_str_len, &unknown_str, /* B */ - &munged_dial_len, &munged_dial, /* B */ - &user_rid, /* d */ - &group_rid, /* d */ - &lm_pw_len, &lm_pw_ptr, /* B */ - &nt_pw_len, &nt_pw_ptr, /* B */ - &acct_ctrl, /* w */ - &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */ - &logon_divs, /* w */ - &hours_len, /* d */ - &hourslen, &hours, /* B */ - &bad_password_count, /* w */ - &logon_count, /* w */ - &unknown_6); /* d */ - - if (len == (uint32) -1) { - ret = False; - goto done; - } - - pdb_set_logon_time(sampass, logon_time, PDB_SET); - pdb_set_logoff_time(sampass, logoff_time, PDB_SET); - pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); - pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); - pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET); - pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); - - pdb_set_username(sampass, username, PDB_SET); - pdb_set_domain(sampass, domain, PDB_SET); - pdb_set_nt_username(sampass, nt_username, PDB_SET); - pdb_set_fullname(sampass, fullname, PDB_SET); - - if (homedir) { - pdb_set_homedir(sampass, homedir, PDB_SET); - } - else { - pdb_set_homedir(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_home()), - PDB_DEFAULT); - } - - if (dir_drive) - pdb_set_dir_drive(sampass, dir_drive, PDB_SET); - else { - pdb_set_dir_drive(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_drive()), - PDB_DEFAULT); - } - - if (logon_script) - pdb_set_logon_script(sampass, logon_script, PDB_SET); - else { - pdb_set_logon_script(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_script()), - PDB_DEFAULT); - } - - if (profile_path) { - pdb_set_profile_path(sampass, profile_path, PDB_SET); - } else { - pdb_set_profile_path(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_path()), - PDB_DEFAULT); - } - - pdb_set_acct_desc(sampass, acct_desc, PDB_SET); - pdb_set_workstations(sampass, workstations, PDB_SET); - pdb_set_munged_dial(sampass, munged_dial, PDB_SET); - - if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { - if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { - ret = False; - goto done; - } - } - - if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { - if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { - ret = False; - goto done; - } - } - - pdb_set_pw_history(sampass, NULL, 0, PDB_SET); - pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); - pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); - pdb_set_hours_len(sampass, hours_len, PDB_SET); - pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); - pdb_set_logon_count(sampass, logon_count, PDB_SET); - pdb_set_unknown_6(sampass, unknown_6, PDB_SET); - pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); - pdb_set_logon_divs(sampass, logon_divs, PDB_SET); - pdb_set_hours(sampass, hours, PDB_SET); - -done: - - SAFE_FREE(username); - SAFE_FREE(domain); - SAFE_FREE(nt_username); - SAFE_FREE(fullname); - SAFE_FREE(homedir); - SAFE_FREE(dir_drive); - SAFE_FREE(logon_script); - SAFE_FREE(profile_path); - SAFE_FREE(acct_desc); - SAFE_FREE(workstations); - SAFE_FREE(munged_dial); - SAFE_FREE(unknown_str); - SAFE_FREE(lm_pw_ptr); - SAFE_FREE(nt_pw_ptr); - SAFE_FREE(hours); - - return ret; -} - -BOOL init_sam_from_buffer_v1(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) -{ - - /* times are stored as 32bit integer - take care on system with 64bit wide time_t - --SSS */ - uint32 logon_time, - logoff_time, - kickoff_time, - bad_password_time, - pass_last_set_time, - pass_can_change_time, - pass_must_change_time; - char *username = NULL; - char *domain = NULL; - char *nt_username = NULL; - char *dir_drive = NULL; - char *unknown_str = NULL; - char *munged_dial = NULL; - char *fullname = NULL; - char *homedir = NULL; - char *logon_script = NULL; - char *profile_path = NULL; - char *acct_desc = NULL; - char *workstations = NULL; - uint32 username_len, domain_len, nt_username_len, - dir_drive_len, unknown_str_len, munged_dial_len, - fullname_len, homedir_len, logon_script_len, - profile_path_len, acct_desc_len, workstations_len; - - uint32 user_rid, group_rid, remove_me, hours_len, unknown_6; - uint16 acct_ctrl, logon_divs; - uint16 bad_password_count, logon_count; - uint8 *hours = NULL; - uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL; - uint32 len = 0; - uint32 lm_pw_len, nt_pw_len, hourslen; - BOOL ret = True; - - if(sampass == NULL || buf == NULL) { - DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n")); - return False; - } - -/* TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */ - - /* unpack the buffer into variables */ - len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V1, - &logon_time, /* d */ - &logoff_time, /* d */ - &kickoff_time, /* d */ - /* Change from V0 is addition of bad_password_time field. */ - &bad_password_time, /* d */ - &pass_last_set_time, /* d */ - &pass_can_change_time, /* d */ - &pass_must_change_time, /* d */ - &username_len, &username, /* B */ - &domain_len, &domain, /* B */ - &nt_username_len, &nt_username, /* B */ - &fullname_len, &fullname, /* B */ - &homedir_len, &homedir, /* B */ - &dir_drive_len, &dir_drive, /* B */ - &logon_script_len, &logon_script, /* B */ - &profile_path_len, &profile_path, /* B */ - &acct_desc_len, &acct_desc, /* B */ - &workstations_len, &workstations, /* B */ - &unknown_str_len, &unknown_str, /* B */ - &munged_dial_len, &munged_dial, /* B */ - &user_rid, /* d */ - &group_rid, /* d */ - &lm_pw_len, &lm_pw_ptr, /* B */ - &nt_pw_len, &nt_pw_ptr, /* B */ - &acct_ctrl, /* w */ - &remove_me, /* d */ - &logon_divs, /* w */ - &hours_len, /* d */ - &hourslen, &hours, /* B */ - &bad_password_count, /* w */ - &logon_count, /* w */ - &unknown_6); /* d */ - - if (len == (uint32) -1) { - ret = False; - goto done; - } - - pdb_set_logon_time(sampass, logon_time, PDB_SET); - pdb_set_logoff_time(sampass, logoff_time, PDB_SET); - pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); - - /* Change from V0 is addition of bad_password_time field. */ - pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET); - pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); - pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET); - pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); - - pdb_set_username(sampass, username, PDB_SET); - pdb_set_domain(sampass, domain, PDB_SET); - pdb_set_nt_username(sampass, nt_username, PDB_SET); - pdb_set_fullname(sampass, fullname, PDB_SET); - - if (homedir) { - pdb_set_homedir(sampass, homedir, PDB_SET); - } - else { - pdb_set_homedir(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_home()), - PDB_DEFAULT); - } - - if (dir_drive) - pdb_set_dir_drive(sampass, dir_drive, PDB_SET); - else { - pdb_set_dir_drive(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_drive()), - PDB_DEFAULT); - } - - if (logon_script) - pdb_set_logon_script(sampass, logon_script, PDB_SET); - else { - pdb_set_logon_script(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_script()), - PDB_DEFAULT); - } - - if (profile_path) { - pdb_set_profile_path(sampass, profile_path, PDB_SET); - } else { - pdb_set_profile_path(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_path()), - PDB_DEFAULT); - } - - pdb_set_acct_desc(sampass, acct_desc, PDB_SET); - pdb_set_workstations(sampass, workstations, PDB_SET); - pdb_set_munged_dial(sampass, munged_dial, PDB_SET); - - if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { - if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { - ret = False; - goto done; - } - } - - if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { - if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { - ret = False; - goto done; - } - } - - pdb_set_pw_history(sampass, NULL, 0, PDB_SET); - - pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); - pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); - pdb_set_hours_len(sampass, hours_len, PDB_SET); - pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); - pdb_set_logon_count(sampass, logon_count, PDB_SET); - pdb_set_unknown_6(sampass, unknown_6, PDB_SET); - pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); - pdb_set_logon_divs(sampass, logon_divs, PDB_SET); - pdb_set_hours(sampass, hours, PDB_SET); - -done: - - SAFE_FREE(username); - SAFE_FREE(domain); - SAFE_FREE(nt_username); - SAFE_FREE(fullname); - SAFE_FREE(homedir); - SAFE_FREE(dir_drive); - SAFE_FREE(logon_script); - SAFE_FREE(profile_path); - SAFE_FREE(acct_desc); - SAFE_FREE(workstations); - SAFE_FREE(munged_dial); - SAFE_FREE(unknown_str); - SAFE_FREE(lm_pw_ptr); - SAFE_FREE(nt_pw_ptr); - SAFE_FREE(hours); - - return ret; -} +#define TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" +/********************************************************************* +*********************************************************************/ -BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) +BOOL init_sam_from_buffer_v3(struct samu *sampass, uint8 *buf, uint32 buflen) { /* times are stored as 32bit integer @@ -1741,8 +846,8 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) fullname_len, homedir_len, logon_script_len, profile_path_len, acct_desc_len, workstations_len; - uint32 user_rid, group_rid, hours_len, unknown_6; - uint16 acct_ctrl, logon_divs; + uint32 user_rid, group_rid, hours_len, unknown_6, acct_ctrl; + uint16 logon_divs; uint16 bad_password_count, logon_count; uint8 *hours = NULL; uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL; @@ -1754,14 +859,14 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) BOOL expand_explicit = lp_passdb_expand_explicit(); if(sampass == NULL || buf == NULL) { - DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n")); + DEBUG(0, ("init_sam_from_buffer_v3: NULL parameters found!\n")); return False; } -/* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ +/* TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */ /* unpack the buffer into variables */ - len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V2, + len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V3, &logon_time, /* d */ &logoff_time, /* d */ &kickoff_time, /* d */ @@ -1787,7 +892,8 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) &nt_pw_len, &nt_pw_ptr, /* B */ /* Change from V1 is addition of password history field. */ &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */ - &acct_ctrl, /* w */ + /* Change from V2 is the uint32 acb_mask */ + &acct_ctrl, /* d */ /* Also "remove_me" field was removed. */ &logon_divs, /* w */ &hours_len, /* d */ @@ -1824,7 +930,7 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) } else { pdb_set_homedir(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_home()), + talloc_sub_basic(sampass, username, lp_logon_home()), PDB_DEFAULT); } @@ -1843,7 +949,7 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) } else { pdb_set_logon_script(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_script()), + talloc_sub_basic(sampass, username, lp_logon_script()), PDB_DEFAULT); } @@ -1857,7 +963,7 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) } else { pdb_set_profile_path(sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_path()), + talloc_sub_basic(sampass, username, lp_logon_path()), PDB_DEFAULT); } @@ -1879,7 +985,6 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) } } - /* Change from V1 is addition of password history field. */ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen) { uint8 *pw_hist = SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN); @@ -1909,11 +1014,11 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) } pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); - pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); pdb_set_hours_len(sampass, hours_len, PDB_SET); pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); pdb_set_logon_count(sampass, logon_count, PDB_SET); pdb_set_unknown_6(sampass, unknown_6, PDB_SET); + /* Change from V2 is the uint32 acct_ctrl */ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); pdb_set_logon_divs(sampass, logon_divs, PDB_SET); pdb_set_hours(sampass, hours, PDB_SET); @@ -1940,7 +1045,10 @@ done: return ret; } -uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only) +/********************************************************************* +*********************************************************************/ + +uint32 init_buffer_from_sam_v3 (uint8 **buf, struct samu *sampass, BOOL size_only) { size_t len, buflen; @@ -1982,9 +1090,9 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si uint32 nt_pw_hist_len; uint32 pwHistLen = 0; - /* do we have a valid SAM_ACCOUNT pointer? */ + /* do we have a valid struct samu pointer? */ if (sampass == NULL) { - DEBUG(0, ("init_buffer_from_sam: SAM_ACCOUNT is NULL!\n")); + DEBUG(0, ("init_buffer_from_sam: struct samu is NULL!\n")); return -1; } @@ -2120,10 +1228,10 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si munged_dial_len = 0; } -/* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ +/* TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */ /* one time to get the size needed */ - len = tdb_pack(NULL, 0, TDB_FORMAT_STRING_V2, + len = tdb_pack(NULL, 0, TDB_FORMAT_STRING_V3, logon_time, /* d */ logoff_time, /* d */ kickoff_time, /* d */ @@ -2148,7 +1256,7 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si lm_pw_len, lm_pw, /* B */ nt_pw_len, nt_pw, /* B */ nt_pw_hist_len, nt_pw_hist, /* B */ - pdb_get_acct_ctrl(sampass), /* w */ + pdb_get_acct_ctrl(sampass), /* d */ pdb_get_logon_divs(sampass), /* w */ pdb_get_hours_len(sampass), /* d */ MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */ @@ -2162,12 +1270,12 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si /* malloc the space needed */ if ( (*buf=(uint8*)SMB_MALLOC(len)) == NULL) { - DEBUG(0,("init_buffer_from_sam_v2: Unable to malloc() memory for buffer!\n")); + DEBUG(0,("init_buffer_from_sam_v3: Unable to malloc() memory for buffer!\n")); return (-1); } /* now for the real call to tdb_pack() */ - buflen = tdb_pack((char *)*buf, len, TDB_FORMAT_STRING_V2, + buflen = tdb_pack((char *)*buf, len, TDB_FORMAT_STRING_V3, logon_time, /* d */ logoff_time, /* d */ kickoff_time, /* d */ @@ -2192,7 +1300,7 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si lm_pw_len, lm_pw, /* B */ nt_pw_len, nt_pw, /* B */ nt_pw_hist_len, nt_pw_hist, /* B */ - pdb_get_acct_ctrl(sampass), /* w */ + pdb_get_acct_ctrl(sampass), /* d */ pdb_get_logon_divs(sampass), /* w */ pdb_get_hours_len(sampass), /* d */ MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */ @@ -2202,7 +1310,7 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si /* check to make sure we got it correct */ if (buflen != len) { - DEBUG(0, ("init_buffer_from_sam_v2: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n", + DEBUG(0, ("init_buffer_from_sam_v3: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n", (unsigned long)buflen, (unsigned long)len)); /* error */ SAFE_FREE (*buf); @@ -2212,78 +1320,40 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si return (buflen); } -BOOL pdb_copy_sam_account(const SAM_ACCOUNT *src, SAM_ACCOUNT **dst) + +/********************************************************************* +*********************************************************************/ + +BOOL pdb_copy_sam_account(struct samu *dst, struct samu *src ) { BOOL result; uint8 *buf; int len; - if ((*dst == NULL) && (!NT_STATUS_IS_OK(pdb_init_sam(dst)))) + if ( !dst ) return False; - len = init_buffer_from_sam_v2(&buf, src, False); + len = init_buffer_from_sam_v3(&buf, src, False); if (len == -1) return False; - result = init_sam_from_buffer_v2(*dst, buf, len); - (*dst)->methods = src->methods; + result = init_sam_from_buffer_v3( dst, buf, len ); + dst->methods = src->methods; + + if ( src->unix_pw ) + dst->unix_pw = tcopy_passwd( dst, src->unix_pw ); free(buf); 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 *********************************************************************/ -BOOL pdb_update_bad_password_count(SAM_ACCOUNT *sampass, BOOL *updated) +BOOL pdb_update_bad_password_count(struct samu *sampass, BOOL *updated) { time_t LastBadPassword; uint16 BadPasswordCount; @@ -2326,7 +1396,7 @@ BOOL pdb_update_bad_password_count(SAM_ACCOUNT *sampass, BOOL *updated) Update the ACB_AUTOLOCK flag checking the AP_LOCK_ACCOUNT_DURATION *********************************************************************/ -BOOL pdb_update_autolock_flag(SAM_ACCOUNT *sampass, BOOL *updated) +BOOL pdb_update_autolock_flag(struct samu *sampass, BOOL *updated) { uint32 duration; time_t LastBadPassword; @@ -2379,7 +1449,7 @@ bad password time. Leaving locked out.\n", Increment the bad_password_count *********************************************************************/ -BOOL pdb_increment_bad_password_count(SAM_ACCOUNT *sampass) +BOOL pdb_increment_bad_password_count(struct samu *sampass) { uint32 account_policy_lockout; BOOL autolock_updated = False, badpw_updated = False; diff --git a/source/passdb/pdb_compat.c b/source/passdb/pdb_compat.c index abd572a7c14..788663f27a4 100644 --- a/source/passdb/pdb_compat.c +++ b/source/passdb/pdb_compat.c @@ -1,6 +1,6 @@ /* Unix SMB/CIFS implementation. - SAM_ACCOUNT access routines + struct samu access routines Copyright (C) Jeremy Allison 1996-2001 Copyright (C) Luke Kenneth Casson Leighton 1996-1998 Copyright (C) Gerald (Jerry) Carter 2000-2001 @@ -27,7 +27,7 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_PASSDB -uint32 pdb_get_user_rid (const SAM_ACCOUNT *sampass) +uint32 pdb_get_user_rid (const struct samu *sampass) { uint32 u_rid; @@ -38,7 +38,7 @@ uint32 pdb_get_user_rid (const SAM_ACCOUNT *sampass) return (0); } -uint32 pdb_get_group_rid (const SAM_ACCOUNT *sampass) +uint32 pdb_get_group_rid (struct samu *sampass) { uint32 g_rid; @@ -48,7 +48,7 @@ uint32 pdb_get_group_rid (const SAM_ACCOUNT *sampass) return (0); } -BOOL pdb_set_user_sid_from_rid (SAM_ACCOUNT *sampass, uint32 rid, enum pdb_value_state flag) +BOOL pdb_set_user_sid_from_rid (struct samu *sampass, uint32 rid, enum pdb_value_state flag) { DOM_SID u_sid; const DOM_SID *global_sam_sid; @@ -75,7 +75,7 @@ BOOL pdb_set_user_sid_from_rid (SAM_ACCOUNT *sampass, uint32 rid, enum pdb_value return True; } -BOOL pdb_set_group_sid_from_rid (SAM_ACCOUNT *sampass, uint32 grid, enum pdb_value_state flag) +BOOL pdb_set_group_sid_from_rid (struct samu *sampass, uint32 grid, enum pdb_value_state flag) { DOM_SID g_sid; const DOM_SID *global_sam_sid; diff --git a/source/passdb/pdb_get_set.c b/source/passdb/pdb_get_set.c index 783e9e23fa3..5cb72e7f863 100644 --- a/source/passdb/pdb_get_set.c +++ b/source/passdb/pdb_get_set.c @@ -1,6 +1,6 @@ /* Unix SMB/CIFS implementation. - SAM_ACCOUNT access routines + struct samu access routines Copyright (C) Jeremy Allison 1996-2001 Copyright (C) Luke Kenneth Casson Leighton 1996-1998 Copyright (C) Gerald (Jerry) Carter 2000-2001 @@ -37,126 +37,126 @@ #define PDB_NOT_QUITE_NULL "" /********************************************************************* - Collection of get...() functions for SAM_ACCOUNT. + Collection of get...() functions for struct samu. ********************************************************************/ -uint16 pdb_get_acct_ctrl (const SAM_ACCOUNT *sampass) +uint32 pdb_get_acct_ctrl (const struct samu *sampass) { if (sampass) - return (sampass->private_u.acct_ctrl); + return (sampass->acct_ctrl); else return (ACB_DISABLED); } -time_t pdb_get_logon_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_logon_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.logon_time); + return (sampass->logon_time); else return (0); } -time_t pdb_get_logoff_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_logoff_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.logoff_time); + return (sampass->logoff_time); else return (-1); } -time_t pdb_get_kickoff_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_kickoff_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.kickoff_time); + return (sampass->kickoff_time); else return (-1); } -time_t pdb_get_bad_password_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_bad_password_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.bad_password_time); + return (sampass->bad_password_time); else return (-1); } -time_t pdb_get_pass_last_set_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_pass_last_set_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.pass_last_set_time); + return (sampass->pass_last_set_time); else return (-1); } -time_t pdb_get_pass_can_change_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_pass_can_change_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.pass_can_change_time); + return (sampass->pass_can_change_time); else return (-1); } -time_t pdb_get_pass_must_change_time (const SAM_ACCOUNT *sampass) +time_t pdb_get_pass_must_change_time (const struct samu *sampass) { if (sampass) - return (sampass->private_u.pass_must_change_time); + return (sampass->pass_must_change_time); else return (-1); } -uint16 pdb_get_logon_divs (const SAM_ACCOUNT *sampass) +uint16 pdb_get_logon_divs (const struct samu *sampass) { if (sampass) - return (sampass->private_u.logon_divs); + return (sampass->logon_divs); else return (-1); } -uint32 pdb_get_hours_len (const SAM_ACCOUNT *sampass) +uint32 pdb_get_hours_len (const struct samu *sampass) { if (sampass) - return (sampass->private_u.hours_len); + return (sampass->hours_len); else return (-1); } -const uint8* pdb_get_hours (const SAM_ACCOUNT *sampass) +const uint8* pdb_get_hours (const struct samu *sampass) { if (sampass) - return (sampass->private_u.hours); + return (sampass->hours); else return (NULL); } -const uint8* pdb_get_nt_passwd (const SAM_ACCOUNT *sampass) +const uint8* pdb_get_nt_passwd (const struct samu *sampass) { if (sampass) { - SMB_ASSERT((!sampass->private_u.nt_pw.data) - || sampass->private_u.nt_pw.length == NT_HASH_LEN); - return ((uint8*)sampass->private_u.nt_pw.data); + SMB_ASSERT((!sampass->nt_pw.data) + || sampass->nt_pw.length == NT_HASH_LEN); + return ((uint8*)sampass->nt_pw.data); } else return (NULL); } -const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass) +const uint8* pdb_get_lanman_passwd (const struct samu *sampass) { if (sampass) { - SMB_ASSERT((!sampass->private_u.lm_pw.data) - || sampass->private_u.lm_pw.length == LM_HASH_LEN); - return ((uint8*)sampass->private_u.lm_pw.data); + SMB_ASSERT((!sampass->lm_pw.data) + || sampass->lm_pw.length == LM_HASH_LEN); + return ((uint8*)sampass->lm_pw.data); } else return (NULL); } -const uint8* pdb_get_pw_history (const SAM_ACCOUNT *sampass, uint32 *current_hist_len) +const uint8* pdb_get_pw_history (const struct samu *sampass, uint32 *current_hist_len) { if (sampass) { - SMB_ASSERT((!sampass->private_u.nt_pw_his.data) - || ((sampass->private_u.nt_pw_his.length % PW_HISTORY_ENTRY_LEN) == 0)); - *current_hist_len = sampass->private_u.nt_pw_his.length / PW_HISTORY_ENTRY_LEN; - return ((uint8*)sampass->private_u.nt_pw_his.data); + SMB_ASSERT((!sampass->nt_pw_his.data) + || ((sampass->nt_pw_his.length % PW_HISTORY_ENTRY_LEN) == 0)); + *current_hist_len = sampass->nt_pw_his.length / PW_HISTORY_ENTRY_LEN; + return ((uint8*)sampass->nt_pw_his.data); } else { *current_hist_len = 0; return (NULL); @@ -169,49 +169,114 @@ const uint8* pdb_get_pw_history (const SAM_ACCOUNT *sampass, uint32 *current_his Used to pass the plaintext to passdb backends that might want to store more than just the NTLM hashes. */ -const char* pdb_get_plaintext_passwd (const SAM_ACCOUNT *sampass) +const char* pdb_get_plaintext_passwd (const struct samu *sampass) { if (sampass) { - return (sampass->private_u.plaintext_pw); + return (sampass->plaintext_pw); } else return (NULL); } -const DOM_SID *pdb_get_user_sid(const SAM_ACCOUNT *sampass) +const DOM_SID *pdb_get_user_sid(const struct samu *sampass) { if (sampass) - return &sampass->private_u.user_sid; - else - return (NULL); + return &sampass->user_sid; + + return NULL; } -const DOM_SID *pdb_get_group_sid(const SAM_ACCOUNT *sampass) +const DOM_SID *pdb_get_group_sid(struct samu *sampass) { - if (sampass) - return &sampass->private_u.group_sid; - else - return (NULL); + DOM_SID *gsid; + struct passwd *pwd; + + /* sanity check */ + + if ( !sampass ) { + return NULL; + } + + /* Return the cached group SID if we have that */ + + if ( sampass->group_sid ) { + return sampass->group_sid; + } + + /* generate the group SID from the user's primary Unix group */ + + if ( !(gsid = TALLOC_P( sampass, DOM_SID )) ) { + return NULL; + } + + /* 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. We rely on the user's Unix primary gid. + We have no choice but to fail if we can't find it. */ + + if ( sampass->unix_pw ) + pwd = sampass->unix_pw; + else + pwd = getpwnam_alloc( sampass, pdb_get_username(sampass) ); + + if ( !pwd ) { + DEBUG(0,("pdb_get_group_sid: Failed to find Unix account for %s\n", pdb_get_username(sampass) )); + return NULL; + } + + if ( pdb_gid_to_sid(pwd->pw_gid, gsid) ) { + enum SID_NAME_USE type = SID_NAME_UNKNOWN; + TALLOC_CTX *mem_ctx = talloc_init("pdb_get_group_sid"); + BOOL lookup_ret; + + if (!mem_ctx) { + return NULL; + } + + /* Now check that it's actually a domain group and not something else */ + + lookup_ret = lookup_sid(mem_ctx, gsid, NULL, NULL, &type); + + TALLOC_FREE( mem_ctx ); + + if ( lookup_ret && (type == SID_NAME_DOM_GRP) ) { + sampass->group_sid = gsid; + return sampass->group_sid; + } + + DEBUG(3, ("Primary group for user %s is a %s and not a domain group\n", + pwd->pw_name, sid_type_lookup(type))); + } + + /* Just set it to the 'Domain Users' RID of 512 which will + always resolve to a name */ + + sid_copy( gsid, get_global_sam_sid() ); + sid_append_rid( gsid, DOMAIN_GROUP_RID_USERS ); + + sampass->group_sid = gsid; + + return sampass->group_sid; } /** - * Get flags showing what is initalised in the SAM_ACCOUNT - * @param sampass the SAM_ACCOUNT in question + * Get flags showing what is initalised in the struct samu + * @param sampass the struct samu in question * @return the flags indicating the members initialised in the struct. **/ -enum pdb_value_state pdb_get_init_flags (const SAM_ACCOUNT *sampass, enum pdb_elements element) +enum pdb_value_state pdb_get_init_flags (const struct samu *sampass, enum pdb_elements element) { enum pdb_value_state ret = PDB_DEFAULT; - if (!sampass || !sampass->private_u.change_flags || !sampass->private_u.set_flags) + if (!sampass || !sampass->change_flags || !sampass->set_flags) return ret; - if (bitmap_query(sampass->private_u.set_flags, element)) { + if (bitmap_query(sampass->set_flags, element)) { DEBUG(11, ("element %d: SET\n", element)); ret = PDB_SET; } - if (bitmap_query(sampass->private_u.change_flags, element)) { + if (bitmap_query(sampass->change_flags, element)) { DEBUG(11, ("element %d: CHANGED\n", element)); ret = PDB_CHANGED; } @@ -223,270 +288,270 @@ enum pdb_value_state pdb_get_init_flags (const SAM_ACCOUNT *sampass, enum pdb_el return ret; } -const char* pdb_get_username (const SAM_ACCOUNT *sampass) +const char* pdb_get_username (const struct samu *sampass) { if (sampass) - return (sampass->private_u.username); + return (sampass->username); else return (NULL); } -const char* pdb_get_domain (const SAM_ACCOUNT *sampass) +const char* pdb_get_domain (const struct samu *sampass) { if (sampass) - return (sampass->private_u.domain); + return (sampass->domain); else return (NULL); } -const char* pdb_get_nt_username (const SAM_ACCOUNT *sampass) +const char* pdb_get_nt_username (const struct samu *sampass) { if (sampass) - return (sampass->private_u.nt_username); + return (sampass->nt_username); else return (NULL); } -const char* pdb_get_fullname (const SAM_ACCOUNT *sampass) +const char* pdb_get_fullname (const struct samu *sampass) { if (sampass) - return (sampass->private_u.full_name); + return (sampass->full_name); else return (NULL); } -const char* pdb_get_homedir (const SAM_ACCOUNT *sampass) +const char* pdb_get_homedir (const struct samu *sampass) { if (sampass) - return (sampass->private_u.home_dir); + return (sampass->home_dir); else return (NULL); } -const char* pdb_get_unix_homedir (const SAM_ACCOUNT *sampass) +const char* pdb_get_unix_homedir (const struct samu *sampass) { - if (sampass) - return (sampass->private_u.unix_home_dir); - else - return (NULL); + if ( sampass && sampass->unix_pw ) + return ( sampass->unix_pw->pw_dir ); + + return (NULL); } -const char* pdb_get_dir_drive (const SAM_ACCOUNT *sampass) +const char* pdb_get_dir_drive (const struct samu *sampass) { if (sampass) - return (sampass->private_u.dir_drive); + return (sampass->dir_drive); else return (NULL); } -const char* pdb_get_logon_script (const SAM_ACCOUNT *sampass) +const char* pdb_get_logon_script (const struct samu *sampass) { if (sampass) - return (sampass->private_u.logon_script); + return (sampass->logon_script); else return (NULL); } -const char* pdb_get_profile_path (const SAM_ACCOUNT *sampass) +const char* pdb_get_profile_path (const struct samu *sampass) { if (sampass) - return (sampass->private_u.profile_path); + return (sampass->profile_path); else return (NULL); } -const char* pdb_get_acct_desc (const SAM_ACCOUNT *sampass) +const char* pdb_get_acct_desc (const struct samu *sampass) { if (sampass) - return (sampass->private_u.acct_desc); + return (sampass->acct_desc); else return (NULL); } -const char* pdb_get_workstations (const SAM_ACCOUNT *sampass) +const char* pdb_get_workstations (const struct samu *sampass) { if (sampass) - return (sampass->private_u.workstations); + return (sampass->workstations); else return (NULL); } -const char* pdb_get_unknown_str (const SAM_ACCOUNT *sampass) +const char* pdb_get_unknown_str (const struct samu *sampass) { if (sampass) - return (sampass->private_u.unknown_str); + return (sampass->unknown_str); else return (NULL); } -const char* pdb_get_munged_dial (const SAM_ACCOUNT *sampass) +const char* pdb_get_munged_dial (const struct samu *sampass) { if (sampass) - return (sampass->private_u.munged_dial); + return (sampass->munged_dial); else return (NULL); } -uint16 pdb_get_bad_password_count(const SAM_ACCOUNT *sampass) +uint16 pdb_get_bad_password_count(const struct samu *sampass) { if (sampass) - return (sampass->private_u.bad_password_count); + return (sampass->bad_password_count); else return 0; } -uint16 pdb_get_logon_count(const SAM_ACCOUNT *sampass) +uint16 pdb_get_logon_count(const struct samu *sampass) { if (sampass) - return (sampass->private_u.logon_count); + return (sampass->logon_count); else return 0; } -uint32 pdb_get_unknown_6 (const SAM_ACCOUNT *sampass) +uint32 pdb_get_unknown_6 (const struct samu *sampass) { if (sampass) - return (sampass->private_u.unknown_6); + return (sampass->unknown_6); else return (-1); } -void *pdb_get_backend_private_data (const SAM_ACCOUNT *sampass, const struct pdb_methods *my_methods) +void *pdb_get_backend_private_data (const struct samu *sampass, const struct pdb_methods *my_methods) { - if (sampass && my_methods == sampass->private_u.backend_private_methods) - return sampass->private_u.backend_private_data; + if (sampass && my_methods == sampass->backend_private_methods) + return sampass->backend_private_data; else return NULL; } /********************************************************************* - Collection of set...() functions for SAM_ACCOUNT. + Collection of set...() functions for struct samu. ********************************************************************/ -BOOL pdb_set_acct_ctrl (SAM_ACCOUNT *sampass, uint16 acct_ctrl, enum pdb_value_state flag) +BOOL pdb_set_acct_ctrl (struct samu *sampass, uint32 acct_ctrl, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.acct_ctrl = acct_ctrl; + sampass->acct_ctrl = acct_ctrl; return pdb_set_init_flags(sampass, PDB_ACCTCTRL, flag); } -BOOL pdb_set_logon_time (SAM_ACCOUNT *sampass, time_t mytime, enum pdb_value_state flag) +BOOL pdb_set_logon_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.logon_time = mytime; + sampass->logon_time = mytime; return pdb_set_init_flags(sampass, PDB_LOGONTIME, flag); } -BOOL pdb_set_logoff_time (SAM_ACCOUNT *sampass, time_t mytime, enum pdb_value_state flag) +BOOL pdb_set_logoff_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.logoff_time = mytime; + sampass->logoff_time = mytime; return pdb_set_init_flags(sampass, PDB_LOGOFFTIME, flag); } -BOOL pdb_set_kickoff_time (SAM_ACCOUNT *sampass, time_t mytime, enum pdb_value_state flag) +BOOL pdb_set_kickoff_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.kickoff_time = mytime; + sampass->kickoff_time = mytime; return pdb_set_init_flags(sampass, PDB_KICKOFFTIME, flag); } -BOOL pdb_set_bad_password_time (SAM_ACCOUNT *sampass, time_t mytime, +BOOL pdb_set_bad_password_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.bad_password_time = mytime; + sampass->bad_password_time = mytime; return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_TIME, flag); } -BOOL pdb_set_pass_can_change_time (SAM_ACCOUNT *sampass, time_t mytime, enum pdb_value_state flag) +BOOL pdb_set_pass_can_change_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.pass_can_change_time = mytime; + sampass->pass_can_change_time = mytime; return pdb_set_init_flags(sampass, PDB_CANCHANGETIME, flag); } -BOOL pdb_set_pass_must_change_time (SAM_ACCOUNT *sampass, time_t mytime, enum pdb_value_state flag) +BOOL pdb_set_pass_must_change_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.pass_must_change_time = mytime; + sampass->pass_must_change_time = mytime; return pdb_set_init_flags(sampass, PDB_MUSTCHANGETIME, flag); } -BOOL pdb_set_pass_last_set_time (SAM_ACCOUNT *sampass, time_t mytime, enum pdb_value_state flag) +BOOL pdb_set_pass_last_set_time (struct samu *sampass, time_t mytime, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.pass_last_set_time = mytime; + sampass->pass_last_set_time = mytime; return pdb_set_init_flags(sampass, PDB_PASSLASTSET, flag); } -BOOL pdb_set_hours_len (SAM_ACCOUNT *sampass, uint32 len, enum pdb_value_state flag) +BOOL pdb_set_hours_len (struct samu *sampass, uint32 len, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.hours_len = len; + sampass->hours_len = len; return pdb_set_init_flags(sampass, PDB_HOURSLEN, flag); } -BOOL pdb_set_logon_divs (SAM_ACCOUNT *sampass, uint16 hours, enum pdb_value_state flag) +BOOL pdb_set_logon_divs (struct samu *sampass, uint16 hours, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.logon_divs = hours; + sampass->logon_divs = hours; return pdb_set_init_flags(sampass, PDB_LOGONDIVS, flag); } /** - * Set flags showing what is initalised in the SAM_ACCOUNT - * @param sampass the SAM_ACCOUNT in question + * Set flags showing what is initalised in the struct samu + * @param sampass the struct samu in question * @param flag The *new* flag to be set. Old flags preserved * this flag is only added. **/ -BOOL pdb_set_init_flags (SAM_ACCOUNT *sampass, enum pdb_elements element, enum pdb_value_state value_flag) +BOOL pdb_set_init_flags (struct samu *sampass, enum pdb_elements element, enum pdb_value_state value_flag) { - if (!sampass || !sampass->mem_ctx) + if (!sampass || !sampass) return False; - if (!sampass->private_u.set_flags) { - if ((sampass->private_u.set_flags = - bitmap_talloc(sampass->mem_ctx, + if (!sampass->set_flags) { + if ((sampass->set_flags = + bitmap_talloc(sampass, PDB_COUNT))==NULL) { DEBUG(0,("bitmap_talloc failed\n")); return False; } } - if (!sampass->private_u.change_flags) { - if ((sampass->private_u.change_flags = - bitmap_talloc(sampass->mem_ctx, + if (!sampass->change_flags) { + if ((sampass->change_flags = + bitmap_talloc(sampass, PDB_COUNT))==NULL) { DEBUG(0,("bitmap_talloc failed\n")); return False; @@ -495,22 +560,22 @@ BOOL pdb_set_init_flags (SAM_ACCOUNT *sampass, enum pdb_elements element, enum p switch(value_flag) { case PDB_CHANGED: - if (!bitmap_set(sampass->private_u.change_flags, element)) { + if (!bitmap_set(sampass->change_flags, element)) { DEBUG(0,("Can't set flag: %d in change_flags.\n",element)); return False; } - if (!bitmap_set(sampass->private_u.set_flags, element)) { + if (!bitmap_set(sampass->set_flags, element)) { DEBUG(0,("Can't set flag: %d in set_flags.\n",element)); return False; } DEBUG(11, ("element %d -> now CHANGED\n", element)); break; case PDB_SET: - if (!bitmap_clear(sampass->private_u.change_flags, element)) { + if (!bitmap_clear(sampass->change_flags, element)) { DEBUG(0,("Can't set flag: %d in change_flags.\n",element)); return False; } - if (!bitmap_set(sampass->private_u.set_flags, element)) { + if (!bitmap_set(sampass->set_flags, element)) { DEBUG(0,("Can't set flag: %d in set_flags.\n",element)); return False; } @@ -518,11 +583,11 @@ BOOL pdb_set_init_flags (SAM_ACCOUNT *sampass, enum pdb_elements element, enum p break; case PDB_DEFAULT: default: - if (!bitmap_clear(sampass->private_u.change_flags, element)) { + if (!bitmap_clear(sampass->change_flags, element)) { DEBUG(0,("Can't set flag: %d in change_flags.\n",element)); return False; } - if (!bitmap_clear(sampass->private_u.set_flags, element)) { + if (!bitmap_clear(sampass->set_flags, element)) { DEBUG(0,("Can't set flag: %d in set_flags.\n",element)); return False; } @@ -533,20 +598,20 @@ BOOL pdb_set_init_flags (SAM_ACCOUNT *sampass, enum pdb_elements element, enum p return True; } -BOOL pdb_set_user_sid (SAM_ACCOUNT *sampass, const DOM_SID *u_sid, enum pdb_value_state flag) +BOOL pdb_set_user_sid (struct samu *sampass, const DOM_SID *u_sid, enum pdb_value_state flag) { if (!sampass || !u_sid) return False; - sid_copy(&sampass->private_u.user_sid, u_sid); + sid_copy(&sampass->user_sid, u_sid); DEBUG(10, ("pdb_set_user_sid: setting user sid %s\n", - sid_string_static(&sampass->private_u.user_sid))); + sid_string_static(&sampass->user_sid))); return pdb_set_init_flags(sampass, PDB_USERSID, flag); } -BOOL pdb_set_user_sid_from_string (SAM_ACCOUNT *sampass, fstring u_sid, enum pdb_value_state flag) +BOOL pdb_set_user_sid_from_string (struct samu *sampass, fstring u_sid, enum pdb_value_state flag) { DOM_SID new_sid; @@ -562,69 +627,70 @@ BOOL pdb_set_user_sid_from_string (SAM_ACCOUNT *sampass, fstring u_sid, enum pdb } if (!pdb_set_user_sid(sampass, &new_sid, flag)) { - DEBUG(1, ("pdb_set_user_sid_from_string: could not set sid %s on SAM_ACCOUNT!\n", u_sid)); + DEBUG(1, ("pdb_set_user_sid_from_string: could not set sid %s on struct samu!\n", u_sid)); return False; } return True; } -BOOL pdb_set_group_sid (SAM_ACCOUNT *sampass, const DOM_SID *g_sid, enum pdb_value_state flag) -{ - if (!sampass || !g_sid) - return False; - - sid_copy(&sampass->private_u.group_sid, g_sid); - - DEBUG(10, ("pdb_set_group_sid: setting group sid %s\n", - sid_string_static(&sampass->private_u.group_sid))); - - return pdb_set_init_flags(sampass, PDB_GROUPSID, flag); -} +/******************************************************************** + We never fill this in from a passdb backend but rather set is + based on the user's primary group membership. However, the + struct samu* is overloaded and reused in domain memship code + as well and built from the NET_USER_INFO_3 or PAC so we + have to allow the explicitly setting of a group SID here. +********************************************************************/ -BOOL pdb_set_group_sid_from_string (SAM_ACCOUNT *sampass, fstring g_sid, enum pdb_value_state flag) +BOOL pdb_set_group_sid (struct samu *sampass, const DOM_SID *g_sid, enum pdb_value_state flag) { - DOM_SID new_sid; + gid_t gid; + if (!sampass || !g_sid) return False; - DEBUG(10, ("pdb_set_group_sid_from_string: setting group sid %s\n", - g_sid)); - - if (!string_to_sid(&new_sid, g_sid)) { - DEBUG(1, ("pdb_set_group_sid_from_string: %s isn't a valid SID!\n", g_sid)); + if ( !(sampass->group_sid = TALLOC_P( sampass, DOM_SID )) ) { return False; } - - if (!pdb_set_group_sid(sampass, &new_sid, flag)) { - DEBUG(1, ("pdb_set_group_sid_from_string: could not set sid %s on SAM_ACCOUNT!\n", g_sid)); - return False; + + /* if we cannot resolve the SID to gid, then just ignore it and + store DOMAIN_USERS as the primary groupSID */ + + if ( sid_to_gid( g_sid, &gid ) ) { + sid_copy(sampass->group_sid, g_sid); + } else { + sid_copy( sampass->group_sid, get_global_sam_sid() ); + sid_append_rid( sampass->group_sid, DOMAIN_GROUP_RID_USERS ); } - return True; + + DEBUG(10, ("pdb_set_group_sid: setting group sid %s\n", + sid_string_static(sampass->group_sid))); + + return pdb_set_init_flags(sampass, PDB_GROUPSID, flag); } /********************************************************************* Set the user's UNIX name. ********************************************************************/ -BOOL pdb_set_username(SAM_ACCOUNT *sampass, const char *username, enum pdb_value_state flag) +BOOL pdb_set_username(struct samu *sampass, const char *username, enum pdb_value_state flag) { if (!sampass) return False; if (username) { DEBUG(10, ("pdb_set_username: setting username %s, was %s\n", username, - (sampass->private_u.username)?(sampass->private_u.username):"NULL")); + (sampass->username)?(sampass->username):"NULL")); - sampass->private_u.username = talloc_strdup(sampass->mem_ctx, username); + sampass->username = talloc_strdup(sampass, username); - if (!sampass->private_u.username) { + if (!sampass->username) { DEBUG(0, ("pdb_set_username: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.username = PDB_NOT_QUITE_NULL; + sampass->username = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_USERNAME, flag); @@ -634,24 +700,24 @@ BOOL pdb_set_username(SAM_ACCOUNT *sampass, const char *username, enum pdb_value Set the domain name. ********************************************************************/ -BOOL pdb_set_domain(SAM_ACCOUNT *sampass, const char *domain, enum pdb_value_state flag) +BOOL pdb_set_domain(struct samu *sampass, const char *domain, enum pdb_value_state flag) { if (!sampass) return False; if (domain) { DEBUG(10, ("pdb_set_domain: setting domain %s, was %s\n", domain, - (sampass->private_u.domain)?(sampass->private_u.domain):"NULL")); + (sampass->domain)?(sampass->domain):"NULL")); - sampass->private_u.domain = talloc_strdup(sampass->mem_ctx, domain); + sampass->domain = talloc_strdup(sampass, domain); - if (!sampass->private_u.domain) { + if (!sampass->domain) { DEBUG(0, ("pdb_set_domain: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.domain = PDB_NOT_QUITE_NULL; + sampass->domain = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_DOMAIN, flag); @@ -661,24 +727,24 @@ BOOL pdb_set_domain(SAM_ACCOUNT *sampass, const char *domain, enum pdb_value_sta Set the user's NT name. ********************************************************************/ -BOOL pdb_set_nt_username(SAM_ACCOUNT *sampass, const char *nt_username, enum pdb_value_state flag) +BOOL pdb_set_nt_username(struct samu *sampass, const char *nt_username, enum pdb_value_state flag) { if (!sampass) return False; if (nt_username) { DEBUG(10, ("pdb_set_nt_username: setting nt username %s, was %s\n", nt_username, - (sampass->private_u.nt_username)?(sampass->private_u.nt_username):"NULL")); + (sampass->nt_username)?(sampass->nt_username):"NULL")); - sampass->private_u.nt_username = talloc_strdup(sampass->mem_ctx, nt_username); + sampass->nt_username = talloc_strdup(sampass, nt_username); - if (!sampass->private_u.nt_username) { + if (!sampass->nt_username) { DEBUG(0, ("pdb_set_nt_username: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.nt_username = PDB_NOT_QUITE_NULL; + sampass->nt_username = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_NTUSERNAME, flag); @@ -688,24 +754,24 @@ BOOL pdb_set_nt_username(SAM_ACCOUNT *sampass, const char *nt_username, enum pdb Set the user's full name. ********************************************************************/ -BOOL pdb_set_fullname(SAM_ACCOUNT *sampass, const char *full_name, enum pdb_value_state flag) +BOOL pdb_set_fullname(struct samu *sampass, const char *full_name, enum pdb_value_state flag) { if (!sampass) return False; if (full_name) { DEBUG(10, ("pdb_set_full_name: setting full name %s, was %s\n", full_name, - (sampass->private_u.full_name)?(sampass->private_u.full_name):"NULL")); + (sampass->full_name)?(sampass->full_name):"NULL")); - sampass->private_u.full_name = talloc_strdup(sampass->mem_ctx, full_name); + sampass->full_name = talloc_strdup(sampass, full_name); - if (!sampass->private_u.full_name) { + if (!sampass->full_name) { DEBUG(0, ("pdb_set_fullname: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.full_name = PDB_NOT_QUITE_NULL; + sampass->full_name = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_FULLNAME, flag); @@ -715,24 +781,24 @@ BOOL pdb_set_fullname(SAM_ACCOUNT *sampass, const char *full_name, enum pdb_valu Set the user's logon script. ********************************************************************/ -BOOL pdb_set_logon_script(SAM_ACCOUNT *sampass, const char *logon_script, enum pdb_value_state flag) +BOOL pdb_set_logon_script(struct samu *sampass, const char *logon_script, enum pdb_value_state flag) { if (!sampass) return False; if (logon_script) { DEBUG(10, ("pdb_set_logon_script: setting logon script %s, was %s\n", logon_script, - (sampass->private_u.logon_script)?(sampass->private_u.logon_script):"NULL")); + (sampass->logon_script)?(sampass->logon_script):"NULL")); - sampass->private_u.logon_script = talloc_strdup(sampass->mem_ctx, logon_script); + sampass->logon_script = talloc_strdup(sampass, logon_script); - if (!sampass->private_u.logon_script) { + if (!sampass->logon_script) { DEBUG(0, ("pdb_set_logon_script: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.logon_script = PDB_NOT_QUITE_NULL; + sampass->logon_script = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_LOGONSCRIPT, flag); @@ -742,24 +808,24 @@ BOOL pdb_set_logon_script(SAM_ACCOUNT *sampass, const char *logon_script, enum p Set the user's profile path. ********************************************************************/ -BOOL pdb_set_profile_path (SAM_ACCOUNT *sampass, const char *profile_path, enum pdb_value_state flag) +BOOL pdb_set_profile_path (struct samu *sampass, const char *profile_path, enum pdb_value_state flag) { if (!sampass) return False; if (profile_path) { DEBUG(10, ("pdb_set_profile_path: setting profile path %s, was %s\n", profile_path, - (sampass->private_u.profile_path)?(sampass->private_u.profile_path):"NULL")); + (sampass->profile_path)?(sampass->profile_path):"NULL")); - sampass->private_u.profile_path = talloc_strdup(sampass->mem_ctx, profile_path); + sampass->profile_path = talloc_strdup(sampass, profile_path); - if (!sampass->private_u.profile_path) { + if (!sampass->profile_path) { DEBUG(0, ("pdb_set_profile_path: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.profile_path = PDB_NOT_QUITE_NULL; + sampass->profile_path = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_PROFILE, flag); @@ -769,24 +835,24 @@ BOOL pdb_set_profile_path (SAM_ACCOUNT *sampass, const char *profile_path, enum Set the user's directory drive. ********************************************************************/ -BOOL pdb_set_dir_drive (SAM_ACCOUNT *sampass, const char *dir_drive, enum pdb_value_state flag) +BOOL pdb_set_dir_drive (struct samu *sampass, const char *dir_drive, enum pdb_value_state flag) { if (!sampass) return False; if (dir_drive) { DEBUG(10, ("pdb_set_dir_drive: setting dir drive %s, was %s\n", dir_drive, - (sampass->private_u.dir_drive)?(sampass->private_u.dir_drive):"NULL")); + (sampass->dir_drive)?(sampass->dir_drive):"NULL")); - sampass->private_u.dir_drive = talloc_strdup(sampass->mem_ctx, dir_drive); + sampass->dir_drive = talloc_strdup(sampass, dir_drive); - if (!sampass->private_u.dir_drive) { + if (!sampass->dir_drive) { DEBUG(0, ("pdb_set_dir_drive: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.dir_drive = PDB_NOT_QUITE_NULL; + sampass->dir_drive = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_DRIVE, flag); @@ -796,76 +862,48 @@ BOOL pdb_set_dir_drive (SAM_ACCOUNT *sampass, const char *dir_drive, enum pdb_va Set the user's home directory. ********************************************************************/ -BOOL pdb_set_homedir (SAM_ACCOUNT *sampass, const char *home_dir, enum pdb_value_state flag) +BOOL pdb_set_homedir (struct samu *sampass, const char *home_dir, enum pdb_value_state flag) { if (!sampass) return False; if (home_dir) { DEBUG(10, ("pdb_set_homedir: setting home dir %s, was %s\n", home_dir, - (sampass->private_u.home_dir)?(sampass->private_u.home_dir):"NULL")); + (sampass->home_dir)?(sampass->home_dir):"NULL")); - sampass->private_u.home_dir = talloc_strdup(sampass->mem_ctx, home_dir); + sampass->home_dir = talloc_strdup(sampass, home_dir); - if (!sampass->private_u.home_dir) { + if (!sampass->home_dir) { DEBUG(0, ("pdb_set_home_dir: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.home_dir = PDB_NOT_QUITE_NULL; + sampass->home_dir = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_SMBHOME, flag); } /********************************************************************* - Set the user's unix home directory. - ********************************************************************/ - -BOOL pdb_set_unix_homedir (SAM_ACCOUNT *sampass, const char *unix_home_dir, enum pdb_value_state flag) -{ - if (!sampass) - return False; - - if (unix_home_dir) { - DEBUG(10, ("pdb_set_unix_homedir: setting home dir %s, was %s\n", unix_home_dir, - (sampass->private_u.unix_home_dir)?(sampass->private_u.unix_home_dir):"NULL")); - - sampass->private_u.unix_home_dir = talloc_strdup(sampass->mem_ctx, - unix_home_dir); - - if (!sampass->private_u.unix_home_dir) { - DEBUG(0, ("pdb_set_unix_home_dir: talloc_strdup() failed!\n")); - return False; - } - - } else { - sampass->private_u.unix_home_dir = PDB_NOT_QUITE_NULL; - } - - return pdb_set_init_flags(sampass, PDB_UNIXHOMEDIR, flag); -} - -/********************************************************************* Set the user's account description. ********************************************************************/ -BOOL pdb_set_acct_desc (SAM_ACCOUNT *sampass, const char *acct_desc, enum pdb_value_state flag) +BOOL pdb_set_acct_desc (struct samu *sampass, const char *acct_desc, enum pdb_value_state flag) { if (!sampass) return False; if (acct_desc) { - sampass->private_u.acct_desc = talloc_strdup(sampass->mem_ctx, acct_desc); + sampass->acct_desc = talloc_strdup(sampass, acct_desc); - if (!sampass->private_u.acct_desc) { + if (!sampass->acct_desc) { DEBUG(0, ("pdb_set_acct_desc: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.acct_desc = PDB_NOT_QUITE_NULL; + sampass->acct_desc = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_ACCTDESC, flag); @@ -875,24 +913,24 @@ BOOL pdb_set_acct_desc (SAM_ACCOUNT *sampass, const char *acct_desc, enum pdb_va Set the user's workstation allowed list. ********************************************************************/ -BOOL pdb_set_workstations (SAM_ACCOUNT *sampass, const char *workstations, enum pdb_value_state flag) +BOOL pdb_set_workstations (struct samu *sampass, const char *workstations, enum pdb_value_state flag) { if (!sampass) return False; if (workstations) { DEBUG(10, ("pdb_set_workstations: setting workstations %s, was %s\n", workstations, - (sampass->private_u.workstations)?(sampass->private_u.workstations):"NULL")); + (sampass->workstations)?(sampass->workstations):"NULL")); - sampass->private_u.workstations = talloc_strdup(sampass->mem_ctx, workstations); + sampass->workstations = talloc_strdup(sampass, workstations); - if (!sampass->private_u.workstations) { + if (!sampass->workstations) { DEBUG(0, ("pdb_set_workstations: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.workstations = PDB_NOT_QUITE_NULL; + sampass->workstations = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_WORKSTATIONS, flag); @@ -902,21 +940,21 @@ BOOL pdb_set_workstations (SAM_ACCOUNT *sampass, const char *workstations, enum Set the user's 'unknown_str', whatever the heck this actually is... ********************************************************************/ -BOOL pdb_set_unknown_str (SAM_ACCOUNT *sampass, const char *unknown_str, enum pdb_value_state flag) +BOOL pdb_set_unknown_str (struct samu *sampass, const char *unknown_str, enum pdb_value_state flag) { if (!sampass) return False; if (unknown_str) { - sampass->private_u.unknown_str = talloc_strdup(sampass->mem_ctx, unknown_str); + sampass->unknown_str = talloc_strdup(sampass, unknown_str); - if (!sampass->private_u.unknown_str) { + if (!sampass->unknown_str) { DEBUG(0, ("pdb_set_unknown_str: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.unknown_str = PDB_NOT_QUITE_NULL; + sampass->unknown_str = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_UNKNOWNSTR, flag); @@ -926,21 +964,21 @@ BOOL pdb_set_unknown_str (SAM_ACCOUNT *sampass, const char *unknown_str, enum pd Set the user's dial string. ********************************************************************/ -BOOL pdb_set_munged_dial (SAM_ACCOUNT *sampass, const char *munged_dial, enum pdb_value_state flag) +BOOL pdb_set_munged_dial (struct samu *sampass, const char *munged_dial, enum pdb_value_state flag) { if (!sampass) return False; if (munged_dial) { - sampass->private_u.munged_dial = talloc_strdup(sampass->mem_ctx, munged_dial); + sampass->munged_dial = talloc_strdup(sampass, munged_dial); - if (!sampass->private_u.munged_dial) { + if (!sampass->munged_dial) { DEBUG(0, ("pdb_set_munged_dial: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.munged_dial = PDB_NOT_QUITE_NULL; + sampass->munged_dial = PDB_NOT_QUITE_NULL; } return pdb_set_init_flags(sampass, PDB_MUNGEDDIAL, flag); @@ -950,17 +988,18 @@ BOOL pdb_set_munged_dial (SAM_ACCOUNT *sampass, const char *munged_dial, enum pd Set the user's NT hash. ********************************************************************/ -BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[NT_HASH_LEN], enum pdb_value_state flag) +BOOL pdb_set_nt_passwd (struct samu *sampass, const uint8 pwd[NT_HASH_LEN], enum pdb_value_state flag) { if (!sampass) return False; - data_blob_clear_free(&sampass->private_u.nt_pw); + data_blob_clear_free(&sampass->nt_pw); if (pwd) { - sampass->private_u.nt_pw = data_blob(pwd, NT_HASH_LEN); + sampass->nt_pw = + data_blob_talloc(sampass, pwd, NT_HASH_LEN); } else { - sampass->private_u.nt_pw = data_blob(NULL, 0); + sampass->nt_pw = data_blob(NULL, 0); } return pdb_set_init_flags(sampass, PDB_NTPASSWD, flag); @@ -970,17 +1009,18 @@ BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[NT_HASH_LEN], enum Set the user's LM hash. ********************************************************************/ -BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[LM_HASH_LEN], enum pdb_value_state flag) +BOOL pdb_set_lanman_passwd (struct samu *sampass, const uint8 pwd[LM_HASH_LEN], enum pdb_value_state flag) { if (!sampass) return False; - data_blob_clear_free(&sampass->private_u.lm_pw); + data_blob_clear_free(&sampass->lm_pw); if (pwd) { - sampass->private_u.lm_pw = data_blob(pwd, LM_HASH_LEN); + sampass->lm_pw = + data_blob_talloc(sampass, pwd, LM_HASH_LEN); } else { - sampass->private_u.lm_pw = data_blob(NULL, 0); + sampass->lm_pw = data_blob(NULL, 0); } return pdb_set_init_flags(sampass, PDB_LMPASSWD, flag); @@ -993,20 +1033,20 @@ BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[LM_HASH_LEN], in pwd. ********************************************************************/ -BOOL pdb_set_pw_history (SAM_ACCOUNT *sampass, const uint8 *pwd, uint32 historyLen, enum pdb_value_state flag) +BOOL pdb_set_pw_history (struct samu *sampass, const uint8 *pwd, uint32 historyLen, enum pdb_value_state flag) { if (!sampass) return False; if (historyLen && pwd){ - sampass->private_u.nt_pw_his = data_blob_talloc(sampass->mem_ctx, + sampass->nt_pw_his = data_blob_talloc(sampass, pwd, historyLen*PW_HISTORY_ENTRY_LEN); - if (!sampass->private_u.nt_pw_his.length) { + if (!sampass->nt_pw_his.length) { DEBUG(0, ("pdb_set_pw_history: data_blob_talloc() failed!\n")); return False; } } else { - sampass->private_u.nt_pw_his = data_blob_talloc(sampass->mem_ctx, NULL, 0); + sampass->nt_pw_his = data_blob_talloc(sampass, NULL, 0); } return pdb_set_init_flags(sampass, PDB_PWHISTORY, flag); @@ -1017,75 +1057,75 @@ BOOL pdb_set_pw_history (SAM_ACCOUNT *sampass, const uint8 *pwd, uint32 historyL below) ********************************************************************/ -BOOL pdb_set_plaintext_pw_only (SAM_ACCOUNT *sampass, const char *password, enum pdb_value_state flag) +BOOL pdb_set_plaintext_pw_only (struct samu *sampass, const char *password, enum pdb_value_state flag) { if (!sampass) return False; if (password) { - if (sampass->private_u.plaintext_pw!=NULL) - memset(sampass->private_u.plaintext_pw,'\0',strlen(sampass->private_u.plaintext_pw)+1); + if (sampass->plaintext_pw!=NULL) + memset(sampass->plaintext_pw,'\0',strlen(sampass->plaintext_pw)+1); - sampass->private_u.plaintext_pw = talloc_strdup(sampass->mem_ctx, password); + sampass->plaintext_pw = talloc_strdup(sampass, password); - if (!sampass->private_u.plaintext_pw) { + if (!sampass->plaintext_pw) { DEBUG(0, ("pdb_set_unknown_str: talloc_strdup() failed!\n")); return False; } } else { - sampass->private_u.plaintext_pw = NULL; + sampass->plaintext_pw = NULL; } return pdb_set_init_flags(sampass, PDB_PLAINTEXT_PW, flag); } -BOOL pdb_set_bad_password_count(SAM_ACCOUNT *sampass, uint16 bad_password_count, enum pdb_value_state flag) +BOOL pdb_set_bad_password_count(struct samu *sampass, uint16 bad_password_count, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.bad_password_count = bad_password_count; + sampass->bad_password_count = bad_password_count; return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_COUNT, flag); } -BOOL pdb_set_logon_count(SAM_ACCOUNT *sampass, uint16 logon_count, enum pdb_value_state flag) +BOOL pdb_set_logon_count(struct samu *sampass, uint16 logon_count, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.logon_count = logon_count; + sampass->logon_count = logon_count; return pdb_set_init_flags(sampass, PDB_LOGON_COUNT, flag); } -BOOL pdb_set_unknown_6 (SAM_ACCOUNT *sampass, uint32 unkn, enum pdb_value_state flag) +BOOL pdb_set_unknown_6 (struct samu *sampass, uint32 unkn, enum pdb_value_state flag) { if (!sampass) return False; - sampass->private_u.unknown_6 = unkn; + sampass->unknown_6 = unkn; return pdb_set_init_flags(sampass, PDB_UNKNOWN6, flag); } -BOOL pdb_set_hours (SAM_ACCOUNT *sampass, const uint8 *hours, enum pdb_value_state flag) +BOOL pdb_set_hours (struct samu *sampass, const uint8 *hours, enum pdb_value_state flag) { if (!sampass) return False; if (!hours) { - memset ((char *)sampass->private_u.hours, 0, MAX_HOURS_LEN); + memset ((char *)sampass->hours, 0, MAX_HOURS_LEN); return True; } - memcpy (sampass->private_u.hours, hours, MAX_HOURS_LEN); + memcpy (sampass->hours, hours, MAX_HOURS_LEN); return pdb_set_init_flags(sampass, PDB_HOURS, flag); } -BOOL pdb_set_backend_private_data (SAM_ACCOUNT *sampass, void *private_data, +BOOL pdb_set_backend_private_data (struct samu *sampass, void *private_data, void (*free_fn)(void **), const struct pdb_methods *my_methods, enum pdb_value_state flag) @@ -1093,13 +1133,15 @@ 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->backend_private_data && + sampass->backend_private_data_free_fn) { + sampass->backend_private_data_free_fn( + &sampass->backend_private_data); } - sampass->private_u.backend_private_data = private_data; - sampass->private_u.backend_private_data_free_fn = free_fn; - sampass->private_u.backend_private_methods = my_methods; + sampass->backend_private_data = private_data; + sampass->backend_private_data_free_fn = free_fn; + sampass->backend_private_methods = my_methods; return pdb_set_init_flags(sampass, PDB_BACKEND_PRIVATE_DATA, flag); } @@ -1112,7 +1154,7 @@ BOOL pdb_set_backend_private_data (SAM_ACCOUNT *sampass, void *private_data, password change. ********************************************************************/ -BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass) +BOOL pdb_set_pass_changed_now (struct samu *sampass) { uint32 expire; uint32 min_age; @@ -1152,7 +1194,7 @@ BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass) Also sets the last change time to NOW. ********************************************************************/ -BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) +BOOL pdb_set_plaintext_passwd (struct samu *sampass, const char *plaintext) { uchar new_lanman_p16[LM_HASH_LEN]; uchar new_nt_p16[NT_HASH_LEN]; @@ -1194,11 +1236,11 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) uint32 current_history_len; /* We need to make sure we don't have a race condition here - the account policy history length can change between when the pw_history - was first loaded into the SAM_ACCOUNT struct and now.... JRA. */ + was first loaded into the struct samu struct and now.... JRA. */ pwhistory = (uchar *)pdb_get_pw_history(sampass, ¤t_history_len); if (current_history_len != pwHistLen) { - /* After closing and reopening SAM_ACCOUNT the history + /* After closing and reopening struct samu the history values will sync up. We can't do this here. */ /* current_history_len > pwHistLen is not a problem - we @@ -1206,8 +1248,12 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) if (current_history_len < pwHistLen) { /* Ensure we have space for the needed history. */ - uchar *new_history = TALLOC(sampass->mem_ctx, + uchar *new_history = TALLOC(sampass, pwHistLen*PW_HISTORY_ENTRY_LEN); + if (!new_history) { + return False; + } + /* And copy it into the new buffer. */ if (current_history_len) { memcpy(new_history, pwhistory, @@ -1247,7 +1293,7 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) } /* check for any PDB_SET/CHANGED field and fill the appropriate mask bit */ -uint32 pdb_build_fields_present (SAM_ACCOUNT *sampass) +uint32 pdb_build_fields_present (struct samu *sampass) { /* value set to all for testing */ return 0x00ffffff; diff --git a/source/passdb/pdb_guest.c b/source/passdb/pdb_guest.c deleted file mode 100644 index 510cf6abc8b..00000000000 --- a/source/passdb/pdb_guest.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 'Guest' password backend for samba - * Copyright (C) Jelmer Vernooij 2002 - * Copyright (C) Andrew Bartlett 2003 - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 675 - * Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "includes.h" - -/****************************************************************** - Lookup a name in the SAM database - ******************************************************************/ - -static NTSTATUS guestsam_getsampwnam (struct pdb_methods *methods, SAM_ACCOUNT *sam_account, const char *sname) -{ - const char *guest_account = lp_guestaccount(); - - if (!sam_account || !sname) { - DEBUG(0,("invalid name specified")); - return NT_STATUS_UNSUCCESSFUL; - } - - if (!(guest_account && *guest_account)) { - DEBUG(1, ("NULL guest account!?!?\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - if (!methods) { - DEBUG(0,("invalid methods\n")); - return NT_STATUS_UNSUCCESSFUL; - } - if (!strequal(guest_account, sname)) { - return NT_STATUS_NO_SUCH_USER; - } - - pdb_fill_default_sam(sam_account); - - if (!pdb_set_username(sam_account, guest_account, PDB_SET)) - return NT_STATUS_UNSUCCESSFUL; - - if (!pdb_set_fullname(sam_account, guest_account, PDB_SET)) - return NT_STATUS_UNSUCCESSFUL; - - if (!pdb_set_domain(sam_account, get_global_sam_name(), PDB_DEFAULT)) - return NT_STATUS_UNSUCCESSFUL; - - if (!pdb_set_acct_ctrl(sam_account, ACB_NORMAL, PDB_DEFAULT)) - return NT_STATUS_UNSUCCESSFUL; - - if (!pdb_set_user_sid_from_rid(sam_account, DOMAIN_USER_RID_GUEST, PDB_SET)) - return NT_STATUS_UNSUCCESSFUL; - - if (!pdb_set_group_sid_from_rid(sam_account, DOMAIN_GROUP_RID_GUESTS, PDB_DEFAULT)) - return NT_STATUS_UNSUCCESSFUL; - - return NT_STATUS_OK; -} - - -/*************************************************************************** - Search by rid - **************************************************************************/ - -static NTSTATUS guestsam_getsampwrid (struct pdb_methods *methods, - SAM_ACCOUNT *sam_account, uint32 rid) -{ - if (rid != DOMAIN_USER_RID_GUEST) { - return NT_STATUS_NO_SUCH_USER; - } - - if (!sam_account) { - return NT_STATUS_INVALID_PARAMETER; - } - - return guestsam_getsampwnam (methods, sam_account, lp_guestaccount()); -} - -static NTSTATUS guestsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid) -{ - uint32 rid; - if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) - return NT_STATUS_NO_SUCH_USER; - - return guestsam_getsampwrid(my_methods, user, rid); -} - - -/*************************************************************************** - Updates a SAM_ACCOUNT - - This isn't a particulary practical option for pdb_guest. We certainly don't - want to twidde the filesystem, so what should we do? - - Current plan is to transparently add the account. It should appear - as if the pdb_guest version was modified, but its actually stored somehwere. - ****************************************************************************/ - -static NTSTATUS guestsam_update_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *newpwd) -{ -#if 1 /* JERRY */ - - /* apparently thr build farm relies upon this heavior :-( */ - - return methods->parent->pdb_add_sam_account(methods->parent, newpwd); -#else - /* I don't think we should allow any modification of - the guest account as SID will could messed up with - the smbpasswd backend --jerry */ - - return NT_STATUS_NOT_IMPLEMENTED; -#endif -} - -NTSTATUS pdb_init_guestsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) -{ - NTSTATUS nt_status; - - if (!pdb_context) { - DEBUG(0, ("invalid pdb_context specified\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { - return nt_status; - } - - (*pdb_method)->name = "guestsam"; - - (*pdb_method)->getsampwnam = guestsam_getsampwnam; - (*pdb_method)->getsampwsid = guestsam_getsampwsid; - (*pdb_method)->update_sam_account = guestsam_update_sam_account; - - /* we should do no group mapping here */ - (*pdb_method)->getgrsid = pdb_nop_getgrsid; - (*pdb_method)->getgrgid = pdb_nop_getgrgid; - (*pdb_method)->getgrnam = pdb_nop_getgrnam; - (*pdb_method)->add_group_mapping_entry = pdb_nop_add_group_mapping_entry; - (*pdb_method)->update_group_mapping_entry = pdb_nop_update_group_mapping_entry; - (*pdb_method)->delete_group_mapping_entry = pdb_nop_delete_group_mapping_entry; - (*pdb_method)->enum_group_mapping = pdb_nop_enum_group_mapping; - - - /* There's not very much to initialise here */ - return NT_STATUS_OK; -} - -NTSTATUS pdb_guest_init(void) -{ - return smb_register_passdb(PASSDB_INTERFACE_VERSION, "guest", pdb_init_guestsam); -} - diff --git a/source/passdb/pdb_interface.c b/source/passdb/pdb_interface.c index 875e264bf01..b3522e33a7f 100644 --- a/source/passdb/pdb_interface.c +++ b/source/passdb/pdb_interface.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Bartlett 2002 Copyright (C) Jelmer Vernooij 2002 Copyright (C) Simo Sorce 2003 + Copyright (C) Volker Lendecke 2006 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 @@ -25,6 +26,10 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_PASSDB +/* Cache of latest SAM lookup query */ + +static struct samu *csamuser = NULL; + static struct pdb_init_function_entry *backends = NULL; static void lazy_initialize_passdb(void) @@ -35,8 +40,10 @@ static void lazy_initialize_passdb(void) initialized = True; } -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 @@ -46,7 +53,7 @@ static struct pdb_init_function_entry *pdb_find_backend_entry(const char *name); time, such LDAP with a missing attribute would produce. ********************************************************************/ -static void pdb_force_pw_initialization(SAM_ACCOUNT *pass) +static void pdb_force_pw_initialization(struct samu *pass) { const uint8 *lm_pwd, *nt_pwd; @@ -108,7 +115,7 @@ NTSTATUS smb_register_passdb(int version, const char *name, pdb_init_function in return NT_STATUS_OK; } -static struct pdb_init_function_entry *pdb_find_backend_entry(const char *name) +struct pdb_init_function_entry *pdb_find_backend_entry(const char *name) { struct pdb_init_function_entry *entry = backends; @@ -120,1334 +127,1164 @@ static struct pdb_init_function_entry *pdb_find_backend_entry(const char *name) return NULL; } -static NTSTATUS context_setsampwent(struct pdb_context *context, BOOL update, uint16 acb_mask) +/****************************************************************** + Make a pdb_methods from scratch + *******************************************************************/ + +NTSTATUS make_pdb_method_name(struct pdb_methods **methods, const char *selected) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + char *module_name = smb_xstrdup(selected); + char *module_location = NULL, *p; + struct pdb_init_function_entry *entry; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - if (!context) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } + lazy_initialize_passdb(); - context->pwent_methods = context->pdb_methods; + p = strchr(module_name, ':'); - if (!context->pwent_methods) { - /* No passdbs at all */ - return ret; + if (p) { + *p = 0; + module_location = p+1; + trim_char(module_location, ' ', ' '); } - while (NT_STATUS_IS_ERR(ret = context->pwent_methods->setsampwent(context->pwent_methods, update, acb_mask))) { - context->pwent_methods = context->pwent_methods->next; - if (context->pwent_methods == NULL) - return NT_STATUS_UNSUCCESSFUL; - } - return ret; -} + trim_char(module_name, ' ', ' '); -static void context_endsampwent(struct pdb_context *context) -{ - if ((!context)){ - DEBUG(0, ("invalid pdb_context specified!\n")); - return; - } - if (context->pwent_methods && context->pwent_methods->endsampwent) - context->pwent_methods->endsampwent(context->pwent_methods); + DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected, module_name)); - /* So we won't get strange data when calling getsampwent now */ - context->pwent_methods = NULL; -} + entry = pdb_find_backend_entry(module_name); + + /* Try to find a module that contains this module */ + if (!entry) { + DEBUG(2,("No builtin backend found, trying to load plugin\n")); + if(NT_STATUS_IS_OK(smb_probe_module("pdb", module_name)) && !(entry = pdb_find_backend_entry(module_name))) { + DEBUG(0,("Plugin is available, but doesn't register passdb backend %s\n", module_name)); + SAFE_FREE(module_name); + return NT_STATUS_UNSUCCESSFUL; + } + } + + /* No such backend found */ + if(!entry) { + DEBUG(0,("No builtin nor plugin backend for %s found\n", module_name)); + SAFE_FREE(module_name); + return NT_STATUS_INVALID_PARAMETER; + } -static NTSTATUS context_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + DEBUG(5,("Found pdb backend %s\n", module_name)); - if ((!context) || (!context->pwent_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !NT_STATUS_IS_OK( nt_status = entry->init(methods, module_location) ) ) { + DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", + selected, nt_errstr(nt_status))); + SAFE_FREE(module_name); + return nt_status; } - /* Loop until we find something useful */ - while (NT_STATUS_IS_ERR(ret = context->pwent_methods->getsampwent(context->pwent_methods, user))) { - context->pwent_methods->endsampwent(context->pwent_methods); + SAFE_FREE(module_name); - context->pwent_methods = context->pwent_methods->next; + DEBUG(5,("pdb backend %s has a valid init\n", selected)); - /* All methods are checked now. There are no more entries */ - if (context->pwent_methods == NULL) - return ret; - - context->pwent_methods->setsampwent(context->pwent_methods, False, 0); - } - user->methods = context->pwent_methods; - pdb_force_pw_initialization(user); - return ret; + return nt_status; } -static NTSTATUS context_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username) +/****************************************************************** + Return an already initialised pdn_methods structure +*******************************************************************/ + +static struct pdb_methods *pdb_get_methods_reload( BOOL reload ) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + static struct pdb_methods *pdb = NULL; - struct pdb_methods *curmethods; - if ((!context)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( pdb && reload ) { + pdb->free_private_data( &(pdb->private_data) ); + if ( !NT_STATUS_IS_OK( make_pdb_method_name( &pdb, lp_passdb_backend() ) ) ) { + return NULL; + } } - curmethods = context->pdb_methods; - while (curmethods){ - if (NT_STATUS_IS_OK(ret = curmethods->getsampwnam(curmethods, sam_acct, username))) { - pdb_force_pw_initialization(sam_acct); - sam_acct->methods = curmethods; - return ret; + + if ( !pdb ) { + if ( !NT_STATUS_IS_OK( make_pdb_method_name( &pdb, lp_passdb_backend() ) ) ) { + return NULL; } - curmethods = curmethods->next; } - return ret; + return pdb; } -static NTSTATUS context_getsampwsid(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const DOM_SID *sid) +static struct pdb_methods *pdb_get_methods(void) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + return pdb_get_methods_reload(False); +} - struct pdb_methods *curmethods; - if ((!context)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } - - curmethods = context->pdb_methods; +/****************************************************************** + Backward compatibility functions for the original passdb interface +*******************************************************************/ - while (curmethods){ - if (NT_STATUS_IS_OK(ret = curmethods->getsampwsid(curmethods, sam_acct, sid))) { - pdb_force_pw_initialization(sam_acct); - sam_acct->methods = curmethods; - return ret; - } - curmethods = curmethods->next; +BOOL pdb_setsampwent(BOOL update, uint16 acb_mask) +{ + struct pdb_methods *pdb = pdb_get_methods(); + + if ( !pdb ) { + return False; } - return ret; + return NT_STATUS_IS_OK(pdb->setsampwent(pdb, update, acb_mask)); } -static NTSTATUS context_add_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct) +void pdb_endsampwent(void) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - const uint8 *lm_pw, *nt_pw; - uint16 acb_flags; - - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } + struct pdb_methods *pdb = pdb_get_methods(); - /* disable acccounts with no passwords (that has not - been allowed by the ACB_PWNOTREQ bit */ - - lm_pw = pdb_get_lanman_passwd( sam_acct ); - nt_pw = pdb_get_nt_passwd( sam_acct ); - acb_flags = pdb_get_acct_ctrl( sam_acct ); - if ( !lm_pw && !nt_pw && !(acb_flags&ACB_PWNOTREQ) ) { - acb_flags |= ACB_DISABLED; - pdb_set_acct_ctrl( sam_acct, acb_flags, PDB_CHANGED ); + if ( !pdb ) { + return; } - - /** @todo This is where a 're-read on add' should be done */ - /* We now add a new account to the first database listed. - * Should we? */ - return context->pdb_methods->add_sam_account(context->pdb_methods, sam_acct); + pdb->endsampwent(pdb); } -static NTSTATUS context_update_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct) +BOOL pdb_getsampwent(struct samu *user) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - const uint8 *lm_pw, *nt_pw; - uint16 acb_flags; + struct pdb_methods *pdb = pdb_get_methods(); - if (!context) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return False; } - if (!sam_acct || !sam_acct->methods){ - DEBUG(0, ("invalid sam_acct specified\n")); - return ret; + if ( !NT_STATUS_IS_OK(pdb->getsampwent(pdb, user) ) ) { + return False; } - /* disable acccounts with no passwords (that has not - been allowed by the ACB_PWNOTREQ bit */ - - lm_pw = pdb_get_lanman_passwd( sam_acct ); - nt_pw = pdb_get_nt_passwd( sam_acct ); - acb_flags = pdb_get_acct_ctrl( sam_acct ); - if ( !lm_pw && !nt_pw && !(acb_flags&ACB_PWNOTREQ) ) { - acb_flags |= ACB_DISABLED; - pdb_set_acct_ctrl( sam_acct, acb_flags, PDB_CHANGED ); - } - - /** @todo This is where a 're-read on update' should be done */ + pdb_force_pw_initialization( user ); - return sam_acct->methods->update_sam_account(sam_acct->methods, sam_acct); + return True; } -static NTSTATUS context_delete_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct) +BOOL pdb_getsampwnam(struct samu *sam_acct, const char *username) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - struct pdb_methods *pdb_selected; - if (!context) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return False; } - if (!sam_acct->methods){ - pdb_selected = context->pdb_methods; - /* There's no passdb backend specified for this account. - * Try to delete it in every passdb available - * Needed to delete accounts in smbpasswd that are not - * in /etc/passwd. - */ - while (pdb_selected){ - if (NT_STATUS_IS_OK(ret = pdb_selected->delete_sam_account(pdb_selected, sam_acct))) { - return ret; - } - pdb_selected = pdb_selected->next; - } - return ret; + if (!NT_STATUS_IS_OK(pdb->getsampwnam(pdb, sam_acct, username))) { + return False; } - if (!sam_acct->methods->delete_sam_account){ - DEBUG(0,("invalid sam_acct->methods->delete_sam_account\n")); - return ret; + if ( csamuser ) { + TALLOC_FREE(csamuser); } + + pdb_force_pw_initialization( sam_acct ); - return sam_acct->methods->delete_sam_account(sam_acct->methods, sam_acct); + if ( (csamuser = samu_new( NULL )) != NULL ) { + pdb_copy_sam_account(csamuser, sam_acct); + } + + return True; } -static NTSTATUS context_rename_sam_account(struct pdb_context *context, SAM_ACCOUNT *oldname, const char *newname) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; +/********************************************************************** +**********************************************************************/ - struct pdb_methods *pdb_selected; - if (!context) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; +BOOL guest_user_info( struct samu *user ) +{ + struct passwd *pwd; + NTSTATUS result; + const char *guestname = lp_guestaccount(); + + if ( !(pwd = getpwnam_alloc( NULL, guestname ) ) ) { + DEBUG(0,("guest_user_info: Unable to locate guest account [%s]!\n", + guestname)); + return False; } + + result = samu_set_unix(user, pwd ); - if (!oldname->methods){ - pdb_selected = context->pdb_methods; - /* There's no passdb backend specified for this account. - * Try to delete it in every passdb available - * Needed to delete accounts in smbpasswd that are not - * in /etc/passwd. - */ - while (pdb_selected){ - if (NT_STATUS_IS_OK(ret = pdb_selected->rename_sam_account(pdb_selected, oldname, newname))) { - return ret; - } - pdb_selected = pdb_selected->next; - } - return ret; - } + TALLOC_FREE( pwd ); - if (!oldname->methods->rename_sam_account){ - DEBUG(0,("invalid oldname->methods->rename_sam_account\n")); - return ret; - } - - return oldname->methods->rename_sam_account(oldname->methods, oldname, newname); + return NT_STATUS_IS_OK( result ); } +/********************************************************************** +**********************************************************************/ -static NTSTATUS context_update_login_attempts(struct pdb_context *context, - SAM_ACCOUNT *sam_acct, BOOL success) +BOOL pdb_getsampwsid(struct samu *sam_acct, const DOM_SID *sid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - - if (!context) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } + struct pdb_methods *pdb; + uint32 rid; - if (!sam_acct || !sam_acct->methods){ - DEBUG(0, ("invalid sam_acct specified\n")); - return ret; + if ( !(pdb = pdb_get_methods()) ) { + return False; } - return sam_acct->methods->update_login_attempts(sam_acct->methods, sam_acct, success); -} + /* hard code the Guest RID of 501 */ -static NTSTATUS context_getgrsid(struct pdb_context *context, - GROUP_MAP *map, DOM_SID sid) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + if ( !sid_peek_check_rid( get_global_sam_sid(), sid, &rid ) ) + return False; - struct pdb_methods *curmethods; - if ((!context)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } - curmethods = context->pdb_methods; - while (curmethods){ - ret = curmethods->getgrsid(curmethods, map, sid); - if (NT_STATUS_IS_OK(ret)) { - map->methods = curmethods; - return ret; - } - curmethods = curmethods->next; + if ( rid == DOMAIN_USER_RID_GUEST ) { + DEBUG(6,("pdb_getsampwsid: Building guest account\n")); + return guest_user_info( sam_acct ); } + + /* check the cache first */ + + if ( csamuser && sid_equal(sid, pdb_get_user_sid(csamuser) ) ) + return pdb_copy_sam_account(sam_acct, csamuser); - return ret; + return NT_STATUS_IS_OK(pdb->getsampwsid(pdb, sam_acct, sid)); } -static NTSTATUS context_getgrgid(struct pdb_context *context, - GROUP_MAP *map, gid_t gid) +static NTSTATUS pdb_default_create_user(struct pdb_methods *methods, + TALLOC_CTX *tmp_ctx, const char *name, + uint32 acb_info, uint32 *rid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct samu *sam_pass; + NTSTATUS status; + struct passwd *pwd; - struct pdb_methods *curmethods; - if ((!context)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } - curmethods = context->pdb_methods; - while (curmethods){ - ret = curmethods->getgrgid(curmethods, map, gid); - if (NT_STATUS_IS_OK(ret)) { - map->methods = curmethods; - return ret; - } - curmethods = curmethods->next; + if ((sam_pass = samu_new(tmp_ctx)) == NULL) { + return NT_STATUS_NO_MEMORY; } - return ret; -} + if ( !(pwd = Get_Pwnam_alloc(tmp_ctx, name)) ) { + pstring add_script; + int add_ret; -static NTSTATUS context_getgrnam(struct pdb_context *context, - GROUP_MAP *map, const char *name) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + if ((acb_info & ACB_NORMAL) && name[strlen(name)-1] != '$') { + pstrcpy(add_script, lp_adduser_script()); + } else { + pstrcpy(add_script, lp_addmachine_script()); + } - struct pdb_methods *curmethods; - if ((!context)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } - curmethods = context->pdb_methods; - while (curmethods){ - ret = curmethods->getgrnam(curmethods, map, name); - if (NT_STATUS_IS_OK(ret)) { - map->methods = curmethods; - return ret; + if (add_script[0] == '\0') { + DEBUG(3, ("Could not find user %s and no add script " + "defined\n", name)); + return NT_STATUS_NO_SUCH_USER; } - curmethods = curmethods->next; + + all_string_sub(add_script, "%u", name, sizeof(add_script)); + add_ret = smbrun(add_script,NULL); + DEBUG(add_ret ? 0 : 3, ("_samr_create_user: Running the command `%s' gave %d\n", + add_script, add_ret)); + flush_pwnam_cache(); + + pwd = Get_Pwnam_alloc(tmp_ctx, name); } - return ret; -} + /* we have a valid SID coming out of this call */ -static NTSTATUS context_add_group_mapping_entry(struct pdb_context *context, - GROUP_MAP *map) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + status = samu_alloc_rid_unix( sam_pass, pwd ); + + TALLOC_FREE( pwd ); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("pdb_default_create_user: failed to create a new user structure: %s\n", nt_errstr(status))); + return status; } - return context->pdb_methods->add_group_mapping_entry(context->pdb_methods, - map); -} + if (!sid_peek_check_rid(get_global_sam_sid(), + pdb_get_user_sid(sam_pass), rid)) { + DEBUG(0, ("Could not get RID of fresh user\n")); + return NT_STATUS_INTERNAL_ERROR; + } -static NTSTATUS context_update_group_mapping_entry(struct pdb_context *context, - GROUP_MAP *map) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + /* Disable the account on creation, it does not have a reasonable password yet. */ - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } + acb_info |= ACB_DISABLED; - return context-> - pdb_methods->update_group_mapping_entry(context->pdb_methods, map); -} + pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED); -static NTSTATUS context_delete_group_mapping_entry(struct pdb_context *context, - DOM_SID sid) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + status = pdb_add_sam_account(sam_pass); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } + TALLOC_FREE(sam_pass); - return context-> - pdb_methods->delete_group_mapping_entry(context->pdb_methods, sid); + return status; } -static NTSTATUS context_enum_group_mapping(struct pdb_context *context, - enum SID_NAME_USE sid_name_use, - GROUP_MAP **pp_rmap, size_t *p_num_entries, - BOOL unix_only) +NTSTATUS pdb_create_user(TALLOC_CTX *mem_ctx, const char *name, uint32 flags, + uint32 *rid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return context->pdb_methods->enum_group_mapping(context->pdb_methods, - sid_name_use, pp_rmap, - p_num_entries, unix_only); + return pdb->create_user(pdb, mem_ctx, name, flags, rid); } -static NTSTATUS context_enum_group_members(struct pdb_context *context, - TALLOC_CTX *mem_ctx, - const DOM_SID *group, - uint32 **pp_member_rids, - size_t *p_num_members) +/**************************************************************************** + Delete a UNIX user on demand. +****************************************************************************/ + +static int smb_delete_user(const char *unix_user) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + pstring del_script; + int ret; + + /* safety check */ - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( strequal( unix_user, "root" ) ) { + DEBUG(0,("smb_delete_user: Refusing to delete local system root account!\n")); + return -1; } - return context->pdb_methods->enum_group_members(context->pdb_methods, - mem_ctx, group, - pp_member_rids, - p_num_members); + pstrcpy(del_script, lp_deluser_script()); + if (! *del_script) + return -1; + all_string_sub(del_script, "%u", unix_user, sizeof(del_script)); + ret = smbrun(del_script,NULL); + flush_pwnam_cache(); + DEBUG(ret ? 0 : 3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); + + return ret; } -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, - size_t *p_num_groups) +static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + struct samu *sam_acct) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + NTSTATUS status; - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + status = pdb_delete_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + return status; } - return context->pdb_methods-> - enum_group_memberships(context->pdb_methods, username, - primary_gid, pp_sids, pp_gids, p_num_groups); + /* + * Now delete the unix side .... + * note: we don't check if the delete really happened as the script is + * not necessary present and maybe the sysadmin doesn't want to delete + * the unix side + */ + smb_delete_user( pdb_get_username(sam_acct) ); + + return status; } -static NTSTATUS context_find_alias(struct pdb_context *context, - const char *name, DOM_SID *sid) +NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, struct samu *sam_acct) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); + uid_t uid = -1; - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return context->pdb_methods->find_alias(context->pdb_methods, - name, sid); -} + /* sanity check to make sure we don't delete root */ -static NTSTATUS context_create_alias(struct pdb_context *context, - const char *name, uint32 *rid) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + if ( !sid_to_uid( pdb_get_user_sid(sam_acct), &uid ) ) { + return NT_STATUS_NO_SUCH_USER; + } - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( uid == 0 ) { + return NT_STATUS_ACCESS_DENIED; } - return context->pdb_methods->create_alias(context->pdb_methods, - name, rid); + return pdb->delete_user(pdb, mem_ctx, sam_acct); } -static NTSTATUS context_delete_alias(struct pdb_context *context, - const DOM_SID *sid) +NTSTATUS pdb_add_sam_account(struct samu *sam_acct) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - - return context->pdb_methods->delete_alias(context->pdb_methods, sid); + + return pdb->add_sam_account(pdb, sam_acct); } -static NTSTATUS context_get_aliasinfo(struct pdb_context *context, - const DOM_SID *sid, - struct acct_info *info) +NTSTATUS pdb_update_sam_account(struct samu *sam_acct) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if (csamuser != NULL) { + TALLOC_FREE(csamuser); + csamuser = NULL; } - return context->pdb_methods->get_aliasinfo(context->pdb_methods, - sid, info); + return pdb->update_sam_account(pdb, sam_acct); } -static NTSTATUS context_set_aliasinfo(struct pdb_context *context, - const DOM_SID *sid, - struct acct_info *info) +NTSTATUS pdb_delete_sam_account(struct samu *sam_acct) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + if (csamuser != NULL) { + TALLOC_FREE(csamuser); + csamuser = NULL; } - return context->pdb_methods->set_aliasinfo(context->pdb_methods, - sid, info); + return pdb->delete_sam_account(pdb, sam_acct); } -static NTSTATUS context_add_aliasmem(struct pdb_context *context, - const DOM_SID *alias, - const DOM_SID *member) +NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); + uid_t uid; - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return NT_STATUS_NOT_IMPLEMENTED; } - return context->pdb_methods->add_aliasmem(context->pdb_methods, - alias, member); -} - -static NTSTATUS context_del_aliasmem(struct pdb_context *context, - const DOM_SID *alias, - const DOM_SID *member) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if (csamuser != NULL) { + TALLOC_FREE(csamuser); + csamuser = NULL; } - return context->pdb_methods->del_aliasmem(context->pdb_methods, - alias, member); -} - -static NTSTATUS context_enum_aliasmem(struct pdb_context *context, - const DOM_SID *alias, DOM_SID **pp_members, - size_t *p_num) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + /* sanity check to make sure we don't rename root */ - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !sid_to_uid( pdb_get_user_sid(oldname), &uid ) ) { + return NT_STATUS_NO_SUCH_USER; } - return context->pdb_methods->enum_aliasmem(context->pdb_methods, - alias, pp_members, p_num); -} - -static NTSTATUS context_enum_alias_memberships(struct pdb_context *context, - 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 ret = NT_STATUS_UNSUCCESSFUL; - - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( uid == 0 ) { + return NT_STATUS_ACCESS_DENIED; } - return context->pdb_methods-> - enum_alias_memberships(context->pdb_methods, mem_ctx, - domain_sid, members, num_members, - pp_alias_rids, p_num_alias_rids); + return pdb->rename_sam_account(pdb, oldname, newname); } -static NTSTATUS context_lookup_rids(struct pdb_context *context, - const DOM_SID *domain_sid, - size_t num_rids, - uint32 *rids, - const char **pp_names, - uint32 *pp_attrs) +NTSTATUS pdb_update_login_attempts(struct samu *sam_acct, BOOL success) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return NT_STATUS_NOT_IMPLEMENTED; } - return context->pdb_methods->lookup_rids(context->pdb_methods, - domain_sid, num_rids, - rids, pp_names, pp_attrs); + return pdb->update_login_attempts(pdb, sam_acct, success); } -static NTSTATUS context_get_account_policy(struct pdb_context *context, - int policy_index, uint32 *value) +BOOL pdb_getgrsid(GROUP_MAP *map, DOM_SID sid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return False; } - return context->pdb_methods->get_account_policy(context->pdb_methods, - policy_index, value); + return NT_STATUS_IS_OK(pdb->getgrsid(pdb, map, sid)); } -static NTSTATUS context_set_account_policy(struct pdb_context *context, - int policy_index, uint32 value) +BOOL pdb_getgrgid(GROUP_MAP *map, gid_t gid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return False; } - return context->pdb_methods->set_account_policy(context->pdb_methods, - policy_index, value); + return NT_STATUS_IS_OK(pdb->getgrgid(pdb, map, gid)); } -static NTSTATUS context_get_seq_num(struct pdb_context *context, time_t *seq_num) +BOOL pdb_getgrnam(GROUP_MAP *map, const char *name) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + struct pdb_methods *pdb = pdb_get_methods(); - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; + if ( !pdb ) { + return False; } - return context->pdb_methods->get_seq_num(context->pdb_methods, seq_num); + return NT_STATUS_IS_OK(pdb->getgrnam(pdb, map, name)); } - -/****************************************************************** - Free and cleanup a pdb context, any associated data and anything - that the attached modules might have associated. - *******************************************************************/ -static void free_pdb_context(struct pdb_context **context) +static NTSTATUS pdb_default_create_dom_group(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + const char *name, + uint32 *rid) { - struct pdb_methods *pdb_selected = (*context)->pdb_methods; + DOM_SID group_sid; + struct group *grp; - while (pdb_selected){ - if(pdb_selected->free_private_data) - pdb_selected->free_private_data(&(pdb_selected->private_data)); - pdb_selected = pdb_selected->next; - } + grp = getgrnam(name); - talloc_destroy((*context)->mem_ctx); - *context = NULL; -} + if (grp == NULL) { + gid_t gid; -static BOOL context_search_users(struct pdb_context *context, - struct pdb_search *search, uint16 acct_flags) -{ - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return False; + if (smb_create_group(name, &gid) != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + grp = getgrgid(gid); } - return context->pdb_methods->search_users(context->pdb_methods, - search, acct_flags); -} + if (grp == NULL) { + return NT_STATUS_ACCESS_DENIED; + } -static BOOL context_search_groups(struct pdb_context *context, - struct pdb_search *search) -{ - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return False; + if (pdb_rid_algorithm()) { + *rid = pdb_gid_to_group_rid( grp->gr_gid ); + } else { + if (!pdb_new_rid(rid)) { + return NT_STATUS_ACCESS_DENIED; + } } - return context->pdb_methods->search_groups(context->pdb_methods, - search); + sid_compose(&group_sid, get_global_sam_sid(), *rid); + + return add_initial_entry(grp->gr_gid, sid_string_static(&group_sid), + SID_NAME_DOM_GRP, name, NULL); } -static BOOL context_search_aliases(struct pdb_context *context, - struct pdb_search *search, - const DOM_SID *sid) +NTSTATUS pdb_create_dom_group(TALLOC_CTX *mem_ctx, const char *name, + uint32 *rid) { - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return False; + struct pdb_methods *pdb = pdb_get_methods(); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return context->pdb_methods->search_aliases(context->pdb_methods, - search, sid); + return pdb->create_dom_group(pdb, mem_ctx, name, rid); } -/****************************************************************** - Make a pdb_methods from scratch - *******************************************************************/ - -static NTSTATUS make_pdb_methods_name(struct pdb_methods **methods, struct pdb_context *context, const char *selected) +static NTSTATUS pdb_default_delete_dom_group(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 rid) { - char *module_name = smb_xstrdup(selected); - char *module_location = NULL, *p; - struct pdb_init_function_entry *entry; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - lazy_initialize_passdb(); + DOM_SID group_sid; + GROUP_MAP map; + NTSTATUS status; + struct group *grp; + const char *grp_name; - p = strchr(module_name, ':'); + sid_compose(&group_sid, get_global_sam_sid(), rid); - if (p) { - *p = 0; - module_location = p+1; - trim_char(module_location, ' ', ' '); + if (!get_domain_group_from_sid(group_sid, &map)) { + DEBUG(10, ("Could not find group for rid %d\n", rid)); + return NT_STATUS_NO_SUCH_GROUP; } - trim_char(module_name, ' ', ' '); + /* We need the group name for the smb_delete_group later on */ - - DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected, module_name)); - - entry = pdb_find_backend_entry(module_name); - - /* Try to find a module that contains this module */ - if (!entry) { - DEBUG(2,("No builtin backend found, trying to load plugin\n")); - if(NT_STATUS_IS_OK(smb_probe_module("pdb", module_name)) && !(entry = pdb_find_backend_entry(module_name))) { - DEBUG(0,("Plugin is available, but doesn't register passdb backend %s\n", module_name)); - SAFE_FREE(module_name); - return NT_STATUS_UNSUCCESSFUL; - } - } - - /* No such backend found */ - if(!entry) { - DEBUG(0,("No builtin nor plugin backend for %s found\n", module_name)); - SAFE_FREE(module_name); - return NT_STATUS_INVALID_PARAMETER; + if (map.gid == (gid_t)-1) { + return NT_STATUS_NO_SUCH_GROUP; } - DEBUG(5,("Found pdb backend %s\n", module_name)); - nt_status = entry->init(context, methods, module_location); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(5,("pdb backend %s has a valid init\n", selected)); - } else { - DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status))); + grp = getgrgid(map.gid); + if (grp == NULL) { + return NT_STATUS_NO_SUCH_GROUP; } - SAFE_FREE(module_name); - return nt_status; -} -/****************************************************************** - Make a pdb_context from scratch. - *******************************************************************/ + /* Copy the name, no idea what pdb_delete_group_mapping_entry does.. */ -static NTSTATUS make_pdb_context(struct pdb_context **context) -{ - TALLOC_CTX *mem_ctx; - - mem_ctx = talloc_init("pdb_context internal allocation context"); - - if (!mem_ctx) { - DEBUG(0, ("make_pdb_context: talloc init failed!\n")); + grp_name = talloc_strdup(mem_ctx, grp->gr_name); + if (grp_name == NULL) { return NT_STATUS_NO_MEMORY; - } + } - *context = TALLOC_P(mem_ctx, struct pdb_context); - if (!*context) { - DEBUG(0, ("make_pdb_context: talloc failed!\n")); - return NT_STATUS_NO_MEMORY; + status = pdb_delete_group_mapping_entry(group_sid); + + if (!NT_STATUS_IS_OK(status)) { + return status; } - ZERO_STRUCTP(*context); - - (*context)->mem_ctx = mem_ctx; - - (*context)->pdb_setsampwent = context_setsampwent; - (*context)->pdb_endsampwent = context_endsampwent; - (*context)->pdb_getsampwent = context_getsampwent; - (*context)->pdb_getsampwnam = context_getsampwnam; - (*context)->pdb_getsampwsid = context_getsampwsid; - (*context)->pdb_add_sam_account = context_add_sam_account; - (*context)->pdb_update_sam_account = context_update_sam_account; - (*context)->pdb_delete_sam_account = context_delete_sam_account; - (*context)->pdb_rename_sam_account = context_rename_sam_account; - (*context)->pdb_update_login_attempts = context_update_login_attempts; - (*context)->pdb_getgrsid = context_getgrsid; - (*context)->pdb_getgrgid = context_getgrgid; - (*context)->pdb_getgrnam = context_getgrnam; - (*context)->pdb_add_group_mapping_entry = context_add_group_mapping_entry; - (*context)->pdb_update_group_mapping_entry = context_update_group_mapping_entry; - (*context)->pdb_delete_group_mapping_entry = context_delete_group_mapping_entry; - (*context)->pdb_enum_group_mapping = context_enum_group_mapping; - (*context)->pdb_enum_group_members = context_enum_group_members; - (*context)->pdb_enum_group_memberships = context_enum_group_memberships; - - (*context)->pdb_find_alias = context_find_alias; - (*context)->pdb_create_alias = context_create_alias; - (*context)->pdb_delete_alias = context_delete_alias; - (*context)->pdb_get_aliasinfo = context_get_aliasinfo; - (*context)->pdb_set_aliasinfo = context_set_aliasinfo; - (*context)->pdb_add_aliasmem = context_add_aliasmem; - (*context)->pdb_del_aliasmem = context_del_aliasmem; - (*context)->pdb_enum_aliasmem = context_enum_aliasmem; - (*context)->pdb_enum_alias_memberships = context_enum_alias_memberships; - (*context)->pdb_lookup_rids = context_lookup_rids; - - (*context)->pdb_get_account_policy = context_get_account_policy; - (*context)->pdb_set_account_policy = context_set_account_policy; - - (*context)->pdb_get_seq_num = context_get_seq_num; - - (*context)->pdb_search_users = context_search_users; - (*context)->pdb_search_groups = context_search_groups; - (*context)->pdb_search_aliases = context_search_aliases; - - (*context)->free_fn = free_pdb_context; + /* Don't check the result of smb_delete_group */ + + smb_delete_group(grp_name); return NT_STATUS_OK; } +NTSTATUS pdb_delete_dom_group(TALLOC_CTX *mem_ctx, uint32 rid) +{ + struct pdb_methods *pdb = pdb_get_methods(); -/****************************************************************** - Make a pdb_context, given an array of strings - *******************************************************************/ + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } -NTSTATUS make_pdb_context_list(struct pdb_context **context, const char **selected) + return pdb->delete_dom_group(pdb, mem_ctx, rid); +} + +NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map) { - int i = 0; - struct pdb_methods *curmethods, *tmpmethods; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - BOOL have_guest = False; + struct pdb_methods *pdb = pdb_get_methods(); - if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context))) { - return nt_status; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - if (!selected) { - DEBUG(0, ("ERROR: empty passdb backend list!\n")); - return nt_status; - } + return pdb->add_group_mapping_entry(pdb, map); +} - while (selected[i]){ - if (strcmp(selected[i], "guest") == 0) { - have_guest = True; - } - /* Try to initialise pdb */ - DEBUG(5,("Trying to load: %s\n", selected[i])); - if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods_name(&curmethods, *context, selected[i]))) { - DEBUG(1, ("Loading %s failed!\n", selected[i])); - free_pdb_context(context); - return nt_status; - } - curmethods->parent = *context; - DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods); - i++; +NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map) +{ + struct pdb_methods *pdb = pdb_get_methods(); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - if (have_guest) - return NT_STATUS_OK; + return pdb->update_group_mapping_entry(pdb, map); +} - if ( (lp_guestaccount() == NULL) || - (*lp_guestaccount() == '\0') ) { - /* We explicitly don't want guest access. No idea what - else that breaks, but be it that way. */ - return NT_STATUS_OK; - } +NTSTATUS pdb_delete_group_mapping_entry(DOM_SID sid) +{ + struct pdb_methods *pdb = pdb_get_methods(); - if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods_name(&curmethods, - *context, - "guest"))) { - DEBUG(1, ("Loading guest module failed!\n")); - free_pdb_context(context); - return nt_status; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - curmethods->parent = *context; - DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods); - - return NT_STATUS_OK; + return pdb->delete_group_mapping_entry(pdb, sid); } -/****************************************************************** - Make a pdb_context, given a text string. - *******************************************************************/ - -NTSTATUS make_pdb_context_string(struct pdb_context **context, const char *selected) +BOOL pdb_enum_group_mapping(const DOM_SID *sid, enum SID_NAME_USE sid_name_use, GROUP_MAP **pp_rmap, + size_t *p_num_entries, BOOL unix_only) { - NTSTATUS ret; - char **newsel = str_list_make(selected, NULL); - ret = make_pdb_context_list(context, (const char **)newsel); - str_list_free(&newsel); - return ret; -} + struct pdb_methods *pdb = pdb_get_methods(); -/****************************************************************** - Return an already initialised pdb_context, to facilitate backward - compatibility (see functions below). -*******************************************************************/ + if ( !pdb ) { + return False; + } -static struct pdb_context *pdb_get_static_context(BOOL reload) + return NT_STATUS_IS_OK(pdb-> enum_group_mapping(pdb, sid, sid_name_use, + pp_rmap, p_num_entries, unix_only)); +} + +NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + uint32 **pp_member_rids, + size_t *p_num_members) { - static struct pdb_context *pdb_context = NULL; + struct pdb_methods *pdb = pdb_get_methods(); + NTSTATUS result; - if ((pdb_context) && (reload)) { - pdb_context->free_fn(&pdb_context); - if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) { - return NULL; - } + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - if (!pdb_context) { - if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) { - return NULL; + result = pdb->enum_group_members(pdb, mem_ctx, + sid, pp_member_rids, p_num_members); + + /* special check for rid 513 */ + + if ( !NT_STATUS_IS_OK( result ) ) { + uint32 rid; + + sid_peek_rid( sid, &rid ); + + if ( rid == DOMAIN_GROUP_RID_USERS ) { + *p_num_members = 0; + *pp_member_rids = NULL; + + return NT_STATUS_OK; } } - - return pdb_context; + + return result; } -/****************************************************************** - Backward compatibility functions for the original passdb interface -*******************************************************************/ - -BOOL pdb_setsampwent(BOOL update, uint16 acb_mask) +NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, struct samu *user, + DOM_SID **pp_sids, gid_t **pp_gids, + size_t *p_num_groups) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context->pdb_setsampwent(pdb_context, update, acb_mask)); + return pdb->enum_group_memberships( + pdb, mem_ctx, user, + pp_sids, pp_gids, p_num_groups); } -void pdb_endsampwent(void) +static NTSTATUS pdb_default_set_unix_primary_group(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + struct samu *sampass) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct group *grp; + gid_t gid; - if (!pdb_context) { - return; + if (!sid_to_gid(pdb_get_group_sid(sampass), &gid) || + (grp = getgrgid(gid)) == NULL) { + return NT_STATUS_INVALID_PRIMARY_GROUP; } - pdb_context->pdb_endsampwent(pdb_context); + if (smb_set_primary_group(grp->gr_name, + pdb_get_username(sampass)) != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; } -BOOL pdb_getsampwent(SAM_ACCOUNT *user) +NTSTATUS pdb_set_unix_primary_group(TALLOC_CTX *mem_ctx, struct samu *user) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context->pdb_getsampwent(pdb_context, user)); + return pdb->set_unix_primary_group(pdb, mem_ctx, user); } -static SAM_ACCOUNT *sam_account_cache = NULL; +/* + * Helper function to see whether a user is in a group. We can't use + * user_in_group_sid here because this creates dependencies only smbd can + * fulfil. + */ -BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username) +static BOOL pdb_user_in_group(TALLOC_CTX *mem_ctx, struct samu *account, + const DOM_SID *group_sid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + DOM_SID *sids; + gid_t *gids; + size_t i, num_groups; - if (!pdb_context) { + if (!NT_STATUS_IS_OK(pdb_enum_group_memberships(mem_ctx, account, + &sids, &gids, + &num_groups))) { return False; } - if (!NT_STATUS_IS_OK(pdb_context->pdb_getsampwnam(pdb_context, - sam_acct, username))) - return False; - - if (sam_account_cache != NULL) { - pdb_free_sam(&sam_account_cache); - sam_account_cache = NULL; + for (i=0; i<num_groups; i++) { + if (sid_equal(group_sid, &sids[i])) { + return True; + } } - - pdb_copy_sam_account(sam_acct, &sam_account_cache); - return True; + return False; } -BOOL pdb_getsampwsid(SAM_ACCOUNT *sam_acct, const DOM_SID *sid) +static NTSTATUS pdb_default_add_groupmem(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 group_rid, + uint32 member_rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + DOM_SID group_sid, member_sid; + struct samu *account = NULL; + GROUP_MAP map; + struct group *grp; + struct passwd *pwd; + const char *group_name; + uid_t uid; - if (!pdb_context) { - return False; + sid_compose(&group_sid, get_global_sam_sid(), group_rid); + sid_compose(&member_sid, get_global_sam_sid(), member_rid); + + if (!get_domain_group_from_sid(group_sid, &map) || + (map.gid == (gid_t)-1) || + ((grp = getgrgid(map.gid)) == NULL)) { + return NT_STATUS_NO_SUCH_GROUP; } - if ((sam_account_cache != NULL) && - (sid_equal(sid, pdb_get_user_sid(sam_account_cache)))) - return pdb_copy_sam_account(sam_account_cache, &sam_acct); + group_name = talloc_strdup(mem_ctx, grp->gr_name); + if (group_name == NULL) { + return NT_STATUS_NO_MEMORY; + } - return NT_STATUS_IS_OK(pdb_context->pdb_getsampwsid(pdb_context, sam_acct, sid)); -} + if ( !(account = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } -BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct) -{ - struct pdb_context *pdb_context = pdb_get_static_context(False); + if (!pdb_getsampwsid(account, &member_sid) || + !sid_to_uid(&member_sid, &uid) || + ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) { + return NT_STATUS_NO_SUCH_USER; + } - if (!pdb_context) { - return False; + if (pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_MEMBER_IN_GROUP; } - - return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, sam_acct)); -} -BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct) -{ - struct pdb_context *pdb_context = pdb_get_static_context(False); + /* + * ok, the group exist, the user exist, the user is not in the group, + * we can (finally) add it to the group ! + */ - if (!pdb_context) { - return False; - } + smb_add_user_group(group_name, pwd->pw_name); - if (sam_account_cache != NULL) { - pdb_free_sam(&sam_account_cache); - sam_account_cache = NULL; + if (!pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_ACCESS_DENIED; } - return NT_STATUS_IS_OK(pdb_context->pdb_update_sam_account(pdb_context, sam_acct)); + return NT_STATUS_OK; } -BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) +NTSTATUS pdb_add_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid, + uint32 member_rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); - - if (!pdb_context) { - return False; - } + struct pdb_methods *pdb = pdb_get_methods(); - if (sam_account_cache != NULL) { - pdb_free_sam(&sam_account_cache); - sam_account_cache = NULL; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context->pdb_delete_sam_account(pdb_context, sam_acct)); + return pdb->add_groupmem(pdb, mem_ctx, group_rid, member_rid); } -NTSTATUS pdb_rename_sam_account(SAM_ACCOUNT *oldname, const char *newname) +static NTSTATUS pdb_default_del_groupmem(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 group_rid, + uint32 member_rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + DOM_SID group_sid, member_sid; + struct samu *account = NULL; + GROUP_MAP map; + struct group *grp; + struct passwd *pwd; + const char *group_name; + uid_t uid; - if (!pdb_context) { - return NT_STATUS_NOT_IMPLEMENTED; + sid_compose(&group_sid, get_global_sam_sid(), group_rid); + sid_compose(&member_sid, get_global_sam_sid(), member_rid); + + if (!get_domain_group_from_sid(group_sid, &map) || + (map.gid == (gid_t)-1) || + ((grp = getgrgid(map.gid)) == NULL)) { + return NT_STATUS_NO_SUCH_GROUP; } - if (sam_account_cache != NULL) { - pdb_free_sam(&sam_account_cache); - sam_account_cache = NULL; + group_name = talloc_strdup(mem_ctx, grp->gr_name); + if (group_name == NULL) { + return NT_STATUS_NO_MEMORY; } - return pdb_context->pdb_rename_sam_account(pdb_context, oldname, newname); -} + if ( !(account = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } -NTSTATUS pdb_update_login_attempts(SAM_ACCOUNT *sam_acct, BOOL success) -{ - struct pdb_context *pdb_context = pdb_get_static_context(False); + if (!pdb_getsampwsid(account, &member_sid) || + !sid_to_uid(&member_sid, &uid) || + ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) { + return NT_STATUS_NO_SUCH_USER; + } - if (!pdb_context) { - return NT_STATUS_NOT_IMPLEMENTED; + if (!pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_MEMBER_NOT_IN_GROUP; + } + + /* + * ok, the group exist, the user exist, the user is in the group, + * we can (finally) delete it from the group! + */ + + smb_delete_user_group(group_name, pwd->pw_name); + + if (pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_ACCESS_DENIED; } - return pdb_context->pdb_update_login_attempts(pdb_context, sam_acct, success); + return NT_STATUS_OK; } -BOOL pdb_getgrsid(GROUP_MAP *map, DOM_SID sid) +NTSTATUS pdb_del_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid, + uint32 member_rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_getgrsid(pdb_context, map, sid)); + return pdb->del_groupmem(pdb, mem_ctx, group_rid, member_rid); } -BOOL pdb_getgrgid(GROUP_MAP *map, gid_t gid) +BOOL pdb_find_alias(const char *name, DOM_SID *sid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_getgrgid(pdb_context, map, gid)); + return NT_STATUS_IS_OK(pdb->find_alias(pdb, name, sid)); } -BOOL pdb_getgrnam(GROUP_MAP *map, const char *name) +NTSTATUS pdb_create_alias(const char *name, uint32 *rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_NOT_IMPLEMENTED; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_getgrnam(pdb_context, map, name)); + return pdb->create_alias(pdb, name, rid); } -BOOL pdb_add_group_mapping_entry(GROUP_MAP *map) +BOOL pdb_delete_alias(const DOM_SID *sid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_add_group_mapping_entry(pdb_context, map)); + return NT_STATUS_IS_OK(pdb->delete_alias(pdb, sid)); + } -BOOL pdb_update_group_mapping_entry(GROUP_MAP *map) +BOOL pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_update_group_mapping_entry(pdb_context, map)); + return NT_STATUS_IS_OK(pdb->get_aliasinfo(pdb, sid, info)); } -BOOL pdb_delete_group_mapping_entry(DOM_SID sid) +BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_delete_group_mapping_entry(pdb_context, sid)); + return NT_STATUS_IS_OK(pdb->set_aliasinfo(pdb, sid, info)); } -BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **pp_rmap, - size_t *p_num_entries, BOOL unix_only) +NTSTATUS pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_enum_group_mapping(pdb_context, sid_name_use, - pp_rmap, p_num_entries, unix_only)); + return pdb->add_aliasmem(pdb, alias, member); } -NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx, - const DOM_SID *sid, - uint32 **pp_member_rids, - size_t *p_num_members) +NTSTATUS pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return NT_STATUS_UNSUCCESSFUL; } - return pdb_context->pdb_enum_group_members(pdb_context, mem_ctx, sid, - pp_member_rids, p_num_members); + return pdb->del_aliasmem(pdb, alias, member); } -NTSTATUS pdb_enum_group_memberships(const char *username, gid_t primary_gid, - DOM_SID **pp_sids, gid_t **pp_gids, - size_t *p_num_groups) +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); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { 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->enum_aliasmem(pdb, alias, + pp_members, p_num_members); } -BOOL pdb_find_alias(const char *name, DOM_SID *sid) +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); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_NOT_IMPLEMENTED; } - return NT_STATUS_IS_OK(pdb_context->pdb_find_alias(pdb_context, - name, sid)); + return pdb->enum_alias_memberships(pdb, mem_ctx, + domain_sid, + members, num_members, + pp_alias_rids, + p_num_alias_rids); } -NTSTATUS pdb_create_alias(const char *name, uint32 *rid) +NTSTATUS pdb_lookup_rids(const DOM_SID *domain_sid, + int num_rids, + uint32 *rids, + const char **names, + uint32 *attrs) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return NT_STATUS_NOT_IMPLEMENTED; } - return pdb_context->pdb_create_alias(pdb_context, name, rid); + return pdb->lookup_rids(pdb, domain_sid, + num_rids, rids, names, attrs); } -BOOL pdb_delete_alias(const DOM_SID *sid) +NTSTATUS pdb_lookup_names(const DOM_SID *domain_sid, + int num_names, + const char **names, + uint32 *rids, + uint32 *attrs) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return False; + if ( !pdb ) { + return NT_STATUS_NOT_IMPLEMENTED; } - return NT_STATUS_IS_OK(pdb_context->pdb_delete_alias(pdb_context, - sid)); - + return pdb->lookup_names(pdb, domain_sid, + num_names, names, rids, attrs); } -BOOL pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info) +BOOL pdb_get_account_policy(int policy_index, uint32 *value) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context->pdb_get_aliasinfo(pdb_context, sid, - info)); + return NT_STATUS_IS_OK(pdb->get_account_policy(pdb, policy_index, value)); } -BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info) +BOOL pdb_set_account_policy(int policy_index, uint32 value) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context->pdb_set_aliasinfo(pdb_context, sid, - info)); + return NT_STATUS_IS_OK(pdb->set_account_policy(pdb, policy_index, value)); } -BOOL pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member) +BOOL pdb_get_seq_num(time_t *seq_num) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_add_aliasmem(pdb_context, alias, member)); + return NT_STATUS_IS_OK(pdb->get_seq_num(pdb, seq_num)); } -BOOL pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member) +BOOL pdb_uid_to_rid(uid_t uid, uint32 *rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_del_aliasmem(pdb_context, alias, member)); + return pdb->uid_to_rid(pdb, uid, rid); } -BOOL pdb_enum_aliasmem(const DOM_SID *alias, - DOM_SID **pp_members, size_t *p_num_members) +BOOL pdb_gid_to_sid(gid_t gid, DOM_SID *sid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_enum_aliasmem(pdb_context, alias, - pp_members, p_num_members)); + return pdb->gid_to_sid(pdb, gid, sid); } -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) +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); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { + if ( !pdb ) { return False; } - 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->sid_to_id(pdb, sid, id, type); } -NTSTATUS pdb_lookup_rids(const DOM_SID *domain_sid, - int num_rids, - uint32 *rids, - const char **names, - uint32 *attrs) +BOOL pdb_rid_algorithm(void) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); - if (!pdb_context) { - return NT_STATUS_NOT_IMPLEMENTED; + if ( !pdb ) { + return False; } - return pdb_context->pdb_lookup_rids(pdb_context, domain_sid, - num_rids, rids, names, attrs); + return pdb->rid_algorithm(pdb); } -BOOL pdb_get_account_policy(int policy_index, uint32 *value) +/******************************************************************** + Allocate a new RID from the passdb backend. Verify that it is free + by calling lookup_global_sam_rid() to verify that the RID is not + in use. This handles servers that have existing users or groups + with add RIDs (assigned from previous algorithmic mappings) +********************************************************************/ + +BOOL pdb_new_rid(uint32 *rid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); + const char *name = NULL; + enum SID_NAME_USE type; + uint32 allocated_rid = 0; + int i; + TALLOC_CTX *ctx; - if (!pdb_context) { + if ( !pdb ) { return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_get_account_policy(pdb_context, policy_index, value)); -} + if (pdb_rid_algorithm()) { + DEBUG(0, ("Trying to allocate a RID when algorithmic RIDs " + "are active\n")); + return False; + } -BOOL pdb_set_account_policy(int policy_index, uint32 value) -{ - struct pdb_context *pdb_context = pdb_get_static_context(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; + } - if (!pdb_context) { + if ( (ctx = talloc_init("pdb_new_rid")) == NULL ) { + DEBUG(0,("pdb_new_rid: Talloc initialization failure\n")); return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_set_account_policy(pdb_context, policy_index, value)); -} + /* Attempt to get an unused RID (max tires is 250...yes that it is + and arbitrary number I pulkled out of my head). -- jerry */ -BOOL pdb_get_seq_num(time_t *seq_num) -{ - struct pdb_context *pdb_context = pdb_get_static_context(False); + for ( i=0; allocated_rid==0 && i<250; i++ ) { + /* get a new RID */ + + if ( !pdb->new_rid(pdb, &allocated_rid) ) { + return False; + } + + /* validate that the RID is not in use */ + + if ( lookup_global_sam_rid( ctx, allocated_rid, &name, &type, NULL ) ) { + allocated_rid = 0; + } + } + + TALLOC_FREE( ctx ); - if (!pdb_context) { + if ( allocated_rid == 0 ) { + DEBUG(0,("pdb_new_rid: Failed to find unused RID\n")); return False; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_get_seq_num(pdb_context, seq_num)); + *rid = allocated_rid; + + return True; } + /*************************************************************** Initialize the static context (at smbd startup etc). @@ -1456,7 +1293,7 @@ BOOL pdb_get_seq_num(time_t *seq_num) BOOL initialize_password_db(BOOL reload) { - return (pdb_get_static_context(reload) != NULL); + return (pdb_get_methods_reload(reload) != NULL); } @@ -1464,48 +1301,47 @@ BOOL initialize_password_db(BOOL reload) Default implementations of some functions. ****************************************************************************/ -static NTSTATUS pdb_default_getsampwnam (struct pdb_methods *methods, SAM_ACCOUNT *user, const char *sname) +static NTSTATUS pdb_default_getsampwnam (struct pdb_methods *methods, struct samu *user, const char *sname) { return NT_STATUS_NO_SUCH_USER; } -static NTSTATUS pdb_default_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid) +static NTSTATUS pdb_default_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid) { return NT_STATUS_NO_SUCH_USER; } -static NTSTATUS pdb_default_add_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *newpwd) +static NTSTATUS pdb_default_add_sam_account (struct pdb_methods *methods, struct samu *newpwd) { - DEBUG(0,("this backend (%s) should not be listed as the first passdb backend! You can't add users to it.\n", methods->name)); return NT_STATUS_NOT_IMPLEMENTED; } -static NTSTATUS pdb_default_update_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *newpwd) +static NTSTATUS pdb_default_update_sam_account (struct pdb_methods *methods, struct samu *newpwd) { return NT_STATUS_NOT_IMPLEMENTED; } -static NTSTATUS pdb_default_delete_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *pwd) +static NTSTATUS pdb_default_delete_sam_account (struct pdb_methods *methods, struct samu *pwd) { return NT_STATUS_NOT_IMPLEMENTED; } -static NTSTATUS pdb_default_rename_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *pwd, const char *newname) +static NTSTATUS pdb_default_rename_sam_account (struct pdb_methods *methods, struct samu *pwd, const char *newname) { return NT_STATUS_NOT_IMPLEMENTED; } -static NTSTATUS pdb_default_update_login_attempts (struct pdb_methods *methods, SAM_ACCOUNT *newpwd, BOOL success) +static NTSTATUS pdb_default_update_login_attempts (struct pdb_methods *methods, struct samu *newpwd, BOOL success) { return NT_STATUS_OK; } -static NTSTATUS pdb_default_setsampwent(struct pdb_methods *methods, BOOL update, uint16 acb_mask) +static NTSTATUS pdb_default_setsampwent(struct pdb_methods *methods, BOOL update, uint32 acb_mask) { return NT_STATUS_NOT_IMPLEMENTED; } -static NTSTATUS pdb_default_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT *user) +static NTSTATUS pdb_default_getsampwent(struct pdb_methods *methods, struct samu *user) { return NT_STATUS_NOT_IMPLEMENTED; } @@ -1531,6 +1367,116 @@ 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) +{ + struct samu *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 ( !(sampw = samu_new( NULL )) ) { + DEBUG(0,("pdb_default_uid_to_rid: samu_new() failed!\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)); + TALLOC_FREE(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)))); + } + + TALLOC_FREE(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) { @@ -1554,31 +1500,36 @@ static BOOL get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **pp_uids, size { struct group *grp; char **gr; - struct sys_pwent *userlist, *user; + struct passwd *pwd; + char *winbindd_env; *pp_uids = NULL; *p_num = 0; /* We only look at our own sam, so don't care about imported stuff */ + winbindd_env = getenv(WINBINDD_DONT_ENV); winbind_off(); if ((grp = getgrgid(gid)) == NULL) { - winbind_on(); + /* allow winbindd lookups, but only if they weren't already disabled */ + if ( !(winbindd_env && strequal(winbindd_env, "1")) ) { + winbind_on(); + } + return False; } /* Primary group members */ - userlist = getpwent_list(); - - for (user = userlist; user != NULL; user = user->next) { - if (user->pw_gid != gid) - continue; - add_uid_to_array_unique(mem_ctx, user->pw_uid, pp_uids, p_num); + setpwent(); + while ((pwd = getpwent()) != NULL) { + if (pwd->pw_gid == gid) { + add_uid_to_array_unique(mem_ctx, pwd->pw_uid, + pp_uids, p_num); + } } - - pwent_free(userlist); + endpwent(); /* Secondary group members */ @@ -1590,7 +1541,11 @@ static BOOL get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **pp_uids, size add_uid_to_array_unique(mem_ctx, pw->pw_uid, pp_uids, p_num); } - winbind_on(); + /* allow winbindd lookups, but only if they weren't already disabled */ + + if ( !(winbindd_env && strequal(winbindd_env, "1")) ) { + winbind_on(); + } return True; } @@ -1608,7 +1563,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)) @@ -1622,13 +1577,10 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, for (i=0; i<num_uids; i++) { DOM_SID sid; - if (!NT_STATUS_IS_OK(uid_to_sid(&sid, uids[i]))) { - DEBUG(1, ("Could not map member uid to SID\n")); - continue; - } + uid_to_sid(&sid, uids[i]); if (!sid_check_is_in_our_domain(&sid)) { - DEBUG(1, ("Inconsistent SAM -- group member uid not " + DEBUG(5, ("Inconsistent SAM -- group member uid not " "in our domain\n")); continue; } @@ -1640,6 +1592,140 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, return NT_STATUS_OK; } +NTSTATUS pdb_default_enum_group_memberships(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + struct samu *user, + DOM_SID **pp_sids, + gid_t **pp_gids, + size_t *p_num_groups) +{ + size_t i; + gid_t gid; + struct passwd *pw; + const char *username = pdb_get_username(user); + + + /* Ignore the primary group SID. Honor the real Unix primary group. + The primary group SID is only of real use to Windows clients */ + + if ( !(pw = getpwnam_alloc(mem_ctx, username)) ) { + return NT_STATUS_NO_SUCH_USER; + } + + gid = pw->pw_gid; + + TALLOC_FREE( pw ); + + if (!getgroups_unix_user(mem_ctx, username, gid, pp_gids, p_num_groups)) { + return NT_STATUS_NO_SUCH_USER; + } + + if (*p_num_groups == 0) { + smb_panic("primary group missing"); + } + + *pp_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *p_num_groups); + + if (*pp_sids == NULL) { + TALLOC_FREE(*pp_gids); + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i<*p_num_groups; i++) { + gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]); + } + + return NT_STATUS_OK; +} + +/******************************************************************* + Look up a rid in the SAM we're responsible for (i.e. passdb) + ********************************************************************/ + +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) +{ + struct samu *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 ( !(sam_account = samu_new( NULL )) ) { + return False; + } + + /* BEING ROOT BLLOCK */ + become_root(); + if (pdb_getsampwsid(sam_account, &sid)) { + struct passwd *pw; + + unbecome_root(); /* -----> EXIT BECOME_ROOT() */ + *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account)); + *psid_name_use = SID_NAME_USER; + + TALLOC_FREE(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; + } + TALLOC_FREE(sam_account); + + ret = pdb_getgrsid(&map, sid); + unbecome_root(); + /* END BECOME_ROOT BLOCK */ + + /* do not resolve SIDs to a name unless there is a valid + gid associated with it */ + + if ( ret && (map.gid != (gid_t)-1) ) { + *name = talloc_strdup(mem_ctx, map.nt_name); + *psid_name_use = map.sid_name_use; + + if ( unix_id ) { + unix_id->gid = map.gid; + } + + return True; + } + + /* Windows will always map RID 513 to something. On a non-domain + controller, this gets mapped to SERVER\None. */ + + if ( unix_id ) { + DEBUG(5, ("Can't find a unix id for an unmapped group\n")); + return False; + } + + if ( rid == DOMAIN_GROUP_RID_USERS ) { + *name = talloc_strdup(mem_ctx, "None" ); + *psid_name_use = SID_NAME_DOM_GRP; + + return True; + } + + return False; +} + NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, const DOM_SID *domain_sid, int num_rids, @@ -1655,14 +1741,11 @@ NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, if (sid_check_is_builtin(domain_sid)) { for (i=0; i<num_rids; i++) { - fstring name; + const char *name; - if (lookup_builtin_rid(rids[i], name)) { + if (lookup_builtin_rid(names, rids[i], &name)) { attrs[i] = SID_NAME_ALIAS; - names[i] = talloc_strdup(names, name); - if (names[i] == NULL) { - return NT_STATUS_NO_MEMORY; - } + names[i] = name; DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i])); have_mapped = True; @@ -1680,14 +1763,14 @@ NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, } for (i = 0; i < num_rids; i++) { - fstring tmpname; - enum SID_NAME_USE type; + const char *name; - if (lookup_global_sam_rid(rids[i], tmpname, &type)) { - attrs[i] = (uint32)type; - names[i] = talloc_strdup(names, tmpname); - if (names[i] == NULL) + if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i], + NULL)) { + if (name == NULL) { return NT_STATUS_NO_MEMORY; + } + names[i] = name; DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i])); have_mapped = True; } else { @@ -1706,6 +1789,63 @@ NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, return result; } +NTSTATUS pdb_default_lookup_names(struct pdb_methods *methods, + const DOM_SID *domain_sid, + int num_names, + const char **names, + uint32 *rids, + uint32 *attrs) +{ + int i; + NTSTATUS result; + BOOL have_mapped = False; + BOOL have_unmapped = False; + + if (sid_check_is_builtin(domain_sid)) { + + for (i=0; i<num_names; i++) { + uint32 rid; + + if (lookup_builtin_name(names[i], &rid)) { + attrs[i] = SID_NAME_ALIAS; + rids[i] = rid; + DEBUG(5,("lookup_rids: %s:%d\n", + names[i], attrs[i])); + have_mapped = True; + } else { + have_unmapped = True; + attrs[i] = SID_NAME_UNKNOWN; + } + } + goto done; + } + + /* Should not happen, but better check once too many */ + if (!sid_check_is_domain(domain_sid)) { + return NT_STATUS_INVALID_HANDLE; + } + + for (i = 0; i < num_names; 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; + attrs[i] = SID_NAME_UNKNOWN; + } + } + + done: + + result = NT_STATUS_NONE_MAPPED; + + if (have_mapped) + result = have_unmapped ? STATUS_SOME_UNMAPPED : NT_STATUS_OK; + + return result; +} + static struct pdb_search *pdb_search_init(enum pdb_search_type type) { TALLOC_CTX *mem_ctx; @@ -1772,24 +1912,22 @@ static BOOL next_entry_users(struct pdb_search *s, struct samr_displayentry *entry) { struct user_search *state = s->private_data; - SAM_ACCOUNT *user = NULL; - NTSTATUS status; + struct samu *user = NULL; next: - status = pdb_init_sam(&user); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Could not pdb_init_sam\n")); + if ( !(user = samu_new( NULL )) ) { + DEBUG(0, ("next_entry_users: samu_new() failed!\n")); return False; } if (!pdb_getsampwent(user)) { - pdb_free_sam(&user); + TALLOC_FREE(user); return False; } if ((state->acct_flags != 0) && ((pdb_get_acct_ctrl(user) & state->acct_flags) == 0)) { - pdb_free_sam(&user); + TALLOC_FREE(user); goto next; } @@ -1798,7 +1936,7 @@ static BOOL next_entry_users(struct pdb_search *s, pdb_get_fullname(user), pdb_get_acct_desc(user), entry); - pdb_free_sam(&user); + TALLOC_FREE(user); return True; } @@ -1810,7 +1948,7 @@ static void search_end_users(struct pdb_search *search) static BOOL pdb_default_search_users(struct pdb_methods *methods, struct pdb_search *search, - uint16 acct_flags) + uint32 acct_flags) { struct user_search *state; @@ -1871,7 +2009,7 @@ static void search_end_groups(struct pdb_search *search) } static BOOL pdb_search_grouptype(struct pdb_search *search, - enum SID_NAME_USE type) + const DOM_SID *sid, enum SID_NAME_USE type) { struct group_search *state; @@ -1881,7 +2019,7 @@ static BOOL pdb_search_grouptype(struct pdb_search *search, return False; } - if (!pdb_enum_group_mapping(type, &state->groups, &state->num_groups, + if (!pdb_enum_group_mapping(sid, type, &state->groups, &state->num_groups, True)) { DEBUG(0, ("Could not enum groups\n")); return False; @@ -1897,7 +2035,7 @@ static BOOL pdb_search_grouptype(struct pdb_search *search, static BOOL pdb_default_search_groups(struct pdb_methods *methods, struct pdb_search *search) { - return pdb_search_grouptype(search, SID_NAME_DOM_GRP); + return pdb_search_grouptype(search, get_global_sam_sid(), SID_NAME_DOM_GRP); } static BOOL pdb_default_search_aliases(struct pdb_methods *methods, @@ -1905,14 +2043,7 @@ static BOOL pdb_default_search_aliases(struct pdb_methods *methods, const DOM_SID *sid) { - if (sid_equal(sid, get_global_sam_sid())) - return pdb_search_grouptype(search, SID_NAME_ALIAS); - - if (sid_equal(sid, &global_sid_Builtin)) - return pdb_search_grouptype(search, SID_NAME_WKN_GRP); - - DEBUG(3, ("unknown domain sid: %s\n", sid_string_static(sid))); - return False; + return pdb_search_grouptype(search, sid, SID_NAME_ALIAS); } static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search, @@ -1941,17 +2072,17 @@ static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search, return (search->num_entries > idx) ? &search->cache[idx] : NULL; } -struct pdb_search *pdb_search_users(uint16 acct_flags) +struct pdb_search *pdb_search_users(uint32 acct_flags) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); struct pdb_search *result; - if (pdb_context == NULL) return NULL; + if (pdb == NULL) return NULL; result = pdb_search_init(PDB_USER_SEARCH); if (result == NULL) return NULL; - if (!pdb_context->pdb_search_users(pdb_context, result, acct_flags)) { + if (!pdb->search_users(pdb, result, acct_flags)) { talloc_destroy(result->mem_ctx); return NULL; } @@ -1960,15 +2091,15 @@ struct pdb_search *pdb_search_users(uint16 acct_flags) struct pdb_search *pdb_search_groups(void) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); struct pdb_search *result; - if (pdb_context == NULL) return NULL; + if (pdb == NULL) return NULL; result = pdb_search_init(PDB_GROUP_SEARCH); if (result == NULL) return NULL; - if (!pdb_context->pdb_search_groups(pdb_context, result)) { + if (!pdb->search_groups(pdb, result)) { talloc_destroy(result->mem_ctx); return NULL; } @@ -1977,15 +2108,15 @@ struct pdb_search *pdb_search_groups(void) struct pdb_search *pdb_search_aliases(const DOM_SID *sid) { - struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_methods *pdb = pdb_get_methods(); struct pdb_search *result; - if (pdb_context == NULL) return NULL; + if (pdb == NULL) return NULL; result = pdb_search_init(PDB_ALIAS_SEARCH); if (result == NULL) return NULL; - if (!pdb_context->pdb_search_aliases(pdb_context, result, sid)) { + if (!pdb->search_aliases(pdb, result, sid)) { talloc_destroy(result->mem_ctx); return NULL; } @@ -2026,21 +2157,28 @@ void pdb_search_destroy(struct pdb_search *search) talloc_destroy(search->mem_ctx); } -NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) +/******************************************************************* + Create a pdb_methods structure and initialize it with the default + operations. In this way a passdb module can simply implement + the functionality it cares about. However, normally this is done + in groups of related functions. +*******************************************************************/ + +NTSTATUS make_pdb_method( struct pdb_methods **methods ) { - *methods = TALLOC_P(mem_ctx, struct pdb_methods); + /* allocate memory for the structure as its own talloc CTX */ - if (!*methods) { + if ( !(*methods = TALLOC_ZERO_P(NULL, struct pdb_methods) ) ) { return NT_STATUS_NO_MEMORY; } - ZERO_STRUCTP(*methods); - (*methods)->setsampwent = pdb_default_setsampwent; (*methods)->endsampwent = pdb_default_endsampwent; (*methods)->getsampwent = pdb_default_getsampwent; (*methods)->getsampwnam = pdb_default_getsampwnam; (*methods)->getsampwsid = pdb_default_getsampwsid; + (*methods)->create_user = pdb_default_create_user; + (*methods)->delete_user = pdb_default_delete_user; (*methods)->add_sam_account = pdb_default_add_sam_account; (*methods)->update_sam_account = pdb_default_update_sam_account; (*methods)->delete_sam_account = pdb_default_delete_sam_account; @@ -2050,12 +2188,17 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) (*methods)->getgrsid = pdb_default_getgrsid; (*methods)->getgrgid = pdb_default_getgrgid; (*methods)->getgrnam = pdb_default_getgrnam; + (*methods)->create_dom_group = pdb_default_create_dom_group; + (*methods)->delete_dom_group = pdb_default_delete_dom_group; (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry; (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry; (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry; (*methods)->enum_group_mapping = pdb_default_enum_group_mapping; (*methods)->enum_group_members = pdb_default_enum_group_members; (*methods)->enum_group_memberships = pdb_default_enum_group_memberships; + (*methods)->set_unix_primary_group = pdb_default_set_unix_primary_group; + (*methods)->add_groupmem = pdb_default_add_groupmem; + (*methods)->del_groupmem = pdb_default_del_groupmem; (*methods)->find_alias = pdb_default_find_alias; (*methods)->create_alias = pdb_default_create_alias; (*methods)->delete_alias = pdb_default_delete_alias; @@ -2069,6 +2212,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/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index 05fc8943829..1e3a5fdb6f0 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -1,11 +1,12 @@ /* Unix SMB/CIFS implementation. LDAP protocol helper functions for SAMBA - Copyright (C) Jean François Micouleau 1998 + Copyright (C) Jean François Micouleau 1998 Copyright (C) Gerald Carter 2001-2003 Copyright (C) Shahms King 2001 Copyright (C) Andrew Bartlett 2002-2003 Copyright (C) Stefan (metze) Metzmacher 2002-2003 + Copyright (C) Simo Sorce 2006 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 @@ -30,7 +31,7 @@ * Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK * * Other LDAP based login attributes: accountExpires, etc. -* (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT +* (should be the domain of Samba proper, but the sam_password/struct samu * structures don't have fields for some of these attributes) * * SSL is done, but can't get the certificate based authentication to work @@ -77,20 +78,15 @@ #endif -#ifndef SAM_ACCOUNT -#define SAM_ACCOUNT struct sam_passwd -#endif - #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 +113,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 +133,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 +249,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 +391,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,96 +429,20 @@ 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; -} - -/* New Interface is being implemented here */ - -#if 0 /* JERRY - not uesed anymore */ - -/********************************************************************** -Initialize SAM_ACCOUNT from an LDAP query (unix attributes only) -*********************************************************************/ -static BOOL get_unix_attributes (struct ldapsam_privates *ldap_state, - SAM_ACCOUNT * sampass, - LDAPMessage * entry, - gid_t *gid) -{ - pstring homedir; - pstring temp; - char **ldap_values; - char **values; - - if ((ldap_values = ldap_get_values (ldap_state->smbldap_state->ldap_struct, entry, "objectClass")) == NULL) { - DEBUG (1, ("get_unix_attributes: no objectClass! \n")); - return False; - } - - for (values=ldap_values;*values;values++) { - if (strequal(*values, LDAP_OBJ_POSIXACCOUNT )) { - break; - } - } - - if (!*values) { /*end of array, no posixAccount */ - DEBUG(10, ("user does not have %s attributes\n", LDAP_OBJ_POSIXACCOUNT)); - ldap_value_free(ldap_values); - return False; - } - ldap_value_free(ldap_values); - - if ( !smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_UNIX_HOME), homedir) ) - { - return False; - } - - if ( !smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_GIDNUMBER), temp) ) - { - return False; - } - - *gid = (gid_t)atol(temp); - - pdb_set_unix_homedir(sampass, homedir, PDB_SET); + talloc_autofree_ldapmod(mem_ctx, mods); - DEBUG(10, ("user has %s attributes\n", LDAP_OBJ_POSIXACCOUNT)); - - return True; + return smbldap_modify(priv->smbldap_state, dn, mods); } - -#endif - -static time_t ldapsam_get_entry_timestamp( - struct ldapsam_privates *ldap_state, - LDAPMessage * entry) + +static time_t ldapsam_get_entry_timestamp( struct ldapsam_privates *ldap_state, LDAPMessage * entry) { pstring temp; struct tm tm; @@ -563,12 +458,12 @@ static time_t ldapsam_get_entry_timestamp( } /********************************************************************** - Initialize SAM_ACCOUNT from an LDAP query. + Initialize struct samu from an LDAP query. (Based on init_sam_from_buffer in pdb_tdb.c) *********************************************************************/ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, - SAM_ACCOUNT * sampass, + struct samu * sampass, LDAPMessage * entry) { time_t logon_time, @@ -594,8 +489,8 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, uint8 smblmpwd[LM_HASH_LEN], smbntpwd[NT_HASH_LEN]; BOOL use_samba_attrs = True; - uint16 acct_ctrl = 0, - logon_divs; + uint32 acct_ctrl = 0; + uint16 logon_divs; uint16 bad_password_count = 0, logon_count = 0; uint32 hours_len; @@ -627,13 +522,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; } @@ -655,36 +553,12 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), temp)) { pdb_set_user_sid_from_string(sampass, temp, PDB_SET); } - - if (smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_SID), temp)) { - pdb_set_group_sid_from_string(sampass, temp, PDB_SET); - } else { - pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT); - } } else { if (smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID), temp)) { user_rid = (uint32)atol(temp); pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); } - - if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_RID), temp)) { - pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT); - } else { - uint32 group_rid; - - group_rid = (uint32)atol(temp); - - /* for some reason, we often have 0 as a primary group RID. - Make sure that we treat this just as a 'default' value */ - - if ( group_rid > 0 ) - pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); - else - pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT); - } } if (pdb_get_init_flags(sampass,PDB_USERSID) == PDB_DEFAULT) { @@ -773,7 +647,7 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH), homedir)) { pdb_set_homedir( sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_home()), + talloc_sub_basic(sampass, username, lp_logon_home()), PDB_DEFAULT ); } else { pstrcpy( tmpstring, homedir ); @@ -788,7 +662,7 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT), logon_script)) { pdb_set_logon_script( sampass, - talloc_sub_basic(sampass->mem_ctx, username, lp_logon_script()), + talloc_sub_basic(sampass, username, lp_logon_script()), PDB_DEFAULT ); } else { pstrcpy( tmpstring, logon_script ); @@ -803,7 +677,7 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH), profile_path)) { pdb_set_profile_path( sampass, - talloc_sub_basic( sampass->mem_ctx, username, lp_logon_path()), + talloc_sub_basic( sampass, username, lp_logon_path()), PDB_DEFAULT ); } else { pstrcpy( tmpstring, profile_path ); @@ -992,6 +866,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))) @@ -1033,14 +916,14 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, } /********************************************************************** - Initialize the ldap db from a SAM_ACCOUNT. Called on update. + Initialize the ldap db from a struct samu. Called on update. (Based on init_buffer_from_sam in pdb_tdb.c) *********************************************************************/ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, LDAPMessage *existing, - LDAPMod *** mods, SAM_ACCOUNT * sampass, - BOOL (*need_update)(const SAM_ACCOUNT *, + LDAPMod *** mods, struct samu * sampass, + BOOL (*need_update)(const struct samu *, enum pdb_elements)) { pstring temp; @@ -1057,9 +940,16 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, * took out adding "objectclass: sambaAccount" * do this on a per-mod basis */ - if (need_update(sampass, PDB_USERNAME)) + if (need_update(sampass, PDB_USERNAME)) { smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, "uid", pdb_get_username(sampass)); + if (ldap_state->is_nds_ldap) { + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, + "cn", pdb_get_username(sampass)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, + "sn", pdb_get_username(sampass)); + } + } DEBUG(2, ("init_ldap_from_sam: Setting entry for user: %s\n", pdb_get_username(sampass))); @@ -1354,7 +1244,7 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, Connect to LDAP server for password enumeration. *********************************************************************/ -static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint16 acb_mask) +static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint32 acb_mask) { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; int rc; @@ -1380,10 +1270,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 +1311,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, + struct samu *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 +1326,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,17 +1346,18 @@ 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; } /********************************************************************** -Get SAM_ACCOUNT entry from LDAP by username. +Get struct samu entry from LDAP by username. *********************************************************************/ -static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname) +static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, struct samu *user, const char *sname) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; @@ -1473,10 +1367,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, ldap_state->schema_ver ); + append_attr(user, &attr_list, + get_userattr_key2string(ldap_state->schema_ver, + LDAP_ATTR_MOD_TIMESTAMP)); + append_attr(user, &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 +1398,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, result); ret = NT_STATUS_OK; } else { ldap_msgfree(result); @@ -1518,24 +1416,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; @@ -1545,10 +1456,10 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, } /********************************************************************** - Get SAM_ACCOUNT entry from LDAP by SID. + Get struct samu entry from LDAP by SID. *********************************************************************/ -static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid) +static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid) { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; LDAPMessage *result = NULL; @@ -1588,9 +1499,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, result); return NT_STATUS_OK; } @@ -1605,14 +1516,14 @@ static BOOL ldapsam_can_pwchange_exop(struct smbldap_state *ldap_state) **********************************************************************/ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, - SAM_ACCOUNT *newpwd, char *dn, + struct samu *newpwd, char *dn, LDAPMod **mods, int ldap_op, - BOOL (*need_update)(const SAM_ACCOUNT *, enum pdb_elements)) + BOOL (*need_update)(const struct samu *, enum pdb_elements)) { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; int rc; - if (!my_methods || !newpwd || !dn) { + if (!newpwd || !dn) { return NT_STATUS_INVALID_PARAMETER; } @@ -1621,10 +1532,16 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, /* may be password change below however */ } else { switch(ldap_op) { - case LDAP_MOD_ADD: - smbldap_set_mod(&mods, LDAP_MOD_ADD, - "objectclass", - LDAP_OBJ_ACCOUNT); + case LDAP_MOD_ADD: + if (ldap_state->is_nds_ldap) { + smbldap_set_mod(&mods, LDAP_MOD_ADD, + "objectclass", + "inetOrgPerson"); + } else { + smbldap_set_mod(&mods, LDAP_MOD_ADD, + "objectclass", + LDAP_OBJ_ACCOUNT); + } rc = smbldap_add(ldap_state->smbldap_state, dn, mods); break; @@ -1639,14 +1556,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 +1656,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, + struct samu * 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 +1675,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; } /********************************************************************** @@ -1800,17 +1718,17 @@ static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_A we need LDAP modification. *********************************************************************/ -static BOOL element_is_changed(const SAM_ACCOUNT *sampass, +static BOOL element_is_changed(const struct samu *sampass, enum pdb_elements element) { return IS_SAM_CHANGED(sampass, element); } /********************************************************************** - Update SAM_ACCOUNT. + Update struct samu. *********************************************************************/ -static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd) +static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struct samu * newpwd) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; @@ -1823,13 +1741,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, result); } if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { @@ -1866,12 +1786,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; } @@ -1881,12 +1795,12 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A } /*************************************************************************** - Renames a SAM_ACCOUNT + Renames a struct samu - The "rename user script" has full responsibility for changing everything ***************************************************************************/ static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods, - SAM_ACCOUNT *old_acct, + struct samu *old_acct, const char *newname) { const char *oldname; @@ -1913,8 +1827,11 @@ static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods, DEBUG (3, ("ldapsam_rename_sam_account: Renaming user %s to %s.\n", oldname, newname)); - pstring_sub(rename_script, "%unew", newname); - pstring_sub(rename_script, "%uold", oldname); + /* we have to allow the account name to end with a '$' */ + string_sub2(rename_script, "%unew", newname, sizeof(pstring), + True, False, True); + string_sub2(rename_script, "%uold", oldname, sizeof(pstring), + True, False, True); rc = smbrun(rename_script, NULL); DEBUG(rc ? 0 : 3,("Running the command `%s' gave %d\n", @@ -1931,7 +1848,7 @@ static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods, we need LDAP modification. *********************************************************************/ -static BOOL element_is_set_or_changed(const SAM_ACCOUNT *sampass, +static BOOL element_is_set_or_changed(const struct samu *sampass, enum pdb_elements element) { return (IS_SAM_SET(sampass, element) || @@ -1939,10 +1856,10 @@ static BOOL element_is_set_or_changed(const SAM_ACCOUNT *sampass, } /********************************************************************** - Add SAM_ACCOUNT to LDAP. + Add struct samu to LDAP. *********************************************************************/ -static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd) +static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct samu * newpwd) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; @@ -1966,12 +1883,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 +1896,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 +1909,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 +1928,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 +1936,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 +1950,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,15 +1976,15 @@ 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; } num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); 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 ); + DEBUG (0, ("ldapsam_add_sam_account: More than one user with specified Sid exists: bailing out!\n")); + TALLOC_FREE( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2081,7 +1998,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 +2007,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 +2072,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 +2150,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 +2175,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 +2184,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 +2198,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; } @@ -2448,216 +2324,256 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; struct smbldap_state *conn = ldap_state->smbldap_state; - pstring filter; - int rc, count; - LDAPMessage *msg = NULL; + const char *id_attrs[] = { "memberUid", "gidNumber", NULL }; + const char *sid_attrs[] = { "sambaSID", NULL }; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + LDAPMessage *result = NULL; LDAPMessage *entry; + char *filter; char **values = NULL; char **memberuid; - char *sid_filter = NULL; - 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); + char *gidstr; + int rc, count; *pp_member_rids = NULL; *p_num_members = 0; - pstr_sprintf(filter, - "(&(objectClass=sambaSamAccount)" - "(sambaPrimaryGroupSid=%s))", - sid_string_static(group)); + filter = talloc_asprintf(mem_ctx, + "(&(objectClass=%s)" + "(objectClass=%s)" + "(sambaSID=%s))", + LDAP_OBJ_POSIXGROUP, + LDAP_OBJ_GROUPMAP, + sid_string_static(group)); - { - const char *attrs[] = { "sambaSID", NULL }; - rc = smbldap_search(conn, lp_ldap_user_suffix(), - LDAP_SCOPE_SUBTREE, filter, attrs, 0, - &msg); - } + rc = smbldap_search(conn, lp_ldap_group_suffix(), + LDAP_SCOPE_SUBTREE, filter, id_attrs, 0, + &result); if (rc != LDAP_SUCCESS) goto done; - for (entry = ldap_first_entry(conn->ldap_struct, msg); - entry != NULL; - entry = ldap_next_entry(conn->ldap_struct, entry)) - { - uint32 rid; - - if (!ldapsam_extract_rid_from_entry(conn->ldap_struct, - entry, - get_global_sam_sid(), - &rid)) { - DEBUG(2, ("Could not find sid from ldap entry\n")); - continue; - } - - add_rid_to_array_unique(mem_ctx, rid, pp_member_rids, - p_num_members); - } - - if (msg != NULL) - ldap_msgfree(msg); - - pstr_sprintf(filter, - "(&(objectClass=sambaGroupMapping)" - "(objectClass=posixGroup)" - "(sambaSID=%s))", - sid_string_static(group)); - - { - const char *attrs[] = { "memberUid", NULL }; - rc = smbldap_search(conn, lp_ldap_user_suffix(), - LDAP_SCOPE_SUBTREE, filter, attrs, 0, - &msg); - } - - if (rc != LDAP_SUCCESS) - goto done; + talloc_autofree_ldapmsg(mem_ctx, result); - count = ldap_count_entries(conn->ldap_struct, msg); + count = ldap_count_entries(conn->ldap_struct, result); if (count > 1) { DEBUG(1, ("Found more than one groupmap entry for %s\n", sid_string_static(group))); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; goto done; } if (count == 0) { - result = NT_STATUS_OK; + ret = NT_STATUS_NO_SUCH_GROUP; goto done; } - entry = ldap_first_entry(conn->ldap_struct, msg); + entry = ldap_first_entry(conn->ldap_struct, result); if (entry == NULL) goto done; - values = ldap_get_values(conn->ldap_struct, msg, "memberUid"); - if (values == NULL) { - result = NT_STATUS_OK; + gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx); + if (!gidstr) { + DEBUG (0, ("ldapsam_enum_group_members: Unable to find the group's gid!\n")); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; goto done; } - sid_filter = SMB_STRDUP("(&(objectClass=sambaSamAccount)(|"); - if (sid_filter == NULL) { - result = NT_STATUS_NO_MEMORY; - goto done; - } + values = ldap_get_values(conn->ldap_struct, entry, "memberUid"); + + if (values) { - for (memberuid = values; *memberuid != NULL; memberuid += 1) { - tmp = sid_filter; - asprintf(&sid_filter, "%s(uid=%s)", tmp, *memberuid); - free(tmp); - if (sid_filter == NULL) { - result = NT_STATUS_NO_MEMORY; + filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|", LDAP_OBJ_SAMBAACCOUNT); + if (filter == NULL) { + ret = NT_STATUS_NO_MEMORY; goto done; } - } - tmp = sid_filter; - asprintf(&sid_filter, "%s))", sid_filter); - free(tmp); - if (sid_filter == NULL) { - result = NT_STATUS_NO_MEMORY; - goto done; - } + for (memberuid = values; *memberuid != NULL; memberuid += 1) { + filter = talloc_asprintf_append(filter, "(uid=%s)", *memberuid); + if (filter == NULL) { + ret = NT_STATUS_NO_MEMORY; + goto done; + } + } + + filter = talloc_asprintf_append(filter, "))"); + if (filter == NULL) { + ret = NT_STATUS_NO_MEMORY; + goto done; + } - { - const char *attrs[] = { "sambaSID", NULL }; rc = smbldap_search(conn, lp_ldap_user_suffix(), - LDAP_SCOPE_SUBTREE, sid_filter, attrs, 0, - &msg); + LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0, + &result); + + if (rc != LDAP_SUCCESS) + goto done; + + count = ldap_count_entries(conn->ldap_struct, result); + DEBUG(10,("ldapsam_enum_group_members: found %d accounts\n", count)); + + talloc_autofree_ldapmsg(mem_ctx, result); + + for (entry = ldap_first_entry(conn->ldap_struct, result); + entry != NULL; + entry = ldap_next_entry(conn->ldap_struct, entry)) + { + char *sidstr; + DOM_SID sid; + uint32 rid; + + sidstr = smbldap_talloc_single_attribute(conn->ldap_struct, + entry, "sambaSID", + mem_ctx); + if (!sidstr) { + DEBUG(0, ("Severe DB error, sambaSamAccount can't miss " + "the sambaSID attribute\n")); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + if (!string_to_sid(&sid, sidstr)) + goto done; + + if (!sid_check_is_in_our_domain(&sid)) { + DEBUG(0, ("Inconsistent SAM -- group member uid not " + "in our domain\n")); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + sid_peek_rid(&sid, &rid); + + add_rid_to_array_unique(mem_ctx, rid, pp_member_rids, + p_num_members); + } } + filter = talloc_asprintf(mem_ctx, + "(&(objectClass=%s)" + "(gidNumber=%s))", + LDAP_OBJ_SAMBASAMACCOUNT, + gidstr); + + rc = smbldap_search(conn, lp_ldap_user_suffix(), + LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0, + &result); + if (rc != LDAP_SUCCESS) goto done; - for (entry = ldap_first_entry(conn->ldap_struct, msg); + talloc_autofree_ldapmsg(mem_ctx, result); + + for (entry = ldap_first_entry(conn->ldap_struct, result); entry != NULL; entry = ldap_next_entry(conn->ldap_struct, entry)) { - fstring str; - DOM_SID sid; uint32 rid; - if (!smbldap_get_single_attribute(conn->ldap_struct, - entry, "sambaSID", - str, sizeof(str)-1)) - continue; - - if (!string_to_sid(&sid, str)) + if (!ldapsam_extract_rid_from_entry(conn->ldap_struct, + entry, + get_global_sam_sid(), + &rid)) { + DEBUG(0, ("Severe DB error, sambaSamAccount can't miss " + "the sambaSID attribute\n")); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; goto done; - - if (!sid_check_is_in_our_domain(&sid)) { - DEBUG(1, ("Inconsistent SAM -- group member uid not " - "in our domain\n")); - continue; } - sid_peek_rid(&sid, &rid); - add_rid_to_array_unique(mem_ctx, rid, pp_member_rids, p_num_members); } - result = NT_STATUS_OK; + ret = NT_STATUS_OK; done: - SAFE_FREE(sid_filter); - if (values != NULL) + if (values) ldap_value_free(values); - if (msg != NULL) - ldap_msgfree(msg); - - return result; + return ret; } 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, + struct samu *user, + DOM_SID **pp_sids, + gid_t **pp_gids, size_t *p_num_groups) { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; struct smbldap_state *conn = ldap_state->smbldap_state; - pstring filter; + char *filter; const char *attrs[] = { "gidNumber", "sambaSID", NULL }; char *escape_name; - int rc; - LDAPMessage *msg = NULL; + int rc, count; + LDAPMessage *result = NULL; LDAPMessage *entry; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + NTSTATUS ret = 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); + char *gidstr; + gid_t primary_gid = -1; *pp_sids = NULL; num_sids = 0; - escape_name = escape_ldap_string_alloc(username); - + 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); + /* retrieve the users primary gid */ + filter = talloc_asprintf(mem_ctx, + "(&(objectClass=%s)(uid=%s))", + LDAP_OBJ_SAMBASAMACCOUNT, + escape_name); + + rc = smbldap_search(conn, lp_ldap_user_suffix(), + LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result); + + if (rc != LDAP_SUCCESS) + goto done; + + talloc_autofree_ldapmsg(mem_ctx, result); + + count = ldap_count_entries(priv2ld(ldap_state), result); + + switch (count) { + case 0: + DEBUG(1, ("User account [%s] not found!\n", pdb_get_username(user))); + ret = NT_STATUS_NO_SUCH_USER; + goto done; + case 1: + entry = ldap_first_entry(priv2ld(ldap_state), result); + + gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx); + if (!gidstr) { + DEBUG (1, ("Unable to find the member's gid!\n")); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + primary_gid = strtoul(gidstr, NULL, 10); + break; + default: + DEBUG(1, ("found more than one accoutn with the same user name ?!\n")); + ret = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + filter = talloc_asprintf(mem_ctx, + "(&(objectClass=%s)(|(memberUid=%s)(gidNumber=%d)))", + LDAP_OBJ_POSIXGROUP, escape_name, primary_gid); rc = smbldap_search(conn, lp_ldap_group_suffix(), - LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg); + LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result); if (rc != LDAP_SUCCESS) goto done; + talloc_autofree_ldapmsg(mem_ctx, result); + num_gids = 0; *pp_gids = NULL; @@ -2666,13 +2582,13 @@ 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); + for (entry = ldap_first_entry(conn->ldap_struct, result); entry != NULL; entry = ldap_next_entry(conn->ldap_struct, entry)) { @@ -2702,167 +2618,218 @@ 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; } *p_num_groups = num_sids; - result = NT_STATUS_OK; + ret = NT_STATUS_OK; done: SAFE_FREE(escape_name); - if (msg != NULL) - ldap_msgfree(msg); - - return result; + return ret; } /********************************************************************** + * 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); - - if ( count == 0 ) { - /* There's no posixGroup account, let's try to find an - * appropriate idmap entry for aliases */ + rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(), + LDAP_SCOPE_SUBTREE, filter, attrs, True, &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); - pstring suffix; - pstring filter; - const char **attr_list; + if ((rc == LDAP_SUCCESS) && + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) > 0)) { - ldap_msgfree(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; + } - 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); + switch (map->sid_name_use) { - free_attr_list(attr_list); + 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; - 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_ALIAS: + if (!sid_check_is_in_our_domain(&map->sid) + && !sid_check_is_in_builtin(&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; - 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 +2838,81 @@ 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=%s)" + "(sambaSid=%s)(gidNumber=%u)" + "(sambaGroupType=%d))", + LDAP_OBJ_GROUPMAP, + 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 +2921,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; + } + + 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) || + (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_search_one_group(ldap_state, filter, &result); + 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 }; - if (rc != LDAP_SUCCESS) { - return NT_STATUS_NO_SUCH_GROUP; + /* 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 +3027,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 +3050,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 +3059,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; @@ -3034,43 +3074,44 @@ 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, + const DOM_SID *domsid, enum SID_NAME_USE sid_name_use, + GROUP_MAP **pp_rmap, + size_t *p_num_entries, BOOL unix_only) { GROUP_MAP map; - GROUP_MAP *mapt; size_t entries = 0; *p_num_entries = 0; *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")); - SAFE_FREE(*pp_rmap); + (*pp_rmap)=SMB_REALLOC_ARRAY((*pp_rmap), GROUP_MAP, entries+1); + if (!(*pp_rmap)) { + DEBUG(0,("ldapsam_enum_group_mapping: Unable to " + "enlarge group map!\n")); return NT_STATUS_UNSUCCESSFUL; } - else - (*pp_rmap) = mapt; - mapt[entries] = map; + (*pp_rmap)[entries] = map; entries += 1; @@ -3095,14 +3136,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_ALIAS; + } + + 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 +3173,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 +3202,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 +3235,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 +3248,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_ALIAS; + } + + 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 +3286,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 +3347,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_ALIAS; + } - /* This query could be further optimized by adding a - (&(sambaSID=<domain-sid>*)) 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; i<num_members; i++) filter = talloc_asprintf(mem_ctx, "%s(sambaSIDList=%s)", @@ -3331,7 +3410,9 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods, return NT_STATUS_OK; } -static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, int policy_index, uint32 value) +static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, + int policy_index, + uint32 value) { NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; int rc; @@ -3352,7 +3433,8 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, policy_attr = get_account_policy_attr(policy_index); if (policy_attr == NULL) { - DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid policy\n")); + DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid " + "policy\n")); return ntstatus; } @@ -3363,40 +3445,39 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, smbldap_set_mod(&mods, LDAP_MOD_REPLACE, policy_attr, value_string); - rc = smbldap_modify(ldap_state->smbldap_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 +3500,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 +3509,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 +3545,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 +3554,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 +3602,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 +3619,43 @@ 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; i<num_rids; i++) attrs[i] = SID_NAME_UNKNOWN; - allsids = SMB_STRDUP(""); - if (allsids == NULL) return NT_STATUS_NO_MEMORY; + allsids = talloc_strdup(mem_ctx, ""); + if (allsids == NULL) { + goto done; + } for (i=0; i<num_rids; i++) { DOM_SID sid; - sid_copy(&sid, domain_sid); - sid_append_rid(&sid, rids[i]); - tmp = allsids; - asprintf(&allsids, "%s(sambaSid=%s)", allsids, - sid_string_static(&sid)); - if (allsids == NULL) return NT_STATUS_NO_MEMORY; - free(tmp); + sid_compose(&sid, domain_sid, rids[i]); + allsids = talloc_asprintf_append(allsids, "(sambaSid=%s)", + sid_string_static(&sid)); + if (allsids == NULL) { + goto done; + } } /* First look for users */ @@ -3577,40 +3664,43 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, char *filter; const char *ldap_attrs[] = { "uid", "sambaSid", NULL }; - asprintf(&filter, ("(&(objectClass=sambaSamAccount)(|%s))"), - allsids); - if (filter == NULL) return NT_STATUS_NO_MEMORY; + filter = talloc_asprintf( + mem_ctx, ("(&(objectClass=%s)(|%s))"), + LDAP_OBJ_SAMBASAMACCOUNT, allsids); + + if (filter == NULL) { + goto done; + } rc = smbldap_search(ldap_state->smbldap_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 +3716,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 +3726,82 @@ 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=%s)(|%s))", + LDAP_OBJ_GROUPMAP, 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_ALIAS)) || + (!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, "displayName", names); + + if (attr == NULL) { + DEBUG(10, ("Could not retrieve 'displayName' attribute from %s\n", + dn)); + attr = smbldap_talloc_single_attribute(ld, entry, "cn", names); + } + + if (attr == NULL) { + DEBUG(2, ("Could not retrieve naming attribute from %s\n", + dn)); continue; } @@ -3694,9 +3815,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,15 +3826,11 @@ 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; } -char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username) +static char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username) { char *filter = NULL; char *escaped = NULL; @@ -3727,8 +3843,7 @@ char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username) escaped = escape_ldap_string_alloc(username); if (escaped == NULL) goto done; - filter = realloc_string_sub(filter, "%u", username); - result = talloc_strdup(mem_ctx, filter); + result = talloc_string_sub(mem_ctx, filter, "%u", username); done: SAFE_FREE(filter); @@ -3762,7 +3877,7 @@ const char **talloc_attrs(TALLOC_CTX *mem_ctx, ...) struct ldap_search_state { struct smbldap_state *connection; - uint16 acct_flags; + uint32 acct_flags; uint16 group_type; const char *base; @@ -3834,7 +3949,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) { @@ -3851,7 +3965,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); @@ -3865,7 +3979,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: @@ -3876,17 +3989,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 : "<NULL>")); 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); @@ -3935,7 +4048,7 @@ static BOOL ldapuser2displayentry(struct ldap_search_state *state, { char **vals; DOM_SID sid; - uint16 acct_flags; + uint32 acct_flags; vals = ldap_get_values(ld, entry, "sambaAcctFlags"); if ((vals == NULL) || (vals[0] == NULL)) { @@ -4003,7 +4116,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; } @@ -4013,7 +4127,7 @@ static BOOL ldapuser2displayentry(struct ldap_search_state *state, static BOOL ldapsam_search_users(struct pdb_methods *methods, struct pdb_search *search, - uint16 acct_flags) + uint32 acct_flags) { struct ldapsam_privates *ldap_state = methods->private_data; struct ldap_search_state *state; @@ -4103,10 +4217,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); @@ -4147,21 +4265,15 @@ 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) + && !sid_peek_check_rid(&global_sid_Builtin, &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)) { - - DEBUG(0, ("%s is not in builtin sid\n", sid_string_static(&sid))); - return False; - } - break; - default: DEBUG(0,("unkown group type: %d\n", group_type)); return False; @@ -4172,6 +4284,7 @@ static BOOL ldapgroup2displayentry(struct ldap_search_state *state, static BOOL ldapsam_search_grouptype(struct pdb_methods *methods, struct pdb_search *search, + const DOM_SID *sid, enum SID_NAME_USE type) { struct ldapsam_privates *ldap_state = methods->private_data; @@ -4190,9 +4303,11 @@ static BOOL ldapsam_search_grouptype(struct pdb_methods *methods, state->scope = LDAP_SCOPE_SUBTREE; state->filter = talloc_asprintf(search->mem_ctx, "(&(objectclass=sambaGroupMapping)" - "(sambaGroupType=%d))", type); + "(sambaGroupType=%d)(sambaSID=%s))", + type, sid_string_static(sid)); 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; @@ -4214,25 +4329,1005 @@ static BOOL ldapsam_search_grouptype(struct pdb_methods *methods, static BOOL ldapsam_search_groups(struct pdb_methods *methods, struct pdb_search *search) { - return ldapsam_search_grouptype(methods, search, SID_NAME_DOM_GRP); + return ldapsam_search_grouptype(methods, search, get_global_sam_sid(), SID_NAME_DOM_GRP); } static BOOL ldapsam_search_aliases(struct pdb_methods *methods, struct pdb_search *search, const DOM_SID *sid) { - if (sid_check_is_domain(sid)) - return ldapsam_search_grouptype(methods, search, - SID_NAME_ALIAS); + return ldapsam_search_grouptype(methods, search, sid, SID_NAME_ALIAS); +} + +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; - if (sid_check_is_builtin(sid)) - return ldapsam_search_grouptype(methods, search, - SID_NAME_WKN_GRP); + TALLOC_CTX *mem_ctx; - DEBUG(5, ("Don't know SID %s\n", sid_string_static(sid))); + 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=%s)(objectClass=%s)))", + sid_string_static(sid), + LDAP_OBJ_GROUPMAP, LDAP_OBJ_SAMBASAMACCOUNT); + 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; +} + +/* + * The following functions is called only if + * ldapsam:trusted and ldapsam:editposix are + * set to true + */ + +/* + * ldapsam_create_user creates a new + * posixAccount and sambaSamAccount object + * in the ldap users subtree + * + * The uid is allocated by winbindd. + */ + +static NTSTATUS ldapsam_create_user(struct pdb_methods *my_methods, + TALLOC_CTX *tmp_ctx, const char *name, + uint32 acb_info, uint32 *rid) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + LDAPMessage *entry = NULL; + LDAPMessage *result = NULL; + uint32 num_result; + BOOL is_machine = False; + BOOL add_posix = False; + LDAPMod **mods = NULL; + struct samu *user; + char *filter; + char *username; + char *homedir; + char *gidstr; + char *uidstr; + char *shell; + const char *dn = NULL; + DOM_SID group_sid; + DOM_SID user_sid; + gid_t gid = -1; + uid_t uid = -1; + NTSTATUS ret; + int rc; + + if (((acb_info & ACB_NORMAL) && name[strlen(name)-1] == '$') || + acb_info & ACB_WSTRUST || + acb_info & ACB_SVRTRUST || + acb_info & ACB_DOMTRUST) { + is_machine = True; + } + + username = escape_ldap_string_alloc(name); + filter = talloc_asprintf(tmp_ctx, "(&(uid=%s)(objectClass=%s))", + username, LDAP_OBJ_POSIXACCOUNT); + SAFE_FREE(username); + + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_create_user: ldap search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result > 1) { + DEBUG (0, ("ldapsam_create_user: More than one user with name [%s] ?!\n", name)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (num_result == 1) { + char *tmp; + /* check if it is just a posix account. + * or if there is a sid attached to this entry + */ + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "sambaSID", tmp_ctx); + if (tmp) { + DEBUG (1, ("ldapsam_create_user: The user [%s] already exist!\n", name)); + return NT_STATUS_USER_EXISTS; + } + + /* it is just a posix account, retrieve the dn for later use */ + dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry); + if (!dn) { + DEBUG(0,("ldapsam_create_user: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + } + + if (num_result == 0) { + add_posix = True; + } + + /* Create the basic samu structure and generate the mods for the ldap commit */ + if (!NT_STATUS_IS_OK((ret = ldapsam_get_new_rid(ldap_state, rid)))) { + DEBUG(1, ("ldapsam_create_user: Could not allocate a new RID\n")); + return ret; + } + + sid_compose(&user_sid, get_global_sam_sid(), *rid); + + user = samu_new(tmp_ctx); + if (!user) { + DEBUG(1,("ldapsam_create_user: Unable to allocate user struct\n")); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_username(user, name, PDB_SET)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + if (!pdb_set_domain(user, get_global_sam_name(), PDB_SET)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + if (is_machine) { + if (acb_info & ACB_NORMAL) { + if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_SET)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + } else { + if (!pdb_set_acct_ctrl(user, acb_info, PDB_SET)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + } + } else { + if (!pdb_set_acct_ctrl(user, ACB_NORMAL | ACB_DISABLED, PDB_SET)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + } + + if (!pdb_set_user_sid(user, &user_sid, PDB_SET)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + if (!init_ldap_from_sam(ldap_state, NULL, &mods, user, element_is_set_or_changed)) { + DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + if (ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT) { + DEBUG(1,("ldapsam_create_user: Unsupported schema version\n")); + } + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SAMBASAMACCOUNT); + + if (add_posix) { + DEBUG(3,("ldapsam_create_user: Creating new posix user\n")); + + /* retrieve the Domain Users group gid */ + if (!sid_compose(&group_sid, get_global_sam_sid(), DOMAIN_GROUP_RID_USERS) || + !sid_to_gid(&group_sid, &gid)) { + DEBUG (0, ("ldapsam_create_user: Unable to get the Domain Users gid: bailing out!\n")); + return NT_STATUS_INVALID_PRIMARY_GROUP; + } + + /* lets allocate a new userid for this user */ + if (!winbind_allocate_uid(&uid)) { + DEBUG (0, ("ldapsam_create_user: Unable to allocate a new user id: bailing out!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + + if (is_machine) { + /* TODO: choose a more appropriate default for machines */ + homedir = talloc_sub_specified(tmp_ctx, lp_template_homedir(), "SMB_workstations_home", ldap_state->domain_name, uid, gid); + shell = talloc_strdup(tmp_ctx, "/bin/false"); + } else { + homedir = talloc_sub_specified(tmp_ctx, lp_template_homedir(), name, ldap_state->domain_name, uid, gid); + shell = talloc_sub_specified(tmp_ctx, lp_template_shell(), name, ldap_state->domain_name, uid, gid); + } + uidstr = talloc_asprintf(tmp_ctx, "%d", uid); + gidstr = talloc_asprintf(tmp_ctx, "%d", gid); + if (is_machine) { + dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", name, lp_ldap_machine_suffix ()); + } else { + dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", name, lp_ldap_user_suffix ()); + } + + if (!homedir || !shell || !uidstr || !gidstr || !dn) { + DEBUG (0, ("ldapsam_create_user: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_ACCOUNT); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXACCOUNT); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "uidNumber", uidstr); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", homedir); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", shell); + } + + talloc_autofree_ldapmod(tmp_ctx, mods); + + if (add_posix) { + rc = smbldap_add(ldap_state->smbldap_state, dn, mods); + } else { + rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); + } + + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_create_user: failed to create a new user [%s] (dn = %s)\n", name ,dn)); + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(2,("ldapsam_create_user: added account [%s] in the LDAP database\n", name)); + + flush_pwnam_cache(); + + return NT_STATUS_OK; +} + +static NTSTATUS ldapsam_delete_user(struct pdb_methods *my_methods, TALLOC_CTX *tmp_ctx, struct samu *sam_acct) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + int num_result; + const char *dn; + char *filter; + int rc; + + DEBUG(0,("ldapsam_delete_user: Attempt to delete user [%s]\n", pdb_get_username(sam_acct))); + + filter = talloc_asprintf(tmp_ctx, + "(&(uid=%s)" + "(objectClass=%s)" + "(objectClass=%s))", + pdb_get_username(sam_acct), + LDAP_OBJ_POSIXACCOUNT, + LDAP_OBJ_SAMBASAMACCOUNT); + + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_delete_user: user search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result == 0) { + DEBUG(0,("ldapsam_delete_user: user not found!\n")); + return NT_STATUS_NO_SUCH_USER; + } + + if (num_result > 1) { + DEBUG (0, ("ldapsam_delete_user: More than one user with name [%s] ?!\n", pdb_get_username(sam_acct))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* it is just a posix account, retrieve the dn for later use */ + dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry); + if (!dn) { + DEBUG(0,("ldapsam_delete_user: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + rc = smbldap_delete(ldap_state->smbldap_state, dn); + if (rc != LDAP_SUCCESS) { + return NT_STATUS_UNSUCCESSFUL; + } + + flush_pwnam_cache(); + + return NT_STATUS_OK; +} + +/* + * ldapsam_create_group creates a new + * posixGroup and sambaGroupMapping object + * in the ldap groups subtree + * + * The gid is allocated by winbindd. + */ + +static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods, + TALLOC_CTX *tmp_ctx, + const char *name, + uint32 *rid) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + NTSTATUS ret; + LDAPMessage *entry = NULL; + LDAPMessage *result = NULL; + uint32 num_result; + BOOL is_new_entry = False; + LDAPMod **mods = NULL; + char *filter; + char *groupsidstr; + char *groupname; + char *grouptype; + char *gidstr; + const char *dn = NULL; + DOM_SID group_sid; + gid_t gid = -1; + int rc; + + groupname = escape_ldap_string_alloc(name); + filter = talloc_asprintf(tmp_ctx, "(&(cn=%s)(objectClass=%s))", + groupname, LDAP_OBJ_POSIXGROUP); + SAFE_FREE(groupname); + + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_create_group: ldap search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result > 1) { + DEBUG (0, ("ldapsam_create_group: There exists more than one group with name [%s]: bailing out!\n", name)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (num_result == 1) { + char *tmp; + /* check if it is just a posix group. + * or if there is a sid attached to this entry + */ + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "sambaSID", tmp_ctx); + if (tmp) { + DEBUG (1, ("ldapsam_create_group: The group [%s] already exist!\n", name)); + return NT_STATUS_GROUP_EXISTS; + } + + /* it is just a posix group, retrieve the gid and the dn for later use */ + tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx); + if (!tmp) { + DEBUG (1, ("ldapsam_create_group: Couldn't retrieve the gidNumber for [%s]?!?!\n", name)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + gid = strtoul(tmp, NULL, 10); + + dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry); + if (!dn) { + DEBUG(0,("ldapsam_create_group: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + } + + if (num_result == 0) { + DEBUG(3,("ldapsam_create_user: Creating new posix group\n")); + + is_new_entry = True; + + /* lets allocate a new groupid for this group */ + if (!winbind_allocate_gid(&gid)) { + DEBUG (0, ("ldapsam_create_group: Unable to allocate a new group id: bailing out!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + gidstr = talloc_asprintf(tmp_ctx, "%d", gid); + dn = talloc_asprintf(tmp_ctx, "cn=%s,%s", name, lp_ldap_group_suffix()); + + if (!gidstr || !dn) { + DEBUG (0, ("ldapsam_create_group: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_POSIXGROUP); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr); + } + + if (!NT_STATUS_IS_OK((ret = ldapsam_get_new_rid(ldap_state, rid)))) { + DEBUG(1, ("ldapsam_create_group: Could not allocate a new RID\n")); + return ret; + } + + sid_compose(&group_sid, get_global_sam_sid(), *rid); + + groupsidstr = talloc_strdup(tmp_ctx, sid_string_static(&group_sid)); + grouptype = talloc_asprintf(tmp_ctx, "%d", SID_NAME_DOM_GRP); + + if (!groupsidstr || !grouptype) { + DEBUG(0,("ldapsam_create_group: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSid", groupsidstr); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaGroupType", grouptype); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", name); + talloc_autofree_ldapmod(tmp_ctx, mods); + + if (is_new_entry) { + rc = smbldap_add(ldap_state->smbldap_state, dn, mods); +#if 0 + if (rc == LDAP_OBJECT_CLASS_VIOLATION) { + /* This call may fail with rfc2307bis schema */ + /* Retry adding a structural class */ + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", "????"); + rc = smbldap_add(ldap_state->smbldap_state, dn, mods); + } +#endif + } else { + rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); + } + + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_create_group: failed to create a new group [%s] (dn = %s)\n", name ,dn)); + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(2,("ldapsam_create_group: added group [%s] in the LDAP database\n", name)); + + return NT_STATUS_OK; +} + +static NTSTATUS ldapsam_delete_dom_group(struct pdb_methods *my_methods, TALLOC_CTX *tmp_ctx, uint32 rid) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + int num_result; + const char *dn; + char *gidstr; + char *filter; + DOM_SID group_sid; + int rc; + + /* get the group sid */ + sid_compose(&group_sid, get_global_sam_sid(), rid); + + filter = talloc_asprintf(tmp_ctx, + "(&(sambaSID=%s)" + "(objectClass=%s)" + "(objectClass=%s))", + sid_string_static(&group_sid), + LDAP_OBJ_POSIXGROUP, + LDAP_OBJ_GROUPMAP); + + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(1,("ldapsam_delete_dom_group: group search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result == 0) { + DEBUG(1,("ldapsam_delete_dom_group: group not found!\n")); + return NT_STATUS_NO_SUCH_GROUP; + } + + if (num_result > 1) { + DEBUG (0, ("ldapsam_delete_dom_group: More than one group with the same SID ?!\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* here it is, retrieve the dn for later use */ + dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry); + if (!dn) { + DEBUG(0,("ldapsam_delete_dom_group: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx); + if (!gidstr) { + DEBUG (0, ("ldapsam_delete_dom_group: Unable to find the group's gid!\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + /* check no user have this group marked as primary group */ + filter = talloc_asprintf(tmp_ctx, + "(&(gidNumber=%s)" + "(objectClass=%s)" + "(objectClass=%s))", + gidstr, + LDAP_OBJ_POSIXACCOUNT, + LDAP_OBJ_SAMBASAMACCOUNT); + + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(1,("ldapsam_delete_dom_group: accounts search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result != 0) { + DEBUG(3,("ldapsam_delete_dom_group: Can't delete group, it is a primary group for %d users\n", num_result)); + return NT_STATUS_MEMBERS_PRIMARY_GROUP; + } + + rc = smbldap_delete(ldap_state->smbldap_state, dn); + if (rc != LDAP_SUCCESS) { + return NT_STATUS_UNSUCCESSFUL; + } + + return NT_STATUS_OK; +} + +static NTSTATUS ldapsam_change_groupmem(struct pdb_methods *my_methods, + TALLOC_CTX *tmp_ctx, + uint32 group_rid, + uint32 member_rid, + int modop) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + LDAPMessage *entry = NULL; + LDAPMessage *result = NULL; + uint32 num_result; + LDAPMod **mods = NULL; + char *filter; + char *uidstr; + const char *dn = NULL; + DOM_SID group_sid; + DOM_SID member_sid; + int rc; + + switch (modop) { + case LDAP_MOD_ADD: + DEBUG(1,("ldapsam_change_groupmem: add new member(rid=%d) to a domain group(rid=%d)", member_rid, group_rid)); + break; + case LDAP_MOD_DELETE: + DEBUG(1,("ldapsam_change_groupmem: delete member(rid=%d) from a domain group(rid=%d)", member_rid, group_rid)); + break; + default: + return NT_STATUS_UNSUCCESSFUL; + } + + /* get member sid */ + sid_compose(&member_sid, get_global_sam_sid(), member_rid); + + /* get the group sid */ + sid_compose(&group_sid, get_global_sam_sid(), group_rid); + + filter = talloc_asprintf(tmp_ctx, + "(&(sambaSID=%s)" + "(objectClass=%s)" + "(objectClass=%s))", + sid_string_static(&member_sid), + LDAP_OBJ_POSIXACCOUNT, + LDAP_OBJ_SAMBASAMACCOUNT); + + /* get the member uid */ + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(1,("ldapsam_change_groupmem: member search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result == 0) { + DEBUG(1,("ldapsam_change_groupmem: member not found!\n")); + return NT_STATUS_NO_SUCH_MEMBER; + } + + if (num_result > 1) { + DEBUG (0, ("ldapsam_change_groupmem: More than one account with the same SID ?!\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + if (modop == LDAP_MOD_DELETE) { + /* check if we are trying to remove the member from his primary group */ + char *gidstr; + gid_t user_gid, group_gid; + + gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx); + if (!gidstr) { + DEBUG (0, ("ldapsam_change_groupmem: Unable to find the member's gid!\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + user_gid = strtoul(gidstr, NULL, 10); + + if (!sid_to_gid(&group_sid, &group_gid)) { + DEBUG (0, ("ldapsam_change_groupmem: Unable to get group gid from SID!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + if (user_gid == group_gid) { + DEBUG (3, ("ldapsam_change_groupmem: can't remove user from it's own primary group!\n")); + return NT_STATUS_MEMBERS_PRIMARY_GROUP; + } + } + + /* here it is, retrieve the uid for later use */ + uidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "uid", tmp_ctx); + if (!uidstr) { + DEBUG (0, ("ldapsam_change_groupmem: Unable to find the member's name!\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + filter = talloc_asprintf(tmp_ctx, + "(&(sambaSID=%s)" + "(objectClass=%s)" + "(objectClass=%s))", + sid_string_static(&group_sid), + LDAP_OBJ_POSIXGROUP, + LDAP_OBJ_GROUPMAP); + + /* get the group */ + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(1,("ldapsam_change_groupmem: group search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(tmp_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result == 0) { + DEBUG(1,("ldapsam_change_groupmem: group not found!\n")); + return NT_STATUS_NO_SUCH_GROUP; + } + + if (num_result > 1) { + DEBUG (0, ("ldapsam_change_groupmem: More than one group with the same SID ?!\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* here it is, retrieve the dn for later use */ + dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry); + if (!dn) { + DEBUG(0,("ldapsam_change_groupmem: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + smbldap_set_mod(&mods, modop, "memberUid", uidstr); + + talloc_autofree_ldapmod(tmp_ctx, mods); + + rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); + if (rc != LDAP_SUCCESS) { + if (rc == LDAP_TYPE_OR_VALUE_EXISTS && modop == LDAP_MOD_ADD) { + DEBUG(1,("ldapsam_change_groupmem: member is already in group, add failed!\n")); + return NT_STATUS_MEMBER_IN_GROUP; + } + if (rc == LDAP_NO_SUCH_ATTRIBUTE && modop == LDAP_MOD_DELETE) { + DEBUG(1,("ldapsam_change_groupmem: member is not in group, delete failed!\n")); + return NT_STATUS_MEMBER_NOT_IN_GROUP; + } + return NT_STATUS_UNSUCCESSFUL; + } + + return NT_STATUS_OK; +} + +static NTSTATUS ldapsam_add_groupmem(struct pdb_methods *my_methods, + TALLOC_CTX *tmp_ctx, + uint32 group_rid, + uint32 member_rid) +{ + return ldapsam_change_groupmem(my_methods, tmp_ctx, group_rid, member_rid, LDAP_MOD_ADD); +} +static NTSTATUS ldapsam_del_groupmem(struct pdb_methods *my_methods, + TALLOC_CTX *tmp_ctx, + uint32 group_rid, + uint32 member_rid) +{ + return ldapsam_change_groupmem(my_methods, tmp_ctx, group_rid, member_rid, LDAP_MOD_DELETE); +} + +static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods, + TALLOC_CTX *mem_ctx, + struct samu *sampass) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + LDAPMessage *entry = NULL; + LDAPMessage *result = NULL; + uint32 num_result; + LDAPMod **mods = NULL; + char *filter; + char *gidstr; + const char *dn = NULL; + gid_t gid; + int rc; + + DEBUG(0,("ldapsam_set_primary_group: Attempt to set primary group for user [%s]\n", pdb_get_username(sampass))); + + if (!sid_to_gid(pdb_get_group_sid(sampass), &gid)) { + DEBUG(0,("ldapsam_set_primary_group: failed to retieve gid from user's group SID!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + gidstr = talloc_asprintf(mem_ctx, "%d", gid); + if (!gidstr) { + DEBUG(0,("ldapsam_set_primary_group: Out of Memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + filter = talloc_asprintf(mem_ctx, + "(&(uid=%s)" + "(objectClass=%s)" + "(objectClass=%s))", + pdb_get_username(sampass), + LDAP_OBJ_POSIXACCOUNT, + LDAP_OBJ_SAMBASAMACCOUNT); + + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result); + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_set_primary_group: user search failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + talloc_autofree_ldapmsg(mem_ctx, result); + + num_result = ldap_count_entries(priv2ld(ldap_state), result); + + if (num_result == 0) { + DEBUG(0,("ldapsam_set_primary_group: user not found!\n")); + return NT_STATUS_NO_SUCH_USER; + } + + if (num_result > 1) { + DEBUG (0, ("ldapsam_set_primary_group: More than one user with name [%s] ?!\n", pdb_get_username(sampass))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + entry = ldap_first_entry(priv2ld(ldap_state), result); + if (!entry) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* retrieve the dn for later use */ + dn = smbldap_talloc_dn(mem_ctx, priv2ld(ldap_state), entry); + if (!dn) { + DEBUG(0,("ldapsam_set_primary_group: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* remove the old one, and add the new one, this way we do not risk races */ + smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "gidNumber", gidstr); + + if (mods == NULL) { + return NT_STATUS_OK; + } + + rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); + + if (rc != LDAP_SUCCESS) { + DEBUG(0,("ldapsam_set_primary_group: failed to modify [%s] primary group to [%s]\n", + pdb_get_username(sampass), gidstr)); + return NT_STATUS_UNSUCCESSFUL; + } + + flush_pwnam_cache(); + + return NT_STATUS_OK; +} + /********************************************************************** Housekeeping *********************************************************************/ @@ -4256,17 +5351,17 @@ static void free_private_data(void **vp) /* No need to free any further, as it is talloc()ed */ } -/********************************************************************** - Intitalise the parts of the pdb_context that are common to all pdb_ldap modes - *********************************************************************/ +/********************************************************************* + Intitalise the parts of the pdb_methods structure that are common to + all pdb_ldap modes +*********************************************************************/ -static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, - const char *location) +static NTSTATUS pdb_init_ldapsam_common(struct pdb_methods **pdb_method, const char *location) { NTSTATUS nt_status; struct ldapsam_privates *ldap_state; - if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { + if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) { return nt_status; } @@ -4289,29 +5384,29 @@ 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); - if (!ldap_state) { + if ( !(ldap_state = TALLOC_ZERO_P(*pdb_method, struct ldapsam_privates)) ) { DEBUG(0, ("pdb_init_ldapsam_common: talloc() failed for ldapsam private_data!\n")); return NT_STATUS_NO_MEMORY; } - if (!NT_STATUS_IS_OK(nt_status = - smbldap_init(pdb_context->mem_ctx, location, - &ldap_state->smbldap_state))); + nt_status = smbldap_init(*pdb_method, location, &ldap_state->smbldap_state); + + if ( !NT_STATUS_IS_OK(nt_status) ) { + return nt_status; + } - ldap_state->domain_name = talloc_strdup(pdb_context->mem_ctx, get_global_sam_name()); - if (!ldap_state->domain_name) { + if ( !(ldap_state->domain_name = talloc_strdup(*pdb_method, get_global_sam_name()) ) ) { return NT_STATUS_NO_MEMORY; } @@ -4326,13 +5421,14 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS ** Initialise the 'compat' mode for pdb_ldap *********************************************************************/ -NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +NTSTATUS pdb_init_ldapsam_compat(struct pdb_methods **pdb_method, const char *location) { NTSTATUS nt_status; struct ldapsam_privates *ldap_state; + char *uri = talloc_strdup( NULL, location ); #ifdef WITH_LDAP_SAMCONFIG - if (!location) { + if (!uri) { int ldap_port = lp_ldap_port(); /* remap default port if not using SSL (ie clear or TLS) */ @@ -4340,17 +5436,23 @@ NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met ldap_port = 389; } - location = talloc_asprintf(pdb_context->mem_ctx, "%s://%s:%d", lp_ldap_ssl() == LDAP_SSL_ON ? "ldaps" : "ldap", lp_ldap_server(), ldap_port); - if (!location) { + uri = talloc_asprintf(NULL, "%s://%s:%d", lp_ldap_ssl() == LDAP_SSL_ON ? "ldaps" : "ldap", lp_ldap_server(), ldap_port); + if (!uri) { return NT_STATUS_NO_MEMORY; } + location = uri; } #endif - if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) { + if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common( pdb_method, uri ))) { return nt_status; } + /* the module itself stores a copy of the location so throw this one away */ + + if ( uri ) + TALLOC_FREE( uri ); + (*pdb_method)->name = "ldapsam_compat"; ldap_state = (*pdb_method)->private_data; @@ -4365,7 +5467,7 @@ NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met Initialise the normal mode for pdb_ldap *********************************************************************/ -NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location) { NTSTATUS nt_status; struct ldapsam_privates *ldap_state; @@ -4378,7 +5480,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_method, location); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -4392,27 +5495,51 @@ 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; + + if (lp_parm_bool(-1, "ldapsam", "editposix", False)) { + (*pdb_method)->create_user = ldapsam_create_user; + (*pdb_method)->delete_user = ldapsam_delete_user; + (*pdb_method)->create_dom_group = ldapsam_create_dom_group; + (*pdb_method)->delete_dom_group = ldapsam_delete_dom_group; + (*pdb_method)->add_groupmem = ldapsam_add_groupmem; + (*pdb_method)->del_groupmem = ldapsam_del_groupmem; + (*pdb_method)->set_unix_primary_group = ldapsam_set_primary_group; + } + } + 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; } @@ -4425,35 +5552,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/source/passdb/pdb_mysql.c b/source/passdb/pdb_mysql.c deleted file mode 100644 index 27675a9cd18..00000000000 --- a/source/passdb/pdb_mysql.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * MySQL password backend for samba - * Copyright (C) Jelmer Vernooij 2002-2004 - * - * 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" -#include <mysql/mysql.h> - -#define CONFIG_HOST_DEFAULT "localhost" -#define CONFIG_USER_DEFAULT "samba" -#define CONFIG_PASS_DEFAULT "" -#define CONFIG_PORT_DEFAULT "3306" -#define CONFIG_DB_DEFAULT "samba" - -static int mysqlsam_debug_level = DBGC_ALL; - -#undef DBGC_CLASS -#define DBGC_CLASS mysqlsam_debug_level - -typedef struct pdb_mysql_data { - MYSQL *handle; - MYSQL_RES *pwent; - const char *location; -} pdb_mysql_data; - -#define SET_DATA(data,methods) { \ - if(!methods){ \ - DEBUG(0, ("invalid methods!\n")); \ - return NT_STATUS_INVALID_PARAMETER; \ - } \ - data = (struct pdb_mysql_data *)methods->private_data; \ - if(!data || !(data->handle)){ \ - DEBUG(0, ("invalid handle!\n")); \ - return NT_STATUS_INVALID_HANDLE; \ - } \ -} - -#define config_value( data, name, default_value ) \ - lp_parm_const_string( GLOBAL_SECTION_SNUM, (data)->location, name, default_value ) - -static long xatol(const char *d) -{ - if(!d) return 0; - return atol(d); -} - -static NTSTATUS row_to_sam_account(MYSQL_RES * r, SAM_ACCOUNT * u) -{ - MYSQL_ROW row; - pstring temp; - unsigned int num_fields; - DOM_SID sid; - - num_fields = mysql_num_fields(r); - row = mysql_fetch_row(r); - if (!row) - return NT_STATUS_INVALID_PARAMETER; - - pdb_set_logon_time(u, xatol(row[0]), PDB_SET); - pdb_set_logoff_time(u, xatol(row[1]), PDB_SET); - pdb_set_kickoff_time(u, xatol(row[2]), PDB_SET); - pdb_set_pass_last_set_time(u, xatol(row[3]), PDB_SET); - pdb_set_pass_can_change_time(u, xatol(row[4]), PDB_SET); - pdb_set_pass_must_change_time(u, xatol(row[5]), PDB_SET); - pdb_set_username(u, row[6], PDB_SET); - pdb_set_domain(u, row[7], PDB_SET); - pdb_set_nt_username(u, row[8], PDB_SET); - pdb_set_fullname(u, row[9], PDB_SET); - pdb_set_homedir(u, row[10], PDB_SET); - pdb_set_dir_drive(u, row[11], PDB_SET); - pdb_set_logon_script(u, row[12], PDB_SET); - pdb_set_profile_path(u, row[13], PDB_SET); - pdb_set_acct_desc(u, row[14], PDB_SET); - pdb_set_workstations(u, row[15], PDB_SET); - pdb_set_unknown_str(u, row[16], PDB_SET); - pdb_set_munged_dial(u, row[17], PDB_SET); - - if(!row[18] || !string_to_sid(&sid, row[18])) { - DEBUG(0,("No user SID retrieved from database!\n")); - } else { - pdb_set_user_sid(u, &sid, PDB_SET); - } - - if(row[19]) { - string_to_sid(&sid, row[19]); - pdb_set_group_sid(u, &sid, PDB_SET); - } - - if (pdb_gethexpwd(row[20], temp)) - pdb_set_lanman_passwd(u, temp, PDB_SET); - if (pdb_gethexpwd(row[21], temp)) - pdb_set_nt_passwd(u, temp, PDB_SET); - - /* Only use plaintext password storage when lanman and nt are - * NOT used */ - if (!row[20] || !row[21]) - pdb_set_plaintext_passwd(u, row[22]); - - pdb_set_acct_ctrl(u, xatol(row[23]), PDB_SET); - pdb_set_logon_divs(u, xatol(row[24]), PDB_SET); - pdb_set_hours_len(u, xatol(row[25]), PDB_SET); - pdb_set_bad_password_count(u, xatol(row[26]), PDB_SET); - pdb_set_logon_count(u, xatol(row[27]), PDB_SET); - pdb_set_unknown_6(u, xatol(row[28]), PDB_SET); - - return NT_STATUS_OK; -} - -static NTSTATUS mysqlsam_setsampwent(struct pdb_methods *methods, BOOL update, uint16 acb_mask) -{ - struct pdb_mysql_data *data = - (struct pdb_mysql_data *) methods->private_data; - char *query; - int ret; - - if (!data || !(data->handle)) { - DEBUG(0, ("invalid handle!\n")); - return NT_STATUS_INVALID_HANDLE; - } - - query = sql_account_query_select(NULL, data->location, update, SQL_SEARCH_NONE, NULL); - - ret = mysql_query(data->handle, query); - talloc_free(query); - - if (ret) { - DEBUG(0, - ("Error executing MySQL query %s\n", mysql_error(data->handle))); - return NT_STATUS_UNSUCCESSFUL; - } - - data->pwent = mysql_store_result(data->handle); - - if (data->pwent == NULL) { - DEBUG(0, - ("Error storing results: %s\n", mysql_error(data->handle))); - return NT_STATUS_UNSUCCESSFUL; - } - - DEBUG(5, - ("mysqlsam_setsampwent succeeded(%llu results)!\n", - mysql_num_rows(data->pwent))); - - return NT_STATUS_OK; -} - -/*************************************************************** - End enumeration of the passwd list. - ****************************************************************/ - -static void mysqlsam_endsampwent(struct pdb_methods *methods) -{ - struct pdb_mysql_data *data = - (struct pdb_mysql_data *) methods->private_data; - - if (data == NULL) { - DEBUG(0, ("invalid handle!\n")); - return; - } - - if (data->pwent != NULL) - mysql_free_result(data->pwent); - - data->pwent = NULL; - - DEBUG(5, ("mysql_endsampwent called\n")); -} - -/***************************************************************** - Get one SAM_ACCOUNT from the list (next in line) - *****************************************************************/ - -static NTSTATUS mysqlsam_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT * user) -{ - struct pdb_mysql_data *data; - - SET_DATA(data, methods); - - if (data->pwent == NULL) { - DEBUG(0, ("invalid pwent\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return row_to_sam_account(data->pwent, user); -} - -static NTSTATUS mysqlsam_select_by_field(struct pdb_methods * methods, SAM_ACCOUNT * user, - enum sql_search_field field, const char *sname) -{ - char *esc_sname; - char *query; - NTSTATUS ret; - MYSQL_RES *res; - int mysql_ret; - struct pdb_mysql_data *data; - char *tmp_sname; - TALLOC_CTX *mem_ctx = talloc_init("mysqlsam_select_by_field"); - - SET_DATA(data, methods); - - esc_sname = talloc_array(mem_ctx, char, strlen(sname) * 2 + 1); - if (!esc_sname) { - talloc_free(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - - tmp_sname = talloc_strdup(mem_ctx, sname); - - /* Escape sname */ - mysql_real_escape_string(data->handle, esc_sname, tmp_sname, - strlen(tmp_sname)); - - talloc_free(tmp_sname); - - if (user == NULL) { - DEBUG(0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n")); - talloc_free(mem_ctx); - return NT_STATUS_INVALID_PARAMETER; - } - - query = sql_account_query_select(mem_ctx, data->location, True, field, esc_sname); - - talloc_free(esc_sname); - - DEBUG(5, ("Executing query %s\n", query)); - - mysql_ret = mysql_query(data->handle, query); - - talloc_free(query); - - if (mysql_ret) { - DEBUG(0, - ("Error while executing MySQL query %s\n", - mysql_error(data->handle))); - talloc_free(mem_ctx); - return NT_STATUS_UNSUCCESSFUL; - } - - res = mysql_store_result(data->handle); - if (res == NULL) { - DEBUG(0, - ("Error storing results: %s\n", mysql_error(data->handle))); - talloc_free(mem_ctx); - return NT_STATUS_UNSUCCESSFUL; - } - - ret = row_to_sam_account(res, user); - mysql_free_result(res); - talloc_free(mem_ctx); - - return ret; -} - -/****************************************************************** - Lookup a name in the SAM database - ******************************************************************/ - -static NTSTATUS mysqlsam_getsampwnam(struct pdb_methods *methods, SAM_ACCOUNT * user, - const char *sname) -{ - struct pdb_mysql_data *data; - - SET_DATA(data, methods); - - if (!sname) { - DEBUG(0, ("invalid name specified")); - return NT_STATUS_INVALID_PARAMETER; - } - - return mysqlsam_select_by_field(methods, user, - SQL_SEARCH_USER_NAME, sname); -} - - -/*************************************************************************** - Search by sid - **************************************************************************/ - -static NTSTATUS mysqlsam_getsampwsid(struct pdb_methods *methods, SAM_ACCOUNT * user, - const DOM_SID * sid) -{ - struct pdb_mysql_data *data; - fstring sid_str; - - SET_DATA(data, methods); - - sid_to_string(sid_str, sid); - - return mysqlsam_select_by_field(methods, user, SQL_SEARCH_USER_SID, sid_str); -} - -/*************************************************************************** - Delete a SAM_ACCOUNT - ****************************************************************************/ - -static NTSTATUS mysqlsam_delete_sam_account(struct pdb_methods *methods, - SAM_ACCOUNT * sam_pass) -{ - const char *sname = pdb_get_username(sam_pass); - char *esc; - char *query; - int ret; - struct pdb_mysql_data *data; - char *tmp_sname; - TALLOC_CTX *mem_ctx; - SET_DATA(data, methods); - - if (!methods) { - DEBUG(0, ("invalid methods!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - data = (struct pdb_mysql_data *) methods->private_data; - if (!data || !(data->handle)) { - DEBUG(0, ("invalid handle!\n")); - return NT_STATUS_INVALID_HANDLE; - } - - if (!sname) { - DEBUG(0, ("invalid name specified\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - mem_ctx = talloc_init("mysqlsam_delete_sam_account"); - - /* Escape sname */ - esc = talloc_array(mem_ctx, char, strlen(sname) * 2 + 1); - if (!esc) { - DEBUG(0, ("Can't allocate memory to store escaped name\n")); - return NT_STATUS_NO_MEMORY; - } - - tmp_sname = talloc_strdup(mem_ctx, sname); - - mysql_real_escape_string(data->handle, esc, tmp_sname, - strlen(tmp_sname)); - - talloc_free(tmp_sname); - - query = sql_account_query_delete(mem_ctx, data->location, esc); - - talloc_free(esc); - - ret = mysql_query(data->handle, query); - - talloc_free(query); - - if (ret) { - DEBUG(0, - ("Error while executing query: %s\n", - mysql_error(data->handle))); - talloc_free(mem_ctx); - return NT_STATUS_UNSUCCESSFUL; - } - - DEBUG(5, ("User '%s' deleted\n", sname)); - talloc_free(mem_ctx); - return NT_STATUS_OK; -} - -static NTSTATUS mysqlsam_replace_sam_account(struct pdb_methods *methods, - const SAM_ACCOUNT * newpwd, char isupdate) -{ - struct pdb_mysql_data *data; - char *query; - - if (!methods) { - DEBUG(0, ("invalid methods!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - data = (struct pdb_mysql_data *) methods->private_data; - - if (data == NULL || data->handle == NULL) { - DEBUG(0, ("invalid handle!\n")); - return NT_STATUS_INVALID_HANDLE; - } - - query = sql_account_query_update(NULL, data->location, newpwd, isupdate); - if ( query == NULL ) /* Nothing to update. */ - return NT_STATUS_OK; - - /* Execute the query */ - if (mysql_query(data->handle, query)) { - DEBUG(0, - ("Error executing %s, %s\n", query, - mysql_error(data->handle))); - talloc_free(query); - return NT_STATUS_INVALID_PARAMETER; - } - - talloc_free(query); - - return NT_STATUS_OK; -} - -static NTSTATUS mysqlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT * newpwd) -{ - return mysqlsam_replace_sam_account(methods, newpwd, 0); -} - -static NTSTATUS mysqlsam_update_sam_account(struct pdb_methods *methods, - SAM_ACCOUNT * newpwd) -{ - return mysqlsam_replace_sam_account(methods, newpwd, 1); -} - -static NTSTATUS mysqlsam_init(struct pdb_context * pdb_context, struct pdb_methods ** pdb_method, - const char *location) -{ - NTSTATUS nt_status; - struct pdb_mysql_data *data; - - mysqlsam_debug_level = debug_add_class("mysqlsam"); - if (mysqlsam_debug_level == -1) { - mysqlsam_debug_level = DBGC_ALL; - DEBUG(0, - ("mysqlsam: Couldn't register custom debugging class!\n")); - } - - - if (!pdb_context) { - DEBUG(0, ("invalid pdb_methods specified\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - if (!NT_STATUS_IS_OK - (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { - return nt_status; - } - - (*pdb_method)->name = "mysqlsam"; - - (*pdb_method)->setsampwent = mysqlsam_setsampwent; - (*pdb_method)->endsampwent = mysqlsam_endsampwent; - (*pdb_method)->getsampwent = mysqlsam_getsampwent; - (*pdb_method)->getsampwnam = mysqlsam_getsampwnam; - (*pdb_method)->getsampwsid = mysqlsam_getsampwsid; - (*pdb_method)->add_sam_account = mysqlsam_add_sam_account; - (*pdb_method)->update_sam_account = mysqlsam_update_sam_account; - (*pdb_method)->delete_sam_account = mysqlsam_delete_sam_account; - - data = talloc(pdb_context->mem_ctx, struct pdb_mysql_data); - (*pdb_method)->private_data = data; - data->handle = NULL; - data->pwent = NULL; - - if (!location) { - DEBUG(0, ("No identifier specified. Check the Samba HOWTO Collection for details\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - data->location = smb_xstrdup(location); - - DEBUG(1, - ("Connecting to database server, host: %s, user: %s, database: %s, port: %ld\n", - config_value(data, "mysql host", CONFIG_HOST_DEFAULT), - config_value(data, "mysql user", CONFIG_USER_DEFAULT), - config_value(data, "mysql database", CONFIG_DB_DEFAULT), - xatol(config_value(data, "mysql port", CONFIG_PORT_DEFAULT)))); - - /* Do the mysql initialization */ - data->handle = mysql_init(NULL); - if (!data->handle) { - DEBUG(0, ("Failed to connect to server\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - if(!sql_account_config_valid(data->location)) { - return NT_STATUS_INVALID_PARAMETER; - } - - /* Process correct entry in $HOME/.my.conf */ - if (!mysql_real_connect(data->handle, - config_value(data, "mysql host", CONFIG_HOST_DEFAULT), - config_value(data, "mysql user", CONFIG_USER_DEFAULT), - config_value(data, "mysql password", CONFIG_PASS_DEFAULT), - config_value(data, "mysql database", CONFIG_DB_DEFAULT), - xatol(config_value (data, "mysql port", CONFIG_PORT_DEFAULT)), - NULL, 0)) { - DEBUG(0, - ("Failed to connect to mysql database: error: %s\n", - mysql_error(data->handle))); - return NT_STATUS_UNSUCCESSFUL; - } - - DEBUG(5, ("Connected to mysql db\n")); - - return NT_STATUS_OK; -} - -NTSTATUS pdb_mysql_init(void) -{ - return smb_register_passdb(PASSDB_INTERFACE_VERSION, "mysql", mysqlsam_init); -} diff --git a/source/passdb/pdb_nds.c b/source/passdb/pdb_nds.c index cf2d1d7c8a8..a82f4e48d4e 100644 --- a/source/passdb/pdb_nds.c +++ b/source/passdb/pdb_nds.c @@ -741,7 +741,7 @@ int pdb_nds_set_password( *********************************************************************/ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, - SAM_ACCOUNT *sam_acct, BOOL success) + struct samu *sam_acct, BOOL success) { struct ldapsam_privates *ldap_state; @@ -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, result); } if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { @@ -816,7 +819,7 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, rc = ldap_simple_bind_s(ld, dn, clear_text_pw); if (rc == LDAP_SUCCESS) { DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username)); - ldap_unbind_ext(ld, NULL, NULL); + ldap_unbind(ld); } else { NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION; DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username)); @@ -845,10 +848,11 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, } /********************************************************************** - Intitalise the parts of the pdb_context that are common to NDS_ldapsam modes + Intitalise the parts of the pdb_methods structuire that are common + to NDS_ldapsam modes *********************************************************************/ -static NTSTATUS pdb_init_NDS_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +static NTSTATUS pdb_init_NDS_ldapsam_common(struct pdb_methods **pdb_method, const char *location) { struct ldapsam_privates *ldap_state = (*pdb_method)->private_data; @@ -869,13 +873,13 @@ static NTSTATUS pdb_init_NDS_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHOD Initialise the 'nds compat' mode for pdb_ldap *********************************************************************/ -static NTSTATUS pdb_init_NDS_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +static NTSTATUS pdb_init_NDS_ldapsam_compat(struct pdb_methods **pdb_method, const char *location) { - NTSTATUS nt_status = pdb_init_ldapsam_compat(pdb_context, pdb_method, location); + NTSTATUS nt_status = pdb_init_ldapsam_compat(pdb_method, location); (*pdb_method)->name = "NDS_ldapsam_compat"; - pdb_init_NDS_ldapsam_common(pdb_context, pdb_method, location); + pdb_init_NDS_ldapsam_common(pdb_method, location); return nt_status; } @@ -885,13 +889,13 @@ static NTSTATUS pdb_init_NDS_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHOD Initialise the 'nds' normal mode for pdb_ldap *********************************************************************/ -static NTSTATUS pdb_init_NDS_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +static NTSTATUS pdb_init_NDS_ldapsam(struct pdb_methods **pdb_method, const char *location) { - NTSTATUS nt_status = pdb_init_ldapsam(pdb_context, pdb_method, location); + NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location); (*pdb_method)->name = "NDS_ldapsam"; - pdb_init_NDS_ldapsam_common(pdb_context, pdb_method, location); + pdb_init_NDS_ldapsam_common(pdb_method, location); return nt_status; } diff --git a/source/passdb/pdb_pgsql.c b/source/passdb/pdb_pgsql.c deleted file mode 100644 index 196fe8f855d..00000000000 --- a/source/passdb/pdb_pgsql.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * PostgresSQL password backend for samba - * Copyright (C) Hamish Friedlander 2003 - * Copyright (C) Jelmer Vernooij 2004 - * - * 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" -#include <libpq-fe.h> - -#define CONFIG_HOST_DEFAULT "localhost" -#define CONFIG_USER_DEFAULT "samba" -#define CONFIG_PASS_DEFAULT "" -#define CONFIG_PORT_DEFAULT "5432" -#define CONFIG_DB_DEFAULT "samba" - -/* handles for doing db transactions */ -typedef struct pdb_pgsql_data { - PGconn *master_handle ; - PGconn *handle ; - - PGresult *pwent ; - long currow ; - const char *db ; - const char *host ; - const char *port ; - const char *user ; - const char *pass ; - - const char *location ; -} pdb_pgsql_data ; - -struct pdb_context *the_pdb_context; - -#define SET_DATA(data,methods) { \ - if(!methods){ \ - DEBUG(0, ("invalid methods!\n")); \ - return NT_STATUS_INVALID_PARAMETER; \ - } \ - data = (struct pdb_pgsql_data *)methods->private_data; \ -} - - -#define SET_DATA_QUIET(data,methods) { \ - if(!methods){ \ - DEBUG(0, ("invalid methods!\n")); \ - return ; \ - } \ - data = (struct pdb_pgsql_data *)methods->private_data; \ -} - - -#define config_value( data, name, default_value ) \ - lp_parm_const_string( GLOBAL_SECTION_SNUM, (data)->location, name, default_value ) - -static PGconn *pgsqlsam_connect( struct pdb_pgsql_data *data ) -{ - PGconn *handle; - - DEBUG - ( - 1, - ( - "Connecting to database server, host: %s, user: %s, password: XXXXXX, database: %s, port: %s\n", - data->host, data->user, data->db, data->port - ) - ) ; - - /* Do the pgsql initialization */ - handle = PQsetdbLogin( - data->host, - data->port, - NULL, - NULL, - data->db, - data->user, - data->pass - ) ; - - if ( handle != NULL && PQstatus( handle ) != CONNECTION_OK ) - { - DEBUG( 0, ("Failed to connect to pgsql database: error: %s\n", - (handle != NULL ? PQerrorMessage( handle ) : "")) ) ; - return NULL; - } - - DEBUG( 5, ("Connected to pgsql database\n") ) ; - return handle; -} - -/* The assumption here is that the master process will get connection 0, - * and all the renaining ones just one connection for their etire life span. - */ -static PGconn *choose_connection( struct pdb_pgsql_data *data ) -{ - if ( data->master_handle == NULL ) - { - data->master_handle = pgsqlsam_connect( data ); - return data->master_handle ; - } - - /* Master connection != NULL, so we are just another process. */ - - /* If we didn't connect yet, do it now. */ - if ( data->handle == NULL ) - { - data->handle = pgsqlsam_connect( data ); - } - - return data->handle ; -} - -static long PQgetlong( PGresult *r, long row, long col ) -{ - if ( PQgetisnull( r, row, col ) ) return 0 ; - - return atol( PQgetvalue( r, row, col ) ) ; -} - -static NTSTATUS row_to_sam_account ( PGresult *r, long row, SAM_ACCOUNT *u ) -{ - pstring temp ; - DOM_SID sid ; - unsigned char *hours ; - size_t hours_len = 0 ; - - if ( row >= PQntuples( r ) ) return NT_STATUS_INVALID_PARAMETER ; - - pdb_set_logon_time ( u, PQgetlong ( r, row, 0 ), PDB_SET ) ; - pdb_set_logoff_time ( u, PQgetlong ( r, row, 1 ), PDB_SET ) ; - pdb_set_kickoff_time ( u, PQgetlong ( r, row, 2 ), PDB_SET ) ; - pdb_set_pass_last_set_time ( u, PQgetlong ( r, row, 3 ), PDB_SET ) ; - pdb_set_pass_can_change_time ( u, PQgetlong ( r, row, 4 ), PDB_SET ) ; - pdb_set_pass_must_change_time( u, PQgetlong ( r, row, 5 ), PDB_SET ) ; - pdb_set_username ( u, PQgetvalue( r, row, 6 ), PDB_SET ) ; - pdb_set_domain ( u, PQgetvalue( r, row, 7 ), PDB_SET ) ; - pdb_set_nt_username ( u, PQgetvalue( r, row, 8 ), PDB_SET ) ; - pdb_set_fullname ( u, PQgetvalue( r, row, 9 ), PDB_SET ) ; - pdb_set_homedir ( u, PQgetvalue( r, row, 10 ), PDB_SET ) ; - pdb_set_dir_drive ( u, PQgetvalue( r, row, 11 ), PDB_SET ) ; - pdb_set_logon_script ( u, PQgetvalue( r, row, 12 ), PDB_SET ) ; - pdb_set_profile_path ( u, PQgetvalue( r, row, 13 ), PDB_SET ) ; - pdb_set_acct_desc ( u, PQgetvalue( r, row, 14 ), PDB_SET ) ; - pdb_set_workstations ( u, PQgetvalue( r, row, 15 ), PDB_SET ) ; - pdb_set_unknown_str ( u, PQgetvalue( r, row, 16 ), PDB_SET ) ; - pdb_set_munged_dial ( u, PQgetvalue( r, row, 17 ), PDB_SET ) ; - - pdb_set_acct_ctrl ( u, PQgetlong ( r, row, 23 ), PDB_SET ) ; - pdb_set_logon_divs ( u, PQgetlong ( r, row, 24 ), PDB_SET ) ; - pdb_set_hours_len ( u, PQgetlong ( r, row, 25 ), PDB_SET ) ; - pdb_set_bad_password_count ( u, PQgetlong ( r, row, 26 ), PDB_SET ) ; - pdb_set_logon_count ( u, PQgetlong ( r, row, 27 ), PDB_SET ) ; - pdb_set_unknown_6 ( u, PQgetlong ( r, row, 28 ), PDB_SET ) ; - hours = PQgetvalue ( r, row, 29 ); - if ( hours != NULL ) { - hours = PQunescapeBytea ( hours, &hours_len ) ; - if ( hours_len > 0 ) - pdb_set_hours ( u, hours, PDB_SET ) ; - free ( hours ); - } - - if ( !PQgetisnull( r, row, 18 ) ) { - string_to_sid( &sid, PQgetvalue( r, row, 18 ) ) ; - pdb_set_user_sid ( u, &sid, PDB_SET ) ; - } - - if ( !PQgetisnull( r, row, 19 ) ) { - string_to_sid( &sid, PQgetvalue( r, row, 19 ) ) ; - pdb_set_group_sid( u, &sid, PDB_SET ) ; - } - - if ( pdb_gethexpwd( PQgetvalue( r, row, 20 ), temp ), PDB_SET ) pdb_set_lanman_passwd( u, temp, PDB_SET ) ; - if ( pdb_gethexpwd( PQgetvalue( r, row, 21 ), temp ), PDB_SET ) pdb_set_nt_passwd ( u, temp, PDB_SET ) ; - - /* Only use plaintext password storage when lanman and nt are NOT used */ - if ( PQgetisnull( r, row, 20 ) || PQgetisnull( r, row, 21 ) ) pdb_set_plaintext_passwd( u, PQgetvalue( r, row, 22 ) ) ; - - return NT_STATUS_OK ; -} - -static NTSTATUS pgsqlsam_setsampwent(struct pdb_methods *methods, BOOL update, uint16 acb_mask) -{ - struct pdb_pgsql_data *data ; - PGconn *handle ; - char *query ; - NTSTATUS retval ; - - SET_DATA( data, methods ) ; - - /* Connect to the DB. */ - handle = choose_connection( data ); - if ( handle == NULL ) - return NT_STATUS_UNSUCCESSFUL ; - DEBUG( 5, ("CONNECTING pgsqlsam_setsampwent\n") ) ; - - query = sql_account_query_select(NULL, data->location, update, SQL_SEARCH_NONE, NULL); - - /* Do it */ - DEBUG( 5, ("Executing query %s\n", query) ) ; - data->pwent = PQexec( handle, query ) ; - data->currow = 0 ; - - /* Result? */ - if ( data->pwent == NULL ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ; - retval = NT_STATUS_UNSUCCESSFUL ; - } - else if ( PQresultStatus( data->pwent ) != PGRES_TUPLES_OK ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( data->pwent ) ) ) ; - retval = NT_STATUS_UNSUCCESSFUL ; - } - else - { - DEBUG( 5, ("pgsqlsam_setsampwent succeeded(%d results)!\n", PQntuples(data->pwent)) ) ; - retval = NT_STATUS_OK ; - } - - talloc_free(query); - return retval ; -} - -/*************************************************************** - End enumeration of the passwd list. - ****************************************************************/ - -static void pgsqlsam_endsampwent(struct pdb_methods *methods) -{ - struct pdb_pgsql_data *data ; - - SET_DATA_QUIET( data, methods ) ; - - if (data->pwent != NULL) - { - PQclear( data->pwent ) ; - } - - data->pwent = NULL ; - data->currow = 0 ; - - DEBUG( 5, ("pgsql_endsampwent called\n") ) ; -} - -/***************************************************************** - Get one SAM_ACCOUNT from the list (next in line) - *****************************************************************/ - -static NTSTATUS pgsqlsam_getsampwent( struct pdb_methods *methods, SAM_ACCOUNT *user ) -{ - struct pdb_pgsql_data *data; - NTSTATUS retval ; - - SET_DATA( data, methods ) ; - - if ( data->pwent == NULL ) - { - DEBUG( 0, ("invalid pwent\n") ) ; - return NT_STATUS_INVALID_PARAMETER ; - } - - retval = row_to_sam_account( data->pwent, data->currow, user ) ; - data->currow++ ; - - return retval ; -} - -static NTSTATUS pgsqlsam_select_by_field ( struct pdb_methods *methods, SAM_ACCOUNT *user, enum sql_search_field field, const char *sname ) -{ - struct pdb_pgsql_data *data ; - PGconn *handle ; - - char *esc ; - char *query ; - - PGresult *result ; - NTSTATUS retval ; - - SET_DATA(data, methods); - - if ( user == NULL ) - { - DEBUG( 0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n") ) ; - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG( 5, ("pgsqlsam_select_by_field: getting data where %d = %s(nonescaped)\n", field, sname) ) ; - - /* Escape sname */ - esc = talloc_array(NULL, char, strlen(sname) * 2 + 1); - if ( !esc ) - { - DEBUG(0, ("Can't allocate memory to store escaped name\n")); - return NT_STATUS_NO_MEMORY; - } - - //tmp_sname = smb_xstrdup(sname); - PQescapeString( esc, sname, strlen(sname) ) ; - - /* Connect to the DB. */ - handle = choose_connection( data ); - if ( handle == NULL ) - return NT_STATUS_UNSUCCESSFUL ; - - query = sql_account_query_select(NULL, data->location, True, field, esc); - - /* Do it */ - DEBUG( 5, ("Executing query %s\n", query) ) ; - result = PQexec( handle, query ) ; - - /* Result? */ - if ( result == NULL ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ; - retval = NT_STATUS_UNSUCCESSFUL ; - } - else if ( PQresultStatus( result ) != PGRES_TUPLES_OK ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ; - retval = NT_STATUS_UNSUCCESSFUL ; - } - else - { - retval = row_to_sam_account( result, 0, user ) ; - } - - talloc_free( esc ) ; - talloc_free( query ) ; - - if ( result != NULL ) - PQclear( result ) ; - - return retval ; -} - -/****************************************************************** - Lookup a name in the SAM database - ******************************************************************/ - -static NTSTATUS pgsqlsam_getsampwnam ( struct pdb_methods *methods, SAM_ACCOUNT *user, const char *sname ) -{ - struct pdb_pgsql_data *data; - size_t i, l; - char *lowercasename; - NTSTATUS result; - - SET_DATA(data, methods); - - if ( !sname ) - { - DEBUG( 0, ("invalid name specified") ) ; - return NT_STATUS_INVALID_PARAMETER; - } - - lowercasename = smb_xstrdup(sname); - l = strlen(lowercasename); - for(i = 0; i < l; i++) { - lowercasename[i] = tolower_ascii(lowercasename[i]); - } - - result = pgsqlsam_select_by_field( methods, user, SQL_SEARCH_USER_NAME, lowercasename ) ; - - SAFE_FREE( lowercasename ) ; - - return result; -} - - -/*************************************************************************** - Search by sid - **************************************************************************/ - -static NTSTATUS pgsqlsam_getsampwsid ( struct pdb_methods *methods, SAM_ACCOUNT *user, const DOM_SID *sid ) -{ - struct pdb_pgsql_data *data; - fstring sid_str; - - SET_DATA( data, methods ) ; - - sid_to_string( sid_str, sid ) ; - - return pgsqlsam_select_by_field( methods, user, SQL_SEARCH_USER_SID, sid_str ) ; -} - -/*************************************************************************** - Delete a SAM_ACCOUNT - ****************************************************************************/ - -static NTSTATUS pgsqlsam_delete_sam_account( struct pdb_methods *methods, SAM_ACCOUNT *sam_pass ) -{ - struct pdb_pgsql_data *data ; - PGconn *handle ; - - const char *sname = pdb_get_username( sam_pass ) ; - char *esc ; - char *query ; - - PGresult *result ; - NTSTATUS retval ; - - SET_DATA(data, methods); - - if ( !sname ) - { - DEBUG( 0, ("invalid name specified\n") ) ; - return NT_STATUS_INVALID_PARAMETER ; - } - - /* Escape sname */ - esc = talloc_array(NULL, char, strlen(sname) * 2 + 1); - if ( !esc ) - { - DEBUG(0, ("Can't allocate memory to store escaped name\n")); - return NT_STATUS_NO_MEMORY; - } - - PQescapeString( esc, sname, strlen(sname) ) ; - - /* Connect to the DB. */ - handle = choose_connection( data ); - if ( handle == NULL ) - return NT_STATUS_UNSUCCESSFUL ; - - query = sql_account_query_delete(NULL, data->location, esc); - - /* Do it */ - result = PQexec( handle, query ) ; - - if ( result == NULL ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ; - retval = NT_STATUS_UNSUCCESSFUL ; - } - else if ( PQresultStatus( result ) != PGRES_COMMAND_OK ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ; - retval = NT_STATUS_UNSUCCESSFUL ; - } - else - { - DEBUG( 5, ("User '%s' deleted\n", sname) ) ; - retval = NT_STATUS_OK ; - } - - if ( result != NULL ) - PQclear( result ) ; - talloc_free( esc ) ; - talloc_free( query ) ; - - return retval ; -} - -static NTSTATUS pgsqlsam_replace_sam_account( struct pdb_methods *methods, const SAM_ACCOUNT *newpwd, char isupdate ) -{ - struct pdb_pgsql_data *data ; - PGconn *handle ; - char *query; - PGresult *result ; - NTSTATUS retval ; - - if ( !methods ) - { - DEBUG( 0, ("invalid methods!\n") ) ; - return NT_STATUS_INVALID_PARAMETER ; - } - - data = (struct pdb_pgsql_data *) methods->private_data ; - - if ( data == NULL || handle == NULL ) - { - DEBUG( 0, ("invalid handle!\n") ) ; - return NT_STATUS_INVALID_HANDLE ; - } - - query = sql_account_query_update(NULL, data->location, newpwd, isupdate); - if ( query == NULL ) /* Nothing to update. */ - return NT_STATUS_OK; - - /* Connect to the DB. */ - handle = choose_connection( data ); - if ( handle == NULL ) - return NT_STATUS_UNSUCCESSFUL ; - - result = PQexec( handle, query ) ; - - /* Execute the query */ - if ( result == NULL ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ; - retval = NT_STATUS_INVALID_PARAMETER; - } - else if ( PQresultStatus( result ) != PGRES_COMMAND_OK ) - { - DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ; - retval = NT_STATUS_INVALID_PARAMETER; - } - else - { - retval = NT_STATUS_OK; - } - if ( result != NULL ) - PQclear( result ) ; - talloc_free(query); - - return retval; -} - -static NTSTATUS pgsqlsam_add_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd ) -{ - return pgsqlsam_replace_sam_account( methods, newpwd, 0 ) ; -} - -static NTSTATUS pgsqlsam_update_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd ) -{ - return pgsqlsam_replace_sam_account( methods, newpwd, 1 ) ; -} - -static NTSTATUS pgsqlsam_init ( struct pdb_context *pdb_context, struct pdb_methods **pdb_method, const char *location ) -{ - NTSTATUS nt_status ; - struct pdb_pgsql_data *data ; - - if ( !pdb_context ) - { - DEBUG( 0, ("invalid pdb_methods specified\n") ) ; - return NT_STATUS_UNSUCCESSFUL; - } - - the_pdb_context = pdb_context; - - if (!NT_STATUS_IS_OK - (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { - return nt_status; - } - - (*pdb_method)->name = "pgsqlsam" ; - - (*pdb_method)->setsampwent = pgsqlsam_setsampwent ; - (*pdb_method)->endsampwent = pgsqlsam_endsampwent ; - (*pdb_method)->getsampwent = pgsqlsam_getsampwent ; - (*pdb_method)->getsampwnam = pgsqlsam_getsampwnam ; - (*pdb_method)->getsampwsid = pgsqlsam_getsampwsid ; - (*pdb_method)->add_sam_account = pgsqlsam_add_sam_account ; - (*pdb_method)->update_sam_account = pgsqlsam_update_sam_account ; - (*pdb_method)->delete_sam_account = pgsqlsam_delete_sam_account ; - - data = talloc( pdb_context->mem_ctx, struct pdb_pgsql_data ) ; - (*pdb_method)->private_data = data ; - - data->master_handle = NULL; - data->handle = NULL; - data->pwent = NULL ; - - if ( !location ) - { - DEBUG( 0, ("No identifier specified. Check the Samba HOWTO Collection for details\n") ) ; - return NT_STATUS_INVALID_PARAMETER; - } - - data->location = smb_xstrdup( location ) ; - - if(!sql_account_config_valid(data->location)) { - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG - ( - 1, - ( - "Database server parameters: host: %s, user: %s, password: XXXX, database: %s, port: %s\n", - config_value( data, "pgsql host" , CONFIG_HOST_DEFAULT ), - config_value( data, "pgsql user" , CONFIG_USER_DEFAULT ), - config_value( data, "pgsql database", CONFIG_DB_DEFAULT ), - config_value( data, "pgsql port" , CONFIG_PORT_DEFAULT ) - ) - ) ; - - /* Save the parameters. */ - data->db = config_value( data, "pgsql database", CONFIG_DB_DEFAULT ); - data->host = config_value( data, "pgsql host" , CONFIG_HOST_DEFAULT ); - data->port = config_value( data, "pgsql port" , CONFIG_PORT_DEFAULT ); - data->user = config_value( data, "pgsql user" , CONFIG_USER_DEFAULT ); - data->pass = config_value( data, "pgsql password", CONFIG_PASS_DEFAULT ); - - DEBUG( 5, ("Pgsql module intialized\n") ) ; - return NT_STATUS_OK; -} - -NTSTATUS pdb_pgsql_init(void) -{ - return smb_register_passdb( PASSDB_INTERFACE_VERSION, "pgsql", pgsqlsam_init ) ; -} diff --git a/source/passdb/pdb_plugin.c b/source/passdb/pdb_plugin.c index 027cd0b5d33..9d835a48ad3 100644 --- a/source/passdb/pdb_plugin.c +++ b/source/passdb/pdb_plugin.c @@ -24,7 +24,7 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_PASSDB -NTSTATUS pdb_init_plugin(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +NTSTATUS pdb_init_plugin(struct pdb_methods **pdb_method, const char *location) { void * dl_handle; char *plugin_location, *plugin_name, *p; @@ -76,5 +76,5 @@ NTSTATUS pdb_init_plugin(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, con } DEBUG(5, ("Starting sam plugin %s with location %s\n", plugin_name, plugin_location)); - return plugin_init(pdb_context, pdb_method, plugin_location); + return plugin_init(pdb_method, plugin_location); } diff --git a/source/passdb/pdb_smbpasswd.c b/source/passdb/pdb_smbpasswd.c index 487df96e953..b976595008a 100644 --- a/source/passdb/pdb_smbpasswd.c +++ b/source/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 */ @@ -1143,12 +1137,12 @@ Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); } /********************************************************************* - Create a smb_passwd struct from a SAM_ACCOUNT. + Create a smb_passwd struct from a struct samu. We will not allocate any new memory. The smb_passwd struct - should only stay around as long as the SAM_ACCOUNT does. + should only stay around as long as the struct samu does. ********************************************************************/ -static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass) +static BOOL build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass) { uint32 rid; @@ -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 { @@ -1189,31 +1182,31 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas } /********************************************************************* - Create a SAM_ACCOUNT from a smb_passwd struct + Create a struct samu from a smb_passwd struct ********************************************************************/ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, - SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf) + struct samu *sam_pass, const struct smb_passwd *pw_buf) { struct passwd *pwfile; - if (sam_pass==NULL) { - DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n")); + if ( !sam_pass ) { + DEBUG(5,("build_sam_account: struct samu is NULL\n")); return False; } /* 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; } - if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) + if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) ) return False; - passwd_free(&pwfile); + TALLOC_FREE(pwfile); /* set remaining fields */ @@ -1230,7 +1223,7 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, Functions to be implemented by the new passdb API ****************************************************************/ -static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update, uint16 acb_mask) +static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update, uint32 acb_mask) { struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; @@ -1270,19 +1263,17 @@ static void smbpasswd_endsampwent (struct pdb_methods *my_methods) /***************************************************************** ****************************************************************/ -static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user) +static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, struct samu *user) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; struct smb_passwd *pw_buf=NULL; BOOL done = False; + DEBUG(5,("pdb_getsampwent\n")); - if (user==NULL) { + if ( !user ) { DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n")); -#if 0 - smb_panic("NULL pointer passed to getsampwent (smbpasswd)\n"); -#endif return nt_status; } @@ -1292,7 +1283,7 @@ static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUN if (pw_buf == NULL) return nt_status; - /* build the SAM_ACCOUNT entry from the smb_passwd struct. + /* build the struct samu entry from the smb_passwd struct. We loop in case the user in the pdb does not exist in the local system password file */ if (build_sam_account(smbpasswd_state, user, pw_buf)) @@ -1312,7 +1303,7 @@ static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUN ***************************************************************/ static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, - SAM_ACCOUNT *sam_acct, const char *username) + struct samu *sam_acct, const char *username) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; @@ -1344,14 +1335,11 @@ static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name)); if (!sam_acct) { - DEBUG(10,("getsampwnam (smbpasswd): SAM_ACCOUNT is NULL\n")); -#if 0 - smb_panic("NULL pointer passed to pdb_getsampwnam\n"); -#endif + DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n")); return nt_status; } - /* now build the SAM_ACCOUNT */ + /* now build the struct samu */ if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw)) return nt_status; @@ -1359,7 +1347,7 @@ static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, return NT_STATUS_OK; } -static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_acct, const DOM_SID *sid) +static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const DOM_SID *sid) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; @@ -1404,14 +1392,11 @@ static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUN DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name)); if (!sam_acct) { - DEBUG(10,("getsampwrid: (smbpasswd) SAM_ACCOUNT is NULL\n")); -#if 0 - smb_panic("NULL pointer passed to pdb_getsampwrid\n"); -#endif + DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n")); return nt_status; } - /* now build the SAM_ACCOUNT */ + /* now build the struct samu */ if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw)) return nt_status; @@ -1427,12 +1412,12 @@ static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUN return NT_STATUS_OK; } -static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass) +static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass) { struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; struct smb_passwd smb_pw; - /* convert the SAM_ACCOUNT */ + /* convert the struct samu */ if (!build_smb_pass(&smb_pw, sampass)) { return NT_STATUS_UNSUCCESSFUL; } @@ -1445,12 +1430,12 @@ static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, SAM_AC return NT_STATUS_OK; } -static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass) +static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass) { struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; struct smb_passwd smb_pw; - /* convert the SAM_ACCOUNT */ + /* convert the struct samu */ if (!build_smb_pass(&smb_pw, sampass)) { DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n")); return NT_STATUS_UNSUCCESSFUL; @@ -1465,7 +1450,7 @@ static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, SAM return NT_STATUS_OK; } -static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *sampass) +static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass) { struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; @@ -1478,21 +1463,27 @@ static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, SA } static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods, - SAM_ACCOUNT *old_acct, + struct samu *old_acct, const char *newname) { pstring rename_script; - SAM_ACCOUNT *new_acct = NULL; + struct samu *new_acct = NULL; BOOL interim_account = False; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; if (!*(lp_renameuser_script())) goto done; - if (!pdb_copy_sam_account(old_acct, &new_acct) || - !pdb_set_username(new_acct, newname, PDB_CHANGED)) + if ( !(new_acct = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } + + if ( !pdb_copy_sam_account( new_acct, old_acct ) + || !pdb_set_username(new_acct, newname, PDB_CHANGED)) + { goto done; - + } + ret = smbpasswd_add_sam_account(my_methods, new_acct); if (!NT_STATUS_IS_OK(ret)) goto done; @@ -1505,9 +1496,11 @@ static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods, if (*rename_script) { int rename_ret; - pstring_sub(rename_script, "%unew", newname); - pstring_sub(rename_script, "%uold", - pdb_get_username(old_acct)); + string_sub2(rename_script, "%unew", newname, sizeof(pstring), + True, False, True); + string_sub2(rename_script, "%uold", pdb_get_username(old_acct), + sizeof(pstring), True, False, True); + rename_ret = smbrun(rename_script, NULL); DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret)); @@ -1527,11 +1520,16 @@ done: smbpasswd_delete_sam_account(my_methods, new_acct); if (new_acct) - pdb_free_sam(&new_acct); + TALLOC_FREE(new_acct); 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; @@ -1542,12 +1540,12 @@ static void free_private_data(void **vp) /* No need to free any further, as it is talloc()ed */ } -static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) +static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location ) { NTSTATUS nt_status; struct smbpasswd_privates *privates; - if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { + if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) { return nt_status; } @@ -1563,11 +1561,11 @@ 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; - /* Setup private data and free function */ + (*pdb_method)->rid_algorithm = smbpasswd_rid_algorithm; - privates = TALLOC_ZERO_P(pdb_context->mem_ctx, struct smbpasswd_privates); + /* Setup private data and free function */ - if (!privates) { + if ( !(privates = TALLOC_ZERO_P( *pdb_method, struct smbpasswd_privates )) ) { DEBUG(0, ("talloc() failed for smbpasswd private_data!\n")); return NT_STATUS_NO_MEMORY; } @@ -1575,9 +1573,9 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m /* Store some config details */ if (location) { - privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, location); + privates->smbpasswd_file = talloc_strdup(*pdb_method, location); } else { - privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, lp_smb_passwd_file()); + privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file()); } if (!privates->smbpasswd_file) { diff --git a/source/passdb/pdb_sql.c b/source/passdb/pdb_sql.c deleted file mode 100644 index f4f6e0112ae..00000000000 --- a/source/passdb/pdb_sql.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Common PDB SQL backend functions - * Copyright (C) Jelmer Vernooij 2003-2004 - * - * 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" - -#define CONFIG_TABLE_DEFAULT "user" -#define CONFIG_LOGON_TIME_DEFAULT "logon_time" -#define CONFIG_LOGOFF_TIME_DEFAULT "logoff_time" -#define CONFIG_KICKOFF_TIME_DEFAULT "kickoff_time" -#define CONFIG_PASS_LAST_SET_TIME_DEFAULT "pass_last_set_time" -#define CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT "pass_can_change_time" -#define CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT "pass_must_change_time" -#define CONFIG_USERNAME_DEFAULT "username" -#define CONFIG_DOMAIN_DEFAULT "domain" -#define CONFIG_NT_USERNAME_DEFAULT "nt_username" -#define CONFIG_FULLNAME_DEFAULT "nt_fullname" -#define CONFIG_HOME_DIR_DEFAULT "home_dir" -#define CONFIG_DIR_DRIVE_DEFAULT "dir_drive" -#define CONFIG_LOGON_SCRIPT_DEFAULT "logon_script" -#define CONFIG_PROFILE_PATH_DEFAULT "profile_path" -#define CONFIG_ACCT_DESC_DEFAULT "acct_desc" -#define CONFIG_WORKSTATIONS_DEFAULT "workstations" -#define CONFIG_UNKNOWN_STR_DEFAULT "unknown_str" -#define CONFIG_MUNGED_DIAL_DEFAULT "munged_dial" -#define CONFIG_USER_SID_DEFAULT "user_sid" -#define CONFIG_GROUP_SID_DEFAULT "group_sid" -#define CONFIG_LM_PW_DEFAULT "lm_pw" -#define CONFIG_NT_PW_DEFAULT "nt_pw" -#define CONFIG_PLAIN_PW_DEFAULT "NULL" -#define CONFIG_ACCT_CTRL_DEFAULT "acct_ctrl" -#define CONFIG_LOGON_DIVS_DEFAULT "logon_divs" -#define CONFIG_HOURS_LEN_DEFAULT "hours_len" -#define CONFIG_BAD_PASSWORD_COUNT_DEFAULT "bad_password_count" -#define CONFIG_LOGON_COUNT_DEFAULT "logon_count" -#define CONFIG_UNKNOWN_6_DEFAULT "unknown_6" -#define CONFIG_LOGON_HOURS "logon_hours" - -/* Used to construct insert and update queries */ - -typedef struct pdb_sql_query { - char update; - char *part1; - char *part2; -} pdb_sql_query; - -static void pdb_sql_int_field(struct pdb_sql_query *q, const char *name, int value) -{ - if (!name || strchr(name, '\'')) - return; /* This field shouldn't be set by us */ - - if (q->update) { - q->part1 = - talloc_asprintf_append(q->part1, - "%s = %d,", name, value); - } else { - q->part1 = - talloc_asprintf_append(q->part1, "%s,", name); - q->part2 = - talloc_asprintf_append(q->part2, "%d,", value); - } -} - -char *sql_escape_string(TALLOC_CTX *mem_ctx, const char *unesc) -{ - char *esc = talloc_array(mem_ctx, char, strlen(unesc) * 2 + 3); - size_t pos_unesc = 0, pos_esc = 0; - - for(pos_unesc = 0; unesc[pos_unesc]; pos_unesc++) { - switch(unesc[pos_unesc]) { - case '\\': - case '\'': - case '"': - esc[pos_esc] = '\\'; pos_esc++; - default: - esc[pos_esc] = unesc[pos_unesc]; pos_esc++; - break; - } - } - - esc[pos_esc] = '\0'; - - return esc; -} - -static NTSTATUS pdb_sql_string_field(struct pdb_sql_query *q, - const char *name, const char *value) -{ - char *esc_value; - - if (!name || !value || !strcmp(value, "") || strchr(name, '\'')) - return NT_STATUS_INVALID_PARAMETER; /* This field shouldn't be set by module */ - - esc_value = sql_escape_string(q, value); - - if (q->update) { - q->part1 = - talloc_asprintf_append(q->part1, - "%s = '%s',", name, esc_value); - } else { - q->part1 = - talloc_asprintf_append(q->part1, "%s,", name); - q->part2 = - talloc_asprintf_append(q->part2, "'%s',", - esc_value); - } - - talloc_free(esc_value); - - return NT_STATUS_OK; -} - -#define config_value(data,name,default_value) \ - lp_parm_const_string(GLOBAL_SECTION_SNUM, data, name, default_value) - -static const char * config_value_write(const char *location, const char *name, const char *default_value) -{ - char const *v = NULL; - char const *swrite = NULL; - - v = lp_parm_const_string(GLOBAL_SECTION_SNUM, location, name, default_value); - - if (!v) - return NULL; - - swrite = strrchr(v, ':'); - - /* Default to the same field as read field */ - if (!swrite) { - - /* Updating NULL does not make much sense */ - if (!strcmp(v, "NULL")) - return NULL; - - return v; - } - - swrite++; - - /* If the field is 0 chars long, we shouldn't write to it */ - if (!strlen(swrite) || !strcmp(swrite, "NULL")) - return NULL; - - /* Otherwise, use the additionally specified */ - return swrite; -} - -static const char * config_value_read(const char *location, const char *name, const char *default_value) -{ - char *v = NULL; - char *swrite; - - v = lp_parm_talloc_string(GLOBAL_SECTION_SNUM, location, name, default_value); - - if (!v) - return "NULL"; - - swrite = strrchr(v, ':'); - - /* If no write is specified, there are no problems */ - if (!swrite) { - if (strlen(v) == 0) - return "NULL"; - return (const char *)v; - } - - /* Otherwise, we have to cut the ':write_part' */ - *swrite = '\0'; - if (strlen(v) == 0) - return "NULL"; - - return (const char *)v; -} - -char *sql_account_query_select(TALLOC_CTX *mem_ctx, const char *data, BOOL update, enum sql_search_field field, const char *value) -{ - const char *field_string; - char *query; - - switch(field) { - case SQL_SEARCH_NONE: - field_string = "'1'"; - value = "1"; - break; - - case SQL_SEARCH_USER_SID: - field_string = config_value_read(data, "user sid column", - CONFIG_USER_SID_DEFAULT); - break; - - case SQL_SEARCH_USER_NAME: - field_string = config_value_read(data, "username column", - CONFIG_USERNAME_DEFAULT); - break; - default: - field_string = "unknown"; - break; - } - - query = talloc_asprintf(mem_ctx, - "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s WHERE %s = '%s'", - config_value_read(data, "logon time column", - CONFIG_LOGON_TIME_DEFAULT), - config_value_read(data, "logoff time column", - CONFIG_LOGOFF_TIME_DEFAULT), - config_value_read(data, "kickoff time column", - CONFIG_KICKOFF_TIME_DEFAULT), - config_value_read(data, "pass last set time column", - CONFIG_PASS_LAST_SET_TIME_DEFAULT), - config_value_read(data, "pass can change time column", - CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT), - config_value_read(data, "pass must change time column", - CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT), - config_value_read(data, "username column", - CONFIG_USERNAME_DEFAULT), - config_value_read(data, "domain column", - CONFIG_DOMAIN_DEFAULT), - config_value_read(data, "nt username column", - CONFIG_NT_USERNAME_DEFAULT), - config_value_read(data, "fullname column", - CONFIG_FULLNAME_DEFAULT), - config_value_read(data, "home dir column", - CONFIG_HOME_DIR_DEFAULT), - config_value_read(data, "dir drive column", - CONFIG_DIR_DRIVE_DEFAULT), - config_value_read(data, "logon script column", - CONFIG_LOGON_SCRIPT_DEFAULT), - config_value_read(data, "profile path column", - CONFIG_PROFILE_PATH_DEFAULT), - config_value_read(data, "acct desc column", - CONFIG_ACCT_DESC_DEFAULT), - config_value_read(data, "workstations column", - CONFIG_WORKSTATIONS_DEFAULT), - config_value_read(data, "unknown string column", - CONFIG_UNKNOWN_STR_DEFAULT), - config_value_read(data, "munged dial column", - CONFIG_MUNGED_DIAL_DEFAULT), - config_value_read(data, "user sid column", - CONFIG_USER_SID_DEFAULT), - config_value_read(data, "group sid column", - CONFIG_GROUP_SID_DEFAULT), - config_value_read(data, "lanman pass column", - CONFIG_LM_PW_DEFAULT), - config_value_read(data, "nt pass column", - CONFIG_NT_PW_DEFAULT), - config_value_read(data, "plain pass column", - CONFIG_PLAIN_PW_DEFAULT), - config_value_read(data, "acct ctrl column", - CONFIG_ACCT_CTRL_DEFAULT), - config_value_read(data, "logon divs column", - CONFIG_LOGON_DIVS_DEFAULT), - config_value_read(data, "hours len column", - CONFIG_HOURS_LEN_DEFAULT), - config_value_read(data, "bad password count column", - CONFIG_BAD_PASSWORD_COUNT_DEFAULT), - config_value_read(data, "logon count column", - CONFIG_LOGON_COUNT_DEFAULT), - config_value_read(data, "unknown 6 column", - CONFIG_UNKNOWN_6_DEFAULT), - config_value_read(data, "logon hours column", - CONFIG_LOGON_HOURS), - config_value(data, "table", CONFIG_TABLE_DEFAULT), - field_string, value - ); - return query; -} - -char *sql_account_query_delete(TALLOC_CTX *mem_ctx, const char *data, const char *esc) -{ - char *query; - - query = talloc_asprintf(mem_ctx, "DELETE FROM %s WHERE %s = '%s'", - config_value(data, "table", CONFIG_TABLE_DEFAULT), - config_value_read(data, "username column", - CONFIG_USERNAME_DEFAULT), esc); - return query; -} - -char *sql_account_query_update(TALLOC_CTX *mem_ctx, const char *location, const SAM_ACCOUNT *newpwd, char isupdate) -{ - char *ret; - pstring temp; - fstring sid_str; - pdb_sql_query *query; - int some_field_affected = 0; - - query = talloc(mem_ctx, pdb_sql_query); - query->update = isupdate; - - /* I know this is somewhat overkill but only the talloc - * functions have asprint_append and the 'normal' asprintf - * is a GNU extension */ - query->part2 = talloc_asprintf(query, "%s", ""); - if (query->update) { - query->part1 = - talloc_asprintf(query, "UPDATE %s SET ", - config_value(location, "table", - CONFIG_TABLE_DEFAULT)); - } else { - query->part1 = - talloc_asprintf(query, "INSERT INTO %s (", - config_value(location, "table", - CONFIG_TABLE_DEFAULT)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_ACCTCTRL)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, "acct ctrl column", - CONFIG_ACCT_CTRL_DEFAULT), - pdb_get_acct_ctrl(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_LOGONTIME)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "logon time column", - CONFIG_LOGON_TIME_DEFAULT), - pdb_get_logon_time(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_LOGOFFTIME)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "logoff time column", - CONFIG_LOGOFF_TIME_DEFAULT), - pdb_get_logoff_time(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_KICKOFFTIME)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "kickoff time column", - CONFIG_KICKOFF_TIME_DEFAULT), - pdb_get_kickoff_time(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_CANCHANGETIME)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "pass can change time column", - CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT), - pdb_get_pass_can_change_time(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_MUSTCHANGETIME)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "pass must change time column", - CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT), - pdb_get_pass_must_change_time(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_PASSLASTSET)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "pass last set time column", - CONFIG_PASS_LAST_SET_TIME_DEFAULT), - pdb_get_pass_last_set_time(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_HOURSLEN)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "hours len column", - CONFIG_HOURS_LEN_DEFAULT), - pdb_get_hours_len(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_LOGONDIVS)) { - some_field_affected = 1; - pdb_sql_int_field(query, - config_value_write(location, - "logon divs column", - CONFIG_LOGON_DIVS_DEFAULT), - pdb_get_logon_divs(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_USERSID)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "user sid column", - CONFIG_USER_SID_DEFAULT), - sid_to_string(sid_str, - pdb_get_user_sid(newpwd))); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_GROUPSID)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "group sid column", - CONFIG_GROUP_SID_DEFAULT), - sid_to_string(sid_str, - pdb_get_group_sid(newpwd))); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_USERNAME)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "username column", - CONFIG_USERNAME_DEFAULT), - pdb_get_username(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_DOMAIN)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "domain column", - CONFIG_DOMAIN_DEFAULT), - pdb_get_domain(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_USERNAME)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, - "nt username column", - CONFIG_NT_USERNAME_DEFAULT), - pdb_get_nt_username(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_FULLNAME)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "fullname column", - CONFIG_FULLNAME_DEFAULT), - pdb_get_fullname(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_LOGONSCRIPT)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, - "logon script column", - CONFIG_LOGON_SCRIPT_DEFAULT), - pdb_get_logon_script(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_PROFILE)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, - "profile path column", - CONFIG_PROFILE_PATH_DEFAULT), - pdb_get_profile_path(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_DRIVE)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "dir drive column", - CONFIG_DIR_DRIVE_DEFAULT), - pdb_get_dir_drive(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_SMBHOME)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, "home dir column", - CONFIG_HOME_DIR_DEFAULT), - pdb_get_homedir(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_WORKSTATIONS)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, - "workstations column", - CONFIG_WORKSTATIONS_DEFAULT), - pdb_get_workstations(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_UNKNOWNSTR)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, - "unknown string column", - CONFIG_UNKNOWN_STR_DEFAULT), - pdb_get_workstations(newpwd)); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_LMPASSWD)) { - some_field_affected = 1; - pdb_sethexpwd(temp, pdb_get_lanman_passwd(newpwd), - pdb_get_acct_ctrl(newpwd)); - pdb_sql_string_field(query, - config_value_write(location, - "lanman pass column", - CONFIG_LM_PW_DEFAULT), temp); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_NTPASSWD)) { - some_field_affected = 1; - pdb_sethexpwd(temp, pdb_get_nt_passwd(newpwd), - pdb_get_acct_ctrl(newpwd)); - pdb_sql_string_field(query, - config_value_write(location, "nt pass column", - CONFIG_NT_PW_DEFAULT), temp); - } - - if (!isupdate || IS_SAM_CHANGED(newpwd, PDB_HOURS)) { - some_field_affected = 1; - pdb_sql_string_field(query, - config_value_write(location, - "logon hours column", - CONFIG_LOGON_HOURS), - (const char *)pdb_get_hours(newpwd)); - } - - if (!some_field_affected) { - talloc_free(query); - return NULL; - } - - if (query->update) { - query->part1[strlen(query->part1) - 1] = '\0'; - query->part1 = talloc_asprintf( - mem_ctx, "%s WHERE %s = '%s'", query->part1, - config_value_read(location, - "user sid column", - CONFIG_USER_SID_DEFAULT), - sid_to_string(sid_str, pdb_get_user_sid (newpwd))); - } else { - query->part2[strlen(query->part2) - 1] = ')'; - query->part1[strlen(query->part1) - 1] = ')'; - query->part1 = - talloc_asprintf_append(query->part1, - " VALUES (%s", query->part2); - } - - ret = talloc_strdup(mem_ctx, query->part1); - talloc_free(query); - return ret; -} - -BOOL sql_account_config_valid(const char *data) -{ - const char *sid_column, *username_column; - - sid_column = config_value_read(data, "user sid column", CONFIG_USER_SID_DEFAULT); - username_column = config_value_read(data, "username column", CONFIG_USERNAME_DEFAULT); - - if(!strcmp(sid_column,"NULL") || !strcmp(username_column, "NULL")) { - DEBUG(0,("Please specify both a valid 'user sid column' and a valid 'username column' in smb.conf\n")); - return False; - } - - return True; -} diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c index de79b4096a6..ba8124d3923 100644 --- a/source/passdb/pdb_tdb.c +++ b/source/passdb/pdb_tdb.c @@ -3,7 +3,7 @@ * SMB parameters and setup * Copyright (C) Andrew Tridgell 1992-1998 * Copyright (C) Simo Sorce 2000-2003 - * Copyright (C) Gerald Carter 2000 + * Copyright (C) Gerald Carter 2000-2006 * Copyright (C) Jeremy Allison 2001 * Copyright (C) Andrew Bartlett 2002 * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005 @@ -38,60 +38,666 @@ static int tdbsam_debug_level = DBGC_ALL; #endif -#define TDBSAM_VERSION 2 /* Most recent TDBSAM version */ +#define TDBSAM_VERSION 3 /* Most recent TDBSAM version */ #define TDBSAM_VERSION_STRING "INFO/version" #define PASSDB_FILE_NAME "passdb.tdb" #define USERPREFIX "USER_" #define RIDPREFIX "RID_" #define PRIVPREFIX "PRIV_" -#define tdbsamver_t int32 - -struct tdbsam_privates { - TDB_CONTEXT *passwd_tdb; - - /* retrive-once info */ - const char *tdbsam_location; -}; struct pwent_list { struct pwent_list *prev, *next; TDB_DATA key; }; static struct pwent_list *tdbsam_pwent_list; +static BOOL pwent_initialized; + +/* GLOBAL TDB SAM CONTEXT */ + +static TDB_CONTEXT *tdbsam; +static int ref_count = 0; +static pstring tdbsam_filename; + +/********************************************************************** + Marshall/unmarshall struct samu structs. + *********************************************************************/ +#define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" +#define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" +#define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" -/** - * Convert old TDBSAM to the latest version. - * @param pdb_tdb A pointer to the opened TDBSAM file which must be converted. - * This file must be opened with read/write access. - * @param from Current version of the TDBSAM file. - * @return True if the conversion has been successful, false otherwise. - **/ +/********************************************************************* +*********************************************************************/ -static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) +static BOOL init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen) { - const char * vstring = TDBSAM_VERSION_STRING; - SAM_ACCOUNT *user = NULL; - const char *prefix = USERPREFIX; - TDB_DATA data, key, old_key; - uint8 *buf = NULL; - BOOL ret; - if (pdb_tdb == NULL) { - DEBUG(0,("tdbsam_convert: Bad TDB Context pointer.\n")); + /* times are stored as 32bit integer + take care on system with 64bit wide time_t + --SSS */ + uint32 logon_time, + logoff_time, + kickoff_time, + pass_last_set_time, + pass_can_change_time, + pass_must_change_time; + char *username = NULL; + char *domain = NULL; + char *nt_username = NULL; + char *dir_drive = NULL; + char *unknown_str = NULL; + char *munged_dial = NULL; + char *fullname = NULL; + char *homedir = NULL; + char *logon_script = NULL; + char *profile_path = NULL; + char *acct_desc = NULL; + char *workstations = NULL; + uint32 username_len, domain_len, nt_username_len, + dir_drive_len, unknown_str_len, munged_dial_len, + fullname_len, homedir_len, logon_script_len, + profile_path_len, acct_desc_len, workstations_len; + + uint32 user_rid, group_rid, remove_me, hours_len, unknown_6; + uint16 acct_ctrl, logon_divs; + uint16 bad_password_count, logon_count; + uint8 *hours = NULL; + uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL; + uint32 len = 0; + uint32 lm_pw_len, nt_pw_len, hourslen; + BOOL ret = True; + + if(sampass == NULL || buf == NULL) { + DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n")); return False; } - /* handle a Samba upgrade */ - tdb_lock_bystring(pdb_tdb, vstring, 0); +/* TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */ + + /* unpack the buffer into variables */ + len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V0, + &logon_time, /* d */ + &logoff_time, /* d */ + &kickoff_time, /* d */ + &pass_last_set_time, /* d */ + &pass_can_change_time, /* d */ + &pass_must_change_time, /* d */ + &username_len, &username, /* B */ + &domain_len, &domain, /* B */ + &nt_username_len, &nt_username, /* B */ + &fullname_len, &fullname, /* B */ + &homedir_len, &homedir, /* B */ + &dir_drive_len, &dir_drive, /* B */ + &logon_script_len, &logon_script, /* B */ + &profile_path_len, &profile_path, /* B */ + &acct_desc_len, &acct_desc, /* B */ + &workstations_len, &workstations, /* B */ + &unknown_str_len, &unknown_str, /* B */ + &munged_dial_len, &munged_dial, /* B */ + &user_rid, /* d */ + &group_rid, /* d */ + &lm_pw_len, &lm_pw_ptr, /* B */ + &nt_pw_len, &nt_pw_ptr, /* B */ + &acct_ctrl, /* w */ + &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */ + &logon_divs, /* w */ + &hours_len, /* d */ + &hourslen, &hours, /* B */ + &bad_password_count, /* w */ + &logon_count, /* w */ + &unknown_6); /* d */ + + if (len == (uint32) -1) { + ret = False; + goto done; + } + + pdb_set_logon_time(sampass, logon_time, PDB_SET); + pdb_set_logoff_time(sampass, logoff_time, PDB_SET); + pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); + pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); + pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET); + pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); + + pdb_set_username(sampass, username, PDB_SET); + pdb_set_domain(sampass, domain, PDB_SET); + pdb_set_nt_username(sampass, nt_username, PDB_SET); + pdb_set_fullname(sampass, fullname, PDB_SET); + + if (homedir) { + pdb_set_homedir(sampass, homedir, PDB_SET); + } + else { + pdb_set_homedir(sampass, + talloc_sub_basic(sampass, username, lp_logon_home()), + PDB_DEFAULT); + } + + if (dir_drive) + pdb_set_dir_drive(sampass, dir_drive, PDB_SET); + else { + pdb_set_dir_drive(sampass, + talloc_sub_basic(sampass, username, lp_logon_drive()), + PDB_DEFAULT); + } + + if (logon_script) + pdb_set_logon_script(sampass, logon_script, PDB_SET); + else { + pdb_set_logon_script(sampass, + talloc_sub_basic(sampass, username, lp_logon_script()), + PDB_DEFAULT); + } + + if (profile_path) { + pdb_set_profile_path(sampass, profile_path, PDB_SET); + } else { + pdb_set_profile_path(sampass, + talloc_sub_basic(sampass, username, lp_logon_path()), + PDB_DEFAULT); + } + + pdb_set_acct_desc(sampass, acct_desc, PDB_SET); + pdb_set_workstations(sampass, workstations, PDB_SET); + pdb_set_munged_dial(sampass, munged_dial, PDB_SET); + + if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { + if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { + if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + pdb_set_pw_history(sampass, NULL, 0, PDB_SET); + pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); + pdb_set_hours_len(sampass, hours_len, PDB_SET); + pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); + pdb_set_logon_count(sampass, logon_count, PDB_SET); + pdb_set_unknown_6(sampass, unknown_6, PDB_SET); + pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); + pdb_set_logon_divs(sampass, logon_divs, PDB_SET); + pdb_set_hours(sampass, hours, PDB_SET); + +done: + + SAFE_FREE(username); + SAFE_FREE(domain); + SAFE_FREE(nt_username); + SAFE_FREE(fullname); + SAFE_FREE(homedir); + SAFE_FREE(dir_drive); + SAFE_FREE(logon_script); + SAFE_FREE(profile_path); + SAFE_FREE(acct_desc); + SAFE_FREE(workstations); + SAFE_FREE(munged_dial); + SAFE_FREE(unknown_str); + SAFE_FREE(lm_pw_ptr); + SAFE_FREE(nt_pw_ptr); + SAFE_FREE(hours); + + return ret; +} + +/********************************************************************* +*********************************************************************/ + +static BOOL init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen) +{ + + /* times are stored as 32bit integer + take care on system with 64bit wide time_t + --SSS */ + uint32 logon_time, + logoff_time, + kickoff_time, + bad_password_time, + pass_last_set_time, + pass_can_change_time, + pass_must_change_time; + char *username = NULL; + char *domain = NULL; + char *nt_username = NULL; + char *dir_drive = NULL; + char *unknown_str = NULL; + char *munged_dial = NULL; + char *fullname = NULL; + char *homedir = NULL; + char *logon_script = NULL; + char *profile_path = NULL; + char *acct_desc = NULL; + char *workstations = NULL; + uint32 username_len, domain_len, nt_username_len, + dir_drive_len, unknown_str_len, munged_dial_len, + fullname_len, homedir_len, logon_script_len, + profile_path_len, acct_desc_len, workstations_len; + + uint32 user_rid, group_rid, remove_me, hours_len, unknown_6; + uint16 acct_ctrl, logon_divs; + uint16 bad_password_count, logon_count; + uint8 *hours = NULL; + uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL; + uint32 len = 0; + uint32 lm_pw_len, nt_pw_len, hourslen; + BOOL ret = True; - if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) { - DEBUG(0,("tdbsam_convert: cannot initialized a SAM_ACCOUNT.\n")); + if(sampass == NULL || buf == NULL) { + DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n")); return False; } +/* TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */ + + /* unpack the buffer into variables */ + len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V1, + &logon_time, /* d */ + &logoff_time, /* d */ + &kickoff_time, /* d */ + /* Change from V0 is addition of bad_password_time field. */ + &bad_password_time, /* d */ + &pass_last_set_time, /* d */ + &pass_can_change_time, /* d */ + &pass_must_change_time, /* d */ + &username_len, &username, /* B */ + &domain_len, &domain, /* B */ + &nt_username_len, &nt_username, /* B */ + &fullname_len, &fullname, /* B */ + &homedir_len, &homedir, /* B */ + &dir_drive_len, &dir_drive, /* B */ + &logon_script_len, &logon_script, /* B */ + &profile_path_len, &profile_path, /* B */ + &acct_desc_len, &acct_desc, /* B */ + &workstations_len, &workstations, /* B */ + &unknown_str_len, &unknown_str, /* B */ + &munged_dial_len, &munged_dial, /* B */ + &user_rid, /* d */ + &group_rid, /* d */ + &lm_pw_len, &lm_pw_ptr, /* B */ + &nt_pw_len, &nt_pw_ptr, /* B */ + &acct_ctrl, /* w */ + &remove_me, /* d */ + &logon_divs, /* w */ + &hours_len, /* d */ + &hourslen, &hours, /* B */ + &bad_password_count, /* w */ + &logon_count, /* w */ + &unknown_6); /* d */ + + if (len == (uint32) -1) { + ret = False; + goto done; + } + + pdb_set_logon_time(sampass, logon_time, PDB_SET); + pdb_set_logoff_time(sampass, logoff_time, PDB_SET); + pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); + + /* Change from V0 is addition of bad_password_time field. */ + pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET); + pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); + pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET); + pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); + + pdb_set_username(sampass, username, PDB_SET); + pdb_set_domain(sampass, domain, PDB_SET); + pdb_set_nt_username(sampass, nt_username, PDB_SET); + pdb_set_fullname(sampass, fullname, PDB_SET); + + if (homedir) { + pdb_set_homedir(sampass, homedir, PDB_SET); + } + else { + pdb_set_homedir(sampass, + talloc_sub_basic(sampass, username, lp_logon_home()), + PDB_DEFAULT); + } + + if (dir_drive) + pdb_set_dir_drive(sampass, dir_drive, PDB_SET); + else { + pdb_set_dir_drive(sampass, + talloc_sub_basic(sampass, username, lp_logon_drive()), + PDB_DEFAULT); + } + + if (logon_script) + pdb_set_logon_script(sampass, logon_script, PDB_SET); + else { + pdb_set_logon_script(sampass, + talloc_sub_basic(sampass, username, lp_logon_script()), + PDB_DEFAULT); + } + + if (profile_path) { + pdb_set_profile_path(sampass, profile_path, PDB_SET); + } else { + pdb_set_profile_path(sampass, + talloc_sub_basic(sampass, username, lp_logon_path()), + PDB_DEFAULT); + } + + pdb_set_acct_desc(sampass, acct_desc, PDB_SET); + pdb_set_workstations(sampass, workstations, PDB_SET); + pdb_set_munged_dial(sampass, munged_dial, PDB_SET); + + if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { + if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { + if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + pdb_set_pw_history(sampass, NULL, 0, PDB_SET); + + pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); + pdb_set_hours_len(sampass, hours_len, PDB_SET); + pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); + pdb_set_logon_count(sampass, logon_count, PDB_SET); + pdb_set_unknown_6(sampass, unknown_6, PDB_SET); + pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); + pdb_set_logon_divs(sampass, logon_divs, PDB_SET); + pdb_set_hours(sampass, hours, PDB_SET); + +done: + + SAFE_FREE(username); + SAFE_FREE(domain); + SAFE_FREE(nt_username); + SAFE_FREE(fullname); + SAFE_FREE(homedir); + SAFE_FREE(dir_drive); + SAFE_FREE(logon_script); + SAFE_FREE(profile_path); + SAFE_FREE(acct_desc); + SAFE_FREE(workstations); + SAFE_FREE(munged_dial); + SAFE_FREE(unknown_str); + SAFE_FREE(lm_pw_ptr); + SAFE_FREE(nt_pw_ptr); + SAFE_FREE(hours); + + return ret; +} + +BOOL init_sam_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen) +{ + + /* times are stored as 32bit integer + take care on system with 64bit wide time_t + --SSS */ + uint32 logon_time, + logoff_time, + kickoff_time, + bad_password_time, + pass_last_set_time, + pass_can_change_time, + pass_must_change_time; + char *username = NULL; + char *domain = NULL; + char *nt_username = NULL; + char *dir_drive = NULL; + char *unknown_str = NULL; + char *munged_dial = NULL; + char *fullname = NULL; + char *homedir = NULL; + char *logon_script = NULL; + char *profile_path = NULL; + char *acct_desc = NULL; + char *workstations = NULL; + uint32 username_len, domain_len, nt_username_len, + dir_drive_len, unknown_str_len, munged_dial_len, + fullname_len, homedir_len, logon_script_len, + profile_path_len, acct_desc_len, workstations_len; + + uint32 user_rid, group_rid, hours_len, unknown_6; + uint16 acct_ctrl, logon_divs; + uint16 bad_password_count, logon_count; + uint8 *hours = NULL; + uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL; + uint32 len = 0; + uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen; + uint32 pwHistLen = 0; + BOOL ret = True; + fstring tmpstring; + BOOL expand_explicit = lp_passdb_expand_explicit(); + + if(sampass == NULL || buf == NULL) { + DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n")); + return False; + } + +/* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ + + /* unpack the buffer into variables */ + len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V2, + &logon_time, /* d */ + &logoff_time, /* d */ + &kickoff_time, /* d */ + &bad_password_time, /* d */ + &pass_last_set_time, /* d */ + &pass_can_change_time, /* d */ + &pass_must_change_time, /* d */ + &username_len, &username, /* B */ + &domain_len, &domain, /* B */ + &nt_username_len, &nt_username, /* B */ + &fullname_len, &fullname, /* B */ + &homedir_len, &homedir, /* B */ + &dir_drive_len, &dir_drive, /* B */ + &logon_script_len, &logon_script, /* B */ + &profile_path_len, &profile_path, /* B */ + &acct_desc_len, &acct_desc, /* B */ + &workstations_len, &workstations, /* B */ + &unknown_str_len, &unknown_str, /* B */ + &munged_dial_len, &munged_dial, /* B */ + &user_rid, /* d */ + &group_rid, /* d */ + &lm_pw_len, &lm_pw_ptr, /* B */ + &nt_pw_len, &nt_pw_ptr, /* B */ + /* Change from V1 is addition of password history field. */ + &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */ + &acct_ctrl, /* w */ + /* Also "remove_me" field was removed. */ + &logon_divs, /* w */ + &hours_len, /* d */ + &hourslen, &hours, /* B */ + &bad_password_count, /* w */ + &logon_count, /* w */ + &unknown_6); /* d */ + + if (len == (uint32) -1) { + ret = False; + goto done; + } + + pdb_set_logon_time(sampass, logon_time, PDB_SET); + pdb_set_logoff_time(sampass, logoff_time, PDB_SET); + pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); + pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET); + pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); + pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET); + pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); + + pdb_set_username(sampass, username, PDB_SET); + pdb_set_domain(sampass, domain, PDB_SET); + pdb_set_nt_username(sampass, nt_username, PDB_SET); + pdb_set_fullname(sampass, fullname, PDB_SET); + + if (homedir) { + fstrcpy( tmpstring, homedir ); + if (expand_explicit) { + standard_sub_basic( username, tmpstring, + sizeof(tmpstring) ); + } + pdb_set_homedir(sampass, tmpstring, PDB_SET); + } + else { + pdb_set_homedir(sampass, + talloc_sub_basic(sampass, username, lp_logon_home()), + PDB_DEFAULT); + } + + if (dir_drive) + pdb_set_dir_drive(sampass, dir_drive, PDB_SET); + else + pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT ); + + if (logon_script) { + fstrcpy( tmpstring, logon_script ); + if (expand_explicit) { + standard_sub_basic( username, tmpstring, + sizeof(tmpstring) ); + } + pdb_set_logon_script(sampass, tmpstring, PDB_SET); + } + else { + pdb_set_logon_script(sampass, + talloc_sub_basic(sampass, username, lp_logon_script()), + PDB_DEFAULT); + } + + if (profile_path) { + fstrcpy( tmpstring, profile_path ); + if (expand_explicit) { + standard_sub_basic( username, tmpstring, + sizeof(tmpstring) ); + } + pdb_set_profile_path(sampass, tmpstring, PDB_SET); + } + else { + pdb_set_profile_path(sampass, + talloc_sub_basic(sampass, username, lp_logon_path()), + PDB_DEFAULT); + } + + pdb_set_acct_desc(sampass, acct_desc, PDB_SET); + pdb_set_workstations(sampass, workstations, PDB_SET); + pdb_set_munged_dial(sampass, munged_dial, PDB_SET); + + if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { + if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { + if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + /* Change from V1 is addition of password history field. */ + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); + if (pwHistLen) { + uint8 *pw_hist = SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN); + if (!pw_hist) { + ret = False; + goto done; + } + memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN); + if (nt_pw_hist_ptr && nt_pw_hist_len) { + int i; + SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0); + nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN; + for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) { + memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN], + &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN], + PW_HISTORY_ENTRY_LEN); + } + } + if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) { + SAFE_FREE(pw_hist); + ret = False; + goto done; + } + SAFE_FREE(pw_hist); + } else { + pdb_set_pw_history(sampass, NULL, 0, PDB_SET); + } + + pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); + pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); + pdb_set_hours_len(sampass, hours_len, PDB_SET); + pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); + pdb_set_logon_count(sampass, logon_count, PDB_SET); + pdb_set_unknown_6(sampass, unknown_6, PDB_SET); + pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); + pdb_set_logon_divs(sampass, logon_divs, PDB_SET); + pdb_set_hours(sampass, hours, PDB_SET); + +done: + + SAFE_FREE(username); + SAFE_FREE(domain); + SAFE_FREE(nt_username); + SAFE_FREE(fullname); + SAFE_FREE(homedir); + SAFE_FREE(dir_drive); + SAFE_FREE(logon_script); + SAFE_FREE(profile_path); + SAFE_FREE(acct_desc); + SAFE_FREE(workstations); + SAFE_FREE(munged_dial); + SAFE_FREE(unknown_str); + SAFE_FREE(lm_pw_ptr); + SAFE_FREE(nt_pw_ptr); + SAFE_FREE(nt_pw_hist_ptr); + SAFE_FREE(hours); + + return ret; +} + + +/********************************************************************** + Intialize a struct samu struct from a BYTE buffer of size len + *********************************************************************/ + +static BOOL init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen) +{ + return init_sam_from_buffer_v3(sampass, buf, buflen); +} + +/********************************************************************** + Intialize a BYTE buffer from a struct samu struct + *********************************************************************/ + +static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, BOOL size_only) +{ + return init_buffer_from_sam_v3(buf, sampass, size_only); +} + +/********************************************************************** + Intialize a BYTE buffer from a struct samu struct + *********************************************************************/ + +static BOOL tdbsam_convert(int32 from) +{ + const char *vstring = TDBSAM_VERSION_STRING; + const char *prefix = USERPREFIX; + TDB_DATA data, key, old_key; + uint8 *buf = NULL; + BOOL ret; + + /* handle a Samba upgrade */ + tdb_lock_bystring(tdbsam, vstring); + /* Enumerate all records and convert them */ - key = tdb_firstkey(pdb_tdb); + key = tdb_firstkey(tdbsam); while (key.dptr) { @@ -99,26 +705,26 @@ static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) { old_key = key; /* increment to next in line */ - key = tdb_nextkey(pdb_tdb, key); + key = tdb_nextkey(tdbsam, key); SAFE_FREE(old_key.dptr); } if (key.dptr) { - + struct samu *user = NULL; + /* read from tdbsam */ - data = tdb_fetch(pdb_tdb, key); + data = tdb_fetch(tdbsam, key); if (!data.dptr) { DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr)); return False; } - if (!NT_STATUS_IS_OK(pdb_reset_sam(user))) { - DEBUG(0,("tdbsam_convert: cannot reset SAM_ACCOUNT.\n")); - SAFE_FREE(data.dptr); + /* unpack the buffer from the former format */ + if ( !(user = samu_new( NULL )) ) { + DEBUG(0,("tdbsam_convert: samu_new() failed!\n")); + SAFE_FREE( data.dptr ); return False; } - - /* unpack the buffer from the former format */ DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from)); switch (from) { case 0: @@ -130,13 +736,17 @@ static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) case 2: ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize); break; + case 3: + ret = init_sam_from_buffer_v3(user, (uint8 *)data.dptr, data.dsize); + break; default: /* unknown tdbsam version */ ret = False; } if (!ret) { - DEBUG(0,("tdbsam_convert: Bad SAM_ACCOUNT entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from)); + DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from)); SAFE_FREE(data.dptr); + TALLOC_FREE(user ); return False; } @@ -144,17 +754,20 @@ static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) SAFE_FREE(data.dptr); /* pack from the buffer into the new format */ + DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from)); - if ((data.dsize=init_buffer_from_sam (&buf, user, False)) == -1) { - DEBUG(0,("tdbsam_convert: cannot pack the SAM_ACCOUNT into the new format\n")); - SAFE_FREE(data.dptr); + data.dsize = init_buffer_from_sam (&buf, user, False); + TALLOC_FREE(user ); + + if ( data.dsize == -1 ) { + DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n")); return False; } data.dptr = (char *)buf; /* Store the buffer inside the TDBSAM */ - if (tdb_store(pdb_tdb, key, data, TDB_MODIFY) != TDB_SUCCESS) { - DEBUG(0,("tdbsam_convert: cannot store the SAM_ACCOUNT (key:%s) in new format\n",key.dptr)); + if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) { + DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr)); SAFE_FREE(data.dptr); return False; } @@ -163,99 +776,106 @@ static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) /* increment to next in line */ old_key = key; - key = tdb_nextkey(pdb_tdb, key); + key = tdb_nextkey(tdbsam, key); SAFE_FREE(old_key.dptr); } } - pdb_free_sam(&user); /* upgrade finished */ - tdb_store_int32(pdb_tdb, vstring, TDBSAM_VERSION); - tdb_unlock_bystring(pdb_tdb, vstring); + tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION); + tdb_unlock_bystring(tdbsam, vstring); return(True); } -/** - * Open the TDB passwd database, check version and convert it if needed. - * @param name filename of the tdbsam file. - * @param open_flags file access mode. - * @return a TDB_CONTEXT handle on the tdbsam file. - **/ +/********************************************************************* + Open the tdbsam file based on the absolute path specified. + Uses a reference count to allow multiple open calls. +*********************************************************************/ -static TDB_CONTEXT * tdbsam_tdbopen (const char *name, int open_flags) +static BOOL tdbsam_open( const char *name ) { - TDB_CONTEXT *pdb_tdb; - tdbsamver_t version; + int32 version; - /* Try to open tdb passwd */ - if (!(pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, - open_flags, 0600))) { - DEBUG(0, ("Unable to open/create TDB passwd\n")); - return NULL; + /* check if we are already open */ + + if ( tdbsam ) { + ref_count++; + DEBUG(8,("tdbsam_open: Incrementing open reference count. Ref count is now %d\n", + ref_count)); + return True; + } + + SMB_ASSERT( ref_count == 0 ); + + /* Try to open tdb passwd. Create a new one if necessary */ + + if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) { + DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name)); + return False; } + /* set the initial reference count - must be done before tdbsam_convert + as that calls tdbsam_open()/tdbsam_close(). */ + + ref_count = 1; + /* Check the version */ - version = (tdbsamver_t) tdb_fetch_int32(pdb_tdb, - TDBSAM_VERSION_STRING); - if (version == -1) + version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING ); + + if (version == -1) { version = 0; /* Version not found, assume version 0 */ + } /* Compare the version */ if (version > TDBSAM_VERSION) { /* Version more recent than the latest known */ - DEBUG(0, ("TDBSAM version unknown: %d\n", version)); - tdb_close(pdb_tdb); - pdb_tdb = NULL; + DEBUG(0, ("tdbsam_open: unknown version => %d\n", version)); + tdb_close( tdbsam ); + ref_count = 0; + return False; } - else if (version < TDBSAM_VERSION) { - /* Older version, must be converted */ - DEBUG(1, ("TDBSAM version too old (%d), trying to convert it.\n", version)); - - /* Reopen the pdb file with read-write access if needed */ - if (!(open_flags & O_RDWR)) { - DEBUG(10, ("tdbsam_tdbopen: TDB file opened with read only access, reopen it with read-write access.\n")); - tdb_close(pdb_tdb); - pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, (open_flags & 07777770) | O_RDWR, 0600); - } + + + if ( version < TDBSAM_VERSION ) { + DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n", + version, TDBSAM_VERSION)); - /* Convert */ - if (!tdbsam_convert(pdb_tdb, version)){ - DEBUG(0, ("tdbsam_tdbopen: Error when trying to convert tdbsam: %s\n",name)); - tdb_close(pdb_tdb); - pdb_tdb = NULL; - } else { - DEBUG(1, ("TDBSAM converted successfully.\n")); - } - - /* Reopen the pdb file as it must be */ - if (!(open_flags & O_RDWR)) { - tdb_close(pdb_tdb); - pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600); + if ( !tdbsam_convert(version) ) { + DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name)); + tdb_close(tdbsam); + ref_count = 0; + return False; } + + DEBUG(3, ("TDBSAM converted successfully.\n")); } - return pdb_tdb; + DEBUG(4,("tdbsam_open: successfully opened %s\n", name )); + + return True; } -/***************************************************************************** - Utility functions to close the tdb sam database - ****************************************************************************/ +/**************************************************************************** + wrapper atound tdb_close() to handle the reference count +****************************************************************************/ -static void tdbsam_tdbclose ( struct tdbsam_privates *state ) +void tdbsam_close( void ) { - if ( !state ) - return; - - if ( state->passwd_tdb ) { - tdb_close( state->passwd_tdb ); - state->passwd_tdb = NULL; + ref_count--; + + DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count)); + + SMB_ASSERT(ref_count >= 0 ); + + if ( ref_count == 0 ) { + tdb_close( tdbsam ); + tdbsam = NULL; } return; - } /**************************************************************************** @@ -295,17 +915,16 @@ static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, Save a list of user keys for iteration. ****************************************************************/ -static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint16 acb_mask) +static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint32 acb_mask) { - uint32 flags = update ? (O_RDWR|O_CREAT) : O_RDONLY; - - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; - - if ( !(tdb_state->passwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, flags )) ) - return NT_STATUS_UNSUCCESSFUL; + if ( !tdbsam_open( tdbsam_filename ) ) { + DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename)); + return NT_STATUS_ACCESS_DENIED; + } + + tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL ); + pwent_initialized = True; - tdb_traverse( tdb_state->passwd_tdb, tdbsam_traverse_setpwent, NULL ); - return NT_STATUS_OK; } @@ -316,10 +935,14 @@ static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, static void tdbsam_endsampwent(struct pdb_methods *my_methods) { - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; struct pwent_list *ptr, *ptr_next; - tdbsam_tdbclose( tdb_state ); + /* close the tdb only if we have a valid pwent state */ + + if ( pwent_initialized ) { + DEBUG(7, ("endtdbpwent: closed sam database.\n")); + tdbsam_close(); + } /* clear out any remaining entries in the list */ @@ -328,59 +951,51 @@ static void tdbsam_endsampwent(struct pdb_methods *my_methods) DLIST_REMOVE( tdbsam_pwent_list, ptr ); SAFE_FREE( ptr->key.dptr); SAFE_FREE( ptr ); - } + } - DEBUG(7, ("endtdbpwent: closed sam database.\n")); + pwent_initialized = False; } /***************************************************************** - Get one SAM_ACCOUNT from the TDB (next in line) + Get one struct samu from the TDB (next in line) *****************************************************************/ -static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user) +static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; TDB_DATA data; struct pwent_list *pkey; if ( !user ) { - DEBUG(0,("tdbsam_getsampwent: SAM_ACCOUNT is NULL.\n")); + DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n")); return nt_status; } if ( !tdbsam_pwent_list ) { DEBUG(4,("tdbsam_getsampwent: end of list\n")); - tdbsam_tdbclose( tdb_state ); return nt_status; } - if ( !tdb_state->passwd_tdb ) { - if ( !(tdb_state->passwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY)) ) - return nt_status; - } - /* pull the next entry */ pkey = tdbsam_pwent_list; DLIST_REMOVE( tdbsam_pwent_list, pkey ); - data = tdb_fetch(tdb_state->passwd_tdb, pkey->key); + data = tdb_fetch(tdbsam, pkey->key); SAFE_FREE( pkey->key.dptr); SAFE_FREE( pkey); - if (!data.dptr) { + if ( !data.dptr ) { DEBUG(5,("pdb_getsampwent: database entry not found. Was the user deleted?\n")); return nt_status; } - if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) { - DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n")); + if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) { + DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n")); } SAFE_FREE( data.dptr ); - return NT_STATUS_OK; } @@ -389,18 +1004,15 @@ static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT * Lookup a name in the SAM TDB ******************************************************************/ -static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname) +static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname) { - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; - TDB_CONTEXT *pwd_tdb; TDB_DATA data, key; fstring keystr; fstring name; if ( !user ) { - DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n")); - return nt_status; + DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n")); + return NT_STATUS_NO_MEMORY; } /* Data is stored in all lower-case */ @@ -412,52 +1024,37 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT key.dptr = keystr; key.dsize = strlen(keystr) + 1; - /* open the accounts TDB */ - if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) { - - if (errno == ENOENT) { - /* - * TDB file doesn't exist, so try to create new one. This is useful to avoid - * confusing error msg when adding user account first time - */ - if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT ))) { - DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n", - tdb_state->tdbsam_location)); - tdb_close(pwd_tdb); - } else { - DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) does not exist. Couldn't create new one. Error was: %s\n", - tdb_state->tdbsam_location, strerror(errno))); - } - - /* requested user isn't there anyway */ - nt_status = NT_STATUS_NO_SUCH_USER; - return nt_status; - } - DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location)); - return nt_status; + /* open the database */ + + if ( !tdbsam_open( tdbsam_filename ) ) { + DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename)); + return NT_STATUS_ACCESS_DENIED; } - + /* get the record */ - data = tdb_fetch(pwd_tdb, key); + + data = tdb_fetch(tdbsam, key); if (!data.dptr) { DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n")); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb))); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam))); DEBUGADD(5, (" Key: %s\n", keystr)); - tdb_close(pwd_tdb); - return nt_status; + tdbsam_close(); + return NT_STATUS_NO_SUCH_USER; } /* unpack the buffer */ + if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) { - DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n")); + DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n")); SAFE_FREE(data.dptr); - tdb_close(pwd_tdb); - return nt_status; + tdbsam_close(); + return NT_STATUS_NO_MEMORY; } + + /* success */ + SAFE_FREE(data.dptr); - - /* no further use for database, close it now */ - tdb_close(pwd_tdb); + tdbsam_close(); return NT_STATUS_OK; } @@ -466,60 +1063,65 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT Search by rid **************************************************************************/ -static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, SAM_ACCOUNT *user, uint32 rid) +static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid) { - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; - TDB_CONTEXT *pwd_tdb; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; TDB_DATA data, key; fstring keystr; fstring name; - - if (user==NULL) { - DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n")); + + if ( !user ) { + DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n")); return nt_status; } - + /* set search key */ + slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid); key.dptr = keystr; key.dsize = strlen (keystr) + 1; - /* open the accounts TDB */ - if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) { - DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n")); - return nt_status; + /* open the database */ + + if ( !tdbsam_open( tdbsam_filename ) ) { + DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename)); + return NT_STATUS_ACCESS_DENIED; } /* get the record */ - data = tdb_fetch (pwd_tdb, key); + + data = tdb_fetch (tdbsam, key); if (!data.dptr) { DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr)); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb))); - tdb_close (pwd_tdb); - return nt_status; + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam))); + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; } - fstrcpy(name, data.dptr); SAFE_FREE(data.dptr); - tdb_close (pwd_tdb); + nt_status = tdbsam_getsampwnam (my_methods, user, name); + + done: + /* cleanup */ - return tdbsam_getsampwnam (my_methods, user, name); + tdbsam_close(); + + return nt_status; } -static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid) +static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid) { uint32 rid; - if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) + + if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) ) return NT_STATUS_UNSUCCESSFUL; + return tdbsam_getsampwrid(my_methods, user, rid); } -static BOOL tdb_delete_samacct_only(TDB_CONTEXT *pwd_tdb, - struct pdb_methods *my_methods, - SAM_ACCOUNT *sam_pass) +static BOOL tdb_delete_samacct_only( struct samu *sam_pass ) { TDB_DATA key; fstring keystr; @@ -529,44 +1131,47 @@ static BOOL tdb_delete_samacct_only(TDB_CONTEXT *pwd_tdb, strlower_m(name); /* set the search key */ + slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name); key.dptr = keystr; key.dsize = strlen (keystr) + 1; /* it's outaa here! 8^) */ - if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) { + + if (tdb_delete(tdbsam, key) != TDB_SUCCESS) { DEBUG(5, ("Error deleting entry from tdb passwd database!\n")); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb))); - tdb_close(pwd_tdb); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam))); return False; } + return True; } /*************************************************************************** - Delete a SAM_ACCOUNT + Delete a struct samu records for the username and RID key ****************************************************************************/ -static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_pass) +static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass) { - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; - TDB_CONTEXT *pwd_tdb; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; TDB_DATA key; fstring keystr; uint32 rid; fstring name; + /* open the database */ + + if ( !tdbsam_open( tdbsam_filename ) ) { + DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n", + tdbsam_filename)); + return NT_STATUS_ACCESS_DENIED; + } + fstrcpy(name, pdb_get_username(sam_pass)); strlower_m(name); - /* open the TDB */ - if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR))) { - DEBUG(0, ("Unable to open TDB passwd!")); - return nt_status; - } - /* set the search key */ + slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name); key.dptr = keystr; key.dsize = strlen (keystr) + 1; @@ -574,40 +1179,43 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_AC rid = pdb_get_user_rid(sam_pass); /* it's outaa here! 8^) */ - if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) { - DEBUG(5, ("Error deleting entry from tdb passwd database!\n")); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb))); - tdb_close(pwd_tdb); - return nt_status; - } - /* delete also the RID key */ + if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) { + DEBUG(5, ("Error deleting entry from tdb passwd database!\n")); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam))); + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } /* set the search key */ + slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid); key.dptr = keystr; key.dsize = strlen (keystr) + 1; /* it's outaa here! 8^) */ - if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) { + + if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) { DEBUG(5, ("Error deleting entry from tdb rid database!\n")); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb))); - tdb_close(pwd_tdb); - return nt_status; + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam))); + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; } + + nt_status = NT_STATUS_OK; - tdb_close(pwd_tdb); + done: + tdbsam_close(); - return NT_STATUS_OK; + return nt_status; } /*************************************************************************** Update the TDB SAM account record only + Assumes that the tdbsam is already open ****************************************************************************/ -static BOOL tdb_update_samacct_only(TDB_CONTEXT *pwd_tdb, - struct pdb_methods *my_methods, - SAM_ACCOUNT* newpwd, int flag) +static BOOL tdb_update_samacct_only( struct samu* newpwd, int flag ) { TDB_DATA key, data; uint8 *buf = NULL; @@ -615,9 +1223,10 @@ static BOOL tdb_update_samacct_only(TDB_CONTEXT *pwd_tdb, fstring name; BOOL ret = True; - /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */ - if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) { - DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n")); + /* copy the struct samu struct into a BYTE buffer for storage */ + + if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) { + DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n")); ret = False; goto done; } @@ -636,9 +1245,10 @@ static BOOL tdb_update_samacct_only(TDB_CONTEXT *pwd_tdb, key.dsize = strlen(keystr) + 1; /* add the account */ - if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) { + + if ( tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS ) { DEBUG(0, ("Unable to modify passwd TDB!")); - DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb))); + DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam))); DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr)); ret = False; @@ -649,15 +1259,14 @@ done: /* cleanup */ SAFE_FREE(buf); - return (ret); + return ret; } /*************************************************************************** Update the TDB SAM RID record only + Assumes that the tdbsam is already open ****************************************************************************/ -static BOOL tdb_update_ridrec_only(TDB_CONTEXT *pwd_tdb, - struct pdb_methods *my_methods, - SAM_ACCOUNT* newpwd, int flag) +static BOOL tdb_update_ridrec_only( struct samu* newpwd, int flag ) { TDB_DATA key, data; fstring keystr; @@ -671,15 +1280,14 @@ static BOOL tdb_update_ridrec_only(TDB_CONTEXT *pwd_tdb, data.dptr = name; /* setup the RID index key */ - slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, - pdb_get_user_rid(newpwd)); + slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd)); key.dptr = keystr; key.dsize = strlen (keystr) + 1; /* add the reference */ - if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) { + if (tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS) { DEBUG(0, ("Unable to modify TDB passwd !")); - DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb))); + DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam))); DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr)); return False; } @@ -692,82 +1300,72 @@ static BOOL tdb_update_ridrec_only(TDB_CONTEXT *pwd_tdb, Update the TDB SAM ****************************************************************************/ -static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag) +static BOOL tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag) { - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; - TDB_CONTEXT *pwd_tdb = NULL; - BOOL ret = True; uint32 user_rid; + BOOL result = True; /* invalidate the existing TDB iterator if it is open */ - if (tdb_state->passwd_tdb) { - tdb_close(tdb_state->passwd_tdb); - tdb_state->passwd_tdb = NULL; - } - - /* open the account TDB passwd*/ - - pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); + tdbsam_endsampwent( my_methods ); - if (!pwd_tdb) { - DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", - tdb_state->tdbsam_location)); +#if 0 + if ( !pdb_get_group_rid(newpwd) ) { + DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] " + "without a primary group RID\n", pdb_get_username(newpwd))); return False; } - - if (!pdb_get_group_rid(newpwd)) { - DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n", - pdb_get_username(newpwd))); - ret = False; - goto done; - } +#endif if ( !(user_rid = pdb_get_user_rid(newpwd)) ) { - DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd))); - ret = False; - goto done; + DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd))); + return False; } - if (!tdb_update_samacct_only(pwd_tdb, my_methods, newpwd, flag) || - !tdb_update_ridrec_only(pwd_tdb, my_methods, newpwd, flag)) { - ret = False; - goto done; + /* open the database */ + + if ( !tdbsam_open( tdbsam_filename ) ) { + DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename)); + return False; + } + + if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) { + result = False; } -done: /* cleanup */ - tdb_close (pwd_tdb); + + tdbsam_close(); - return (ret); + return result; } /*************************************************************************** - Modifies an existing SAM_ACCOUNT + Modifies an existing struct samu ****************************************************************************/ -static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd) +static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd) { - if (tdb_update_sam(my_methods, newpwd, TDB_MODIFY)) - return NT_STATUS_OK; - else + if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) ) return NT_STATUS_UNSUCCESSFUL; + + return NT_STATUS_OK; } /*************************************************************************** - Adds an existing SAM_ACCOUNT + Adds an existing struct samu ****************************************************************************/ -static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd) +static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd) { - if (tdb_update_sam(my_methods, newpwd, TDB_INSERT)) - return NT_STATUS_OK; - else + if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) ) return NT_STATUS_UNSUCCESSFUL; + + return NT_STATUS_OK; } /*************************************************************************** - Renames a SAM_ACCOUNT + Renames a struct samu - check for the posix user/rename user script - Add and lock the new user record - rename the posix user @@ -776,123 +1374,202 @@ static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, SAM_ACCO - unlock the new user record ***************************************************************************/ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods, - SAM_ACCOUNT *old_acct, + struct samu *old_acct, const char *newname) { - struct tdbsam_privates *tdb_state = - (struct tdbsam_privates *)my_methods->private_data; - SAM_ACCOUNT *new_acct = NULL; - pstring rename_script; - TDB_CONTEXT *pwd_tdb = NULL; - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - BOOL interim_account = False; - - if (!*(lp_renameuser_script())) - goto done; + struct samu *new_acct = NULL; + pstring rename_script; + BOOL interim_account = False; + int rename_ret; - if (!pdb_copy_sam_account(old_acct, &new_acct) || - !pdb_set_username(new_acct, newname, PDB_CHANGED)) - goto done; - - /* invalidate the existing TDB iterator if it is open */ + /* can't do anything without an external script */ - if (tdb_state->passwd_tdb) { - tdb_close(tdb_state->passwd_tdb); - tdb_state->passwd_tdb = NULL; + pstrcpy(rename_script, lp_renameuser_script() ); + if ( ! *rename_script ) { + return NT_STATUS_ACCESS_DENIED; } - /* open the account TDB passwd */ + /* invalidate the existing TDB iterator if it is open */ - pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); + tdbsam_endsampwent( my_methods ); + + if ( !(new_acct = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } - if (!pwd_tdb) { - DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", - tdb_state->tdbsam_location)); - goto done; + if ( !pdb_copy_sam_account(new_acct, old_acct) + || !pdb_set_username(new_acct, newname, PDB_CHANGED)) + { + TALLOC_FREE(new_acct ); + return NT_STATUS_NO_MEMORY; + } + + /* open the database */ + + if ( !tdbsam_open( tdbsam_filename ) ) { + DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename)); + TALLOC_FREE(new_acct ); + return NT_STATUS_ACCESS_DENIED; } /* add the new account and lock it */ - if (!tdb_update_samacct_only(pwd_tdb, my_methods, new_acct, - TDB_INSERT)) + + if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) { goto done; + } + interim_account = True; - if (tdb_lock_bystring(pwd_tdb, newname, 30) == -1) { + if ( tdb_lock_bystring_with_timeout(tdbsam, newname, 30) == -1 ) { goto done; } /* rename the posix user */ - pstrcpy(rename_script, lp_renameuser_script()); - - if (*rename_script) { - int rename_ret; - - pstring_sub(rename_script, "%unew", newname); - pstring_sub(rename_script, "%uold", - pdb_get_username(old_acct)); - rename_ret = smbrun(rename_script, NULL); + string_sub2(rename_script, "%unew", newname, sizeof(pstring), + True, False, True); + string_sub2(rename_script, "%uold", pdb_get_username(old_acct), + sizeof(pstring), True, False, True); + rename_ret = smbrun(rename_script, NULL); - DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret)); + DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret)); - if (rename_ret) - goto done; - } else { - goto done; + if (rename_ret) { + goto done; } /* rewrite the rid->username record */ - if (!tdb_update_ridrec_only(pwd_tdb, my_methods, new_acct, TDB_MODIFY)) + + if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) { goto done; + } interim_account = False; - tdb_unlock_bystring(pwd_tdb, newname); - - tdb_delete_samacct_only(pwd_tdb, my_methods, old_acct); - - ret = NT_STATUS_OK; + tdb_unlock_bystring( tdbsam, newname ); + tdb_delete_samacct_only( old_acct ); + + tdbsam_close(); + + TALLOC_FREE(new_acct ); + return NT_STATUS_OK; done: /* cleanup */ if (interim_account) { - tdb_unlock_bystring(pwd_tdb, newname); - tdb_delete_samacct_only(pwd_tdb, my_methods, new_acct); + tdb_unlock_bystring(tdbsam, newname); + tdb_delete_samacct_only(new_acct); } - if (pwd_tdb) - tdb_close (pwd_tdb); + + tdbsam_close(); + if (new_acct) - pdb_free_sam(&new_acct); + TALLOC_FREE(new_acct); - return (ret); + return NT_STATUS_ACCESS_DENIED; } - -static void free_private_data(void **vp) + +static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods) { - struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp; - tdbsam_tdbclose(*tdb_state); - *tdb_state = NULL; + 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. - /* No need to free any further, as it is talloc()ed */ + 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) { + 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; + } -/** - * Init tdbsam backend - * - * @param pdb_context initialised passdb context - * @param pdb_method backend methods structure to be filled with function pointers - * @param location the backend tdb file location - * - * @return nt_status code - **/ + rid = BASE_RID; /* Default if not set */ -static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) + 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; +} + +/********************************************************************* + Initialize the tdb sam backend. Setup the dispath table of methods, + open the tdb, etc... +*********************************************************************/ + +static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location) { NTSTATUS nt_status; - struct tdbsam_privates *tdb_state; + pstring tdbfile; + const char *pfile = location; - if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { + if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) { return nt_status; } @@ -908,26 +1585,21 @@ 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; - tdb_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct tdbsam_privates); - - if (!tdb_state) { - DEBUG(0, ("talloc() failed for tdbsam private_data!\n")); - return NT_STATUS_NO_MEMORY; - } + (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm; + (*pdb_method)->new_rid = tdbsam_new_rid; - if (location) { - tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, location); - } else { - pstring tdbfile; - get_private_directory(tdbfile); - pstrcat(tdbfile, "/"); - pstrcat(tdbfile, PASSDB_FILE_NAME); - tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, tdbfile); + /* save the path for later */ + + if ( !location ) { + pstr_sprintf( tdbfile, "%s/%s", lp_private_dir(), PASSDB_FILE_NAME ); + pfile = tdbfile; } + pstrcpy( tdbsam_filename, pfile ); - (*pdb_method)->private_data = tdb_state; - - (*pdb_method)->free_private_data = free_private_data; + /* no private data */ + + (*pdb_method)->private_data = NULL; + (*pdb_method)->free_private_data = NULL; return NT_STATUS_OK; } diff --git a/source/passdb/pdb_xml.c b/source/passdb/pdb_xml.c deleted file mode 100644 index d40a5731a43..00000000000 --- a/source/passdb/pdb_xml.c +++ /dev/null @@ -1,580 +0,0 @@ - -/* - * XML password backend for samba - * Copyright (C) Jelmer Vernooij 2002 - * Some parts based on the libxml gjobread example by Daniel Veillard - * - * 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. - */ - -/* FIXME: - * - Support stdin input by using '-' - * - Be faster. Don't rewrite the whole file when adding a user, but store it in the memory and save it when exiting. Requires changes to samba source. - * - Gives the ability to read/write to standard input/output - * - Do locking! - * - Better names! - */ - - -#define XML_URL "http://samba.org/samba/DTD/passdb" - -#include "includes.h" - -#include <libxml/xmlmemory.h> -#include <libxml/parser.h> - -static int xmlsam_debug_level = DBGC_ALL; - -#undef DBGC_CLASS -#define DBGC_CLASS xmlsam_debug_level - - -/* Helper utilities for charset conversion */ -static xmlNodePtr smbXmlNewChild(xmlNodePtr prnt, xmlNsPtr ns, const xmlChar *name, const char *content) -{ - char *string_utf8; - xmlNodePtr ret; - - if(!content) return xmlNewChild(prnt, ns, name, NULL); - - - if(push_utf8_allocate(&string_utf8,content) == (size_t)-1) - return NULL; - - ret = xmlNewTextChild(prnt, ns, name, string_utf8); - - SAFE_FREE(string_utf8); - - return ret; -} - - -static char * iota(int a) { - static char tmp[10]; - - snprintf(tmp, 9, "%d", a); - return tmp; -} - -static BOOL parsePass(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SAM_ACCOUNT * u) -{ - pstring temp; - - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (strcmp(cur->name, "crypt")) - DEBUG(0, ("Unknown element %s\n", cur->name)); - else { - if (!strcmp(xmlGetProp(cur, "type"), "nt") - && - pdb_gethexpwd(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1), temp)) - pdb_set_nt_passwd(u, temp, PDB_SET); - else if (!strcmp(xmlGetProp(cur, "type"), "lanman") - && - pdb_gethexpwd(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1), temp)) - pdb_set_lanman_passwd(u, temp, PDB_SET); - else - DEBUG(0, - ("Unknown crypt type: %s\n", - xmlGetProp(cur, "type"))); - } - cur = cur->next; - } - return True; -} - -static BOOL parseUser(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SAM_ACCOUNT * u) -{ - char *tmp; - DOM_SID sid; - - tmp = xmlGetProp(cur, "sid"); - if (tmp){ - string_to_sid(&sid, tmp); - pdb_set_user_sid(u, &sid, PDB_SET); - } - pdb_set_username(u, xmlGetProp(cur, "name"), PDB_SET); - /* We don't care what the top level element name is */ - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if ((!strcmp(cur->name, "group")) && (cur->ns == ns)) { - tmp = xmlGetProp(cur, "sid"); - if (tmp){ - string_to_sid(&sid, tmp); - pdb_set_group_sid(u, &sid, PDB_SET); - } - } - - else if ((!strcmp(cur->name, "domain")) && (cur->ns == ns)) - pdb_set_domain(u, - xmlNodeListGetString(doc, cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "fullname") && cur->ns == ns) - pdb_set_fullname(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "nt_username") && cur->ns == ns) - pdb_set_nt_username(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "logon_script") && cur->ns == ns) - pdb_set_logon_script(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "profile_path") && cur->ns == ns) - pdb_set_profile_path(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "logon_time") && cur->ns == ns) - pdb_set_logon_time(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "logoff_time") && cur->ns == ns) - pdb_set_logoff_time(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), - PDB_SET); - - else if (!strcmp(cur->name, "kickoff_time") && cur->ns == ns) - pdb_set_kickoff_time(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), - PDB_SET); - - else if (!strcmp(cur->name, "logon_divs") && cur->ns == ns) - pdb_set_logon_divs(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "hours_len") && cur->ns == ns) - pdb_set_hours_len(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "bad_password_count") && cur->ns == ns) - pdb_set_bad_password_count(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "logon_count") && cur->ns == ns) - pdb_set_logon_count(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "unknown_6") && cur->ns == ns) - pdb_set_unknown_6(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "homedir") && cur->ns == ns) - pdb_set_homedir(u, - xmlNodeListGetString(doc, cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "unknown_str") && cur->ns == ns) - pdb_set_unknown_str(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "dir_drive") && cur->ns == ns) - pdb_set_dir_drive(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "munged_dial") && cur->ns == ns) - pdb_set_munged_dial(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "acct_desc") && cur->ns == ns) - pdb_set_acct_desc(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if (!strcmp(cur->name, "acct_ctrl") && cur->ns == ns) - pdb_set_acct_ctrl(u, - atol(xmlNodeListGetString - (doc, cur->xmlChildrenNode, 1)), PDB_SET); - - else if (!strcmp(cur->name, "workstations") && cur->ns == ns) - pdb_set_workstations(u, - xmlNodeListGetString(doc, - cur->xmlChildrenNode, - 1), PDB_SET); - - else if ((!strcmp(cur->name, "password")) && (cur->ns == ns)) { - tmp = xmlGetProp(cur, "last_set"); - if (tmp) - pdb_set_pass_last_set_time(u, atol(tmp), PDB_SET); - tmp = xmlGetProp(cur, "must_change"); - if (tmp) - pdb_set_pass_must_change_time(u, atol(tmp), PDB_SET); - tmp = xmlGetProp(cur, "can_change"); - if (tmp) - pdb_set_pass_can_change_time(u, atol(tmp), PDB_SET); - parsePass(doc, ns, cur, u); - } - - else - DEBUG(0, ("Unknown element %s\n", cur->name)); - cur = cur->next; - } - - return True; -} - -typedef struct pdb_xml { - char *location; - char written; - xmlDocPtr doc; - xmlNodePtr users; - xmlNodePtr pwent; - xmlNsPtr ns; -} pdb_xml; - -static xmlNodePtr parseSambaXMLFile(struct pdb_xml *data) -{ - xmlNodePtr cur; - - data->doc = xmlParseFile(data->location); - if (data->doc == NULL) - return NULL; - - cur = xmlDocGetRootElement(data->doc); - if (!cur) { - DEBUG(0, ("empty document\n")); - xmlFreeDoc(data->doc); - return NULL; - } - data->ns = xmlSearchNsByHref(data->doc, cur, XML_URL); - if (!data->ns) { - DEBUG(0, - ("document of the wrong type, samba user namespace not found\n")); - xmlFreeDoc(data->doc); - return NULL; - } - if (strcmp(cur->name, "samba")) { - DEBUG(0, ("document of the wrong type, root node != samba")); - xmlFreeDoc(data->doc); - return NULL; - } - - cur = cur->xmlChildrenNode; - while (cur && xmlIsBlankNode(cur)) { - cur = cur->next; - } - if (!cur) - return NULL; - if ((strcmp(cur->name, "users")) || (cur->ns != data->ns)) { - DEBUG(0, ("document of the wrong type, was '%s', users expected", - cur->name)); - DEBUG(0, ("xmlDocDump follows\n")); - xmlDocDump(stderr, data->doc); - DEBUG(0, ("xmlDocDump finished\n")); - xmlFreeDoc(data->doc); - return NULL; - } - data->users = cur; - cur = cur->xmlChildrenNode; - return cur; -} - -static NTSTATUS xmlsam_setsampwent(struct pdb_methods *methods, BOOL update, uint16 acb_mask) -{ - pdb_xml *data; - - if (!methods) { - DEBUG(0, ("Invalid methods\n")); - return NT_STATUS_INVALID_PARAMETER; - } - data = (pdb_xml *) methods->private_data; - if (!data) { - DEBUG(0, ("Invalid pdb_xml_data\n")); - return NT_STATUS_INVALID_PARAMETER; - } - data->pwent = parseSambaXMLFile(data); - if (!data->pwent) - return NT_STATUS_UNSUCCESSFUL; - - return NT_STATUS_OK; -} - -/*************************************************************** - End enumeration of the passwd list. - ****************************************************************/ - -static void xmlsam_endsampwent(struct pdb_methods *methods) -{ - pdb_xml *data; - - if (!methods) { - DEBUG(0, ("Invalid methods\n")); - return; - } - - data = (pdb_xml *) methods->private_data; - - if (!data) { - DEBUG(0, ("Invalid pdb_xml_data\n")); - return; - } - - xmlFreeDoc(data->doc); - data->doc = NULL; - data->pwent = NULL; -} - -/***************************************************************** - Get one SAM_ACCOUNT from the list (next in line) - *****************************************************************/ - -static NTSTATUS xmlsam_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT * user) -{ - pdb_xml *data; - - if (!methods) { - DEBUG(0, ("Invalid methods\n")); - return NT_STATUS_INVALID_PARAMETER; - } - data = (pdb_xml *) methods->private_data; - - if (!data) { - DEBUG(0, ("Invalid pdb_xml_data\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - while (data->pwent) { - if ((!strcmp(data->pwent->name, "user")) && - (data->pwent->ns == data->ns)) { - - parseUser(data->doc, data->ns, data->pwent, user); - data->pwent = data->pwent->next; - return NT_STATUS_OK; - } - data->pwent = data->pwent->next; - } - return NT_STATUS_UNSUCCESSFUL; -} - -/*************************************************************************** - Adds an existing SAM_ACCOUNT - ****************************************************************************/ - -static NTSTATUS xmlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT * u) -{ - pstring temp; - fstring sid_str; - xmlNodePtr cur, user, pass, root; - pdb_xml *data; - - DEBUG(10, ("xmlsam_add_sam_account called!\n")); - - if (!methods) { - DEBUG(0, ("Invalid methods\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - data = (pdb_xml *) methods->private_data; - if (!data) { - DEBUG(0, ("Invalid pdb_xml_data\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* Create a new document if we can't open the current one */ - if (!parseSambaXMLFile(data)) { - DEBUG(0, ("Can't load current XML file, creating a new one\n")); - data->doc = xmlNewDoc(XML_DEFAULT_VERSION); - root = xmlNewDocNode(data->doc, NULL, "samba", NULL); - cur = xmlDocSetRootElement(data->doc, root); - data->ns = xmlNewNs(root, XML_URL, "samba"); - data->users = smbXmlNewChild(root, data->ns, "users", NULL); - } - - user = smbXmlNewChild(data->users, data->ns, "user", NULL); - xmlNewProp(user, "sid", - sid_to_string(sid_str, pdb_get_user_sid(u))); - - if (pdb_get_username(u) && strcmp(pdb_get_username(u), "")) - xmlNewProp(user, "name", pdb_get_username(u)); - - cur = smbXmlNewChild(user, data->ns, "group", NULL); - - xmlNewProp(cur, "sid", - sid_to_string(sid_str, pdb_get_group_sid(u))); - - if (pdb_get_init_flags(u, PDB_LOGONTIME) != PDB_DEFAULT) - smbXmlNewChild(user, data->ns, "logon_time", - iota(pdb_get_logon_time(u))); - - if (pdb_get_init_flags(u, PDB_LOGOFFTIME) != PDB_DEFAULT) - smbXmlNewChild(user, data->ns, "logoff_time", - iota(pdb_get_logoff_time(u))); - - if (pdb_get_init_flags(u, PDB_KICKOFFTIME) != PDB_DEFAULT) - smbXmlNewChild(user, data->ns, "kickoff_time", - iota(pdb_get_kickoff_time(u))); - - if (pdb_get_domain(u) && strcmp(pdb_get_domain(u), "")) - smbXmlNewChild(user, data->ns, "domain", pdb_get_domain(u)); - - if (pdb_get_nt_username(u) && strcmp(pdb_get_nt_username(u), "")) - smbXmlNewChild(user, data->ns, "nt_username", pdb_get_nt_username(u)); - - if (pdb_get_fullname(u) && strcmp(pdb_get_fullname(u), "")) - smbXmlNewChild(user, data->ns, "fullname", pdb_get_fullname(u)); - - if (pdb_get_homedir(u) && strcmp(pdb_get_homedir(u), "")) - smbXmlNewChild(user, data->ns, "homedir", pdb_get_homedir(u)); - - if (pdb_get_dir_drive(u) && strcmp(pdb_get_dir_drive(u), "")) - smbXmlNewChild(user, data->ns, "dir_drive", pdb_get_dir_drive(u)); - - if (pdb_get_logon_script(u) && strcmp(pdb_get_logon_script(u), "")) - smbXmlNewChild(user, data->ns, "logon_script", - pdb_get_logon_script(u)); - - if (pdb_get_profile_path(u) && strcmp(pdb_get_profile_path(u), "")) - smbXmlNewChild(user, data->ns, "profile_path", - pdb_get_profile_path(u)); - - if (pdb_get_acct_desc(u) && strcmp(pdb_get_acct_desc(u), "")) - smbXmlNewChild(user, data->ns, "acct_desc", pdb_get_acct_desc(u)); - - if (pdb_get_workstations(u) && strcmp(pdb_get_workstations(u), "")) - smbXmlNewChild(user, data->ns, "workstations", - pdb_get_workstations(u)); - - if (pdb_get_unknown_str(u) && strcmp(pdb_get_unknown_str(u), "")) - smbXmlNewChild(user, data->ns, "unknown_str", pdb_get_unknown_str(u)); - - if (pdb_get_munged_dial(u) && strcmp(pdb_get_munged_dial(u), "")) - smbXmlNewChild(user, data->ns, "munged_dial", pdb_get_munged_dial(u)); - - - /* Password stuff */ - pass = smbXmlNewChild(user, data->ns, "password", NULL); - if (pdb_get_pass_last_set_time(u)) - xmlNewProp(pass, "last_set", iota(pdb_get_pass_last_set_time(u))); - if (pdb_get_init_flags(u, PDB_CANCHANGETIME) != PDB_DEFAULT) - xmlNewProp(pass, "can_change", - iota(pdb_get_pass_can_change_time(u))); - - if (pdb_get_init_flags(u, PDB_MUSTCHANGETIME) != PDB_DEFAULT) - xmlNewProp(pass, "must_change", - iota(pdb_get_pass_must_change_time(u))); - - - if (pdb_get_lanman_passwd(u)) { - pdb_sethexpwd(temp, pdb_get_lanman_passwd(u), - pdb_get_acct_ctrl(u)); - cur = smbXmlNewChild(pass, data->ns, "crypt", temp); - xmlNewProp(cur, "type", "lanman"); - } - - if (pdb_get_nt_passwd(u)) { - pdb_sethexpwd(temp, pdb_get_nt_passwd(u), pdb_get_acct_ctrl(u)); - cur = smbXmlNewChild(pass, data->ns, "crypt", temp); - xmlNewProp(cur, "type", "nt"); - } - - smbXmlNewChild(user, data->ns, "acct_ctrl", iota(pdb_get_acct_ctrl(u))); - - if (pdb_get_logon_divs(u)) - smbXmlNewChild(user, data->ns, "logon_divs", - iota(pdb_get_logon_divs(u))); - - if (pdb_get_hours_len(u)) - smbXmlNewChild(user, data->ns, "hours_len", - iota(pdb_get_hours_len(u))); - - smbXmlNewChild(user, data->ns, "bad_password_count", iota(pdb_get_bad_password_count(u))); - smbXmlNewChild(user, data->ns, "logon_count", iota(pdb_get_logon_count(u))); - smbXmlNewChild(user, data->ns, "unknown_6", iota(pdb_get_unknown_6(u))); - xmlSaveFile(data->location, data->doc); - - return NT_STATUS_OK; -} - -static NTSTATUS xmlsam_init(PDB_CONTEXT * pdb_context, PDB_METHODS ** pdb_method, - const char *location) -{ - NTSTATUS nt_status; - pdb_xml *data; - - xmlsam_debug_level = debug_add_class("xmlsam"); - if (xmlsam_debug_level == -1) { - xmlsam_debug_level = DBGC_ALL; - DEBUG(0, ("xmlsam: Couldn't register custom debugging class!\n")); - } - - if (!pdb_context) { - DEBUG(0, ("invalid pdb_methods specified\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - if (!NT_STATUS_IS_OK - (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { - return nt_status; - } - - (*pdb_method)->name = "xmlsam"; - - (*pdb_method)->setsampwent = xmlsam_setsampwent; - (*pdb_method)->endsampwent = xmlsam_endsampwent; - (*pdb_method)->getsampwent = xmlsam_getsampwent; - (*pdb_method)->add_sam_account = xmlsam_add_sam_account; - (*pdb_method)->getsampwnam = NULL; - (*pdb_method)->getsampwsid = NULL; - (*pdb_method)->update_sam_account = NULL; - (*pdb_method)->delete_sam_account = NULL; - (*pdb_method)->getgrsid = NULL; - (*pdb_method)->getgrgid = NULL; - (*pdb_method)->getgrnam = NULL; - (*pdb_method)->add_group_mapping_entry = NULL; - (*pdb_method)->update_group_mapping_entry = NULL; - (*pdb_method)->delete_group_mapping_entry = NULL; - (*pdb_method)->enum_group_mapping = NULL; - - data = _talloc(pdb_context->mem_ctx, sizeof(pdb_xml)); - data->location = talloc_strdup(pdb_context->mem_ctx, (location ? location : "passdb.xml")); - data->pwent = NULL; - data->written = 0; - (*pdb_method)->private_data = data; - - LIBXML_TEST_VERSION xmlKeepBlanksDefault(0); - - return NT_STATUS_OK; -} - -NTSTATUS pdb_xml_init(void) -{ - return smb_register_passdb(PASSDB_INTERFACE_VERSION, "xml", xmlsam_init); -} diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index 14896a33400..32793dea586 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -177,13 +177,16 @@ BOOL secrets_fetch_domain_guid(const char *domain, struct uuid *guid) strupper_m(key); dyn_guid = (struct uuid *)secrets_fetch(key, &size); - if ((!dyn_guid) && (lp_server_role() == ROLE_DOMAIN_PDC)) { - smb_uuid_generate_random(&new_guid); - if (!secrets_store_domain_guid(domain, &new_guid)) - return False; - dyn_guid = (struct uuid *)secrets_fetch(key, &size); - if (dyn_guid == NULL) + if (!dyn_guid) { + if (lp_server_role() == ROLE_DOMAIN_PDC) { + smb_uuid_generate_random(&new_guid); + if (!secrets_store_domain_guid(domain, &new_guid)) + return False; + dyn_guid = (struct uuid *)secrets_fetch(key, &size); + } + if (dyn_guid == NULL) { return False; + } } if (size != sizeof(struct uuid)) { @@ -242,7 +245,7 @@ BOOL secrets_lock_trust_account_password(const char *domain, BOOL dolock) return False; if (dolock) - return (tdb_lock_bystring(tdb, trust_keystr(domain),0) == 0); + return (tdb_lock_bystring(tdb, trust_keystr(domain)) == 0); else tdb_unlock_bystring(tdb, trust_keystr(domain)); return True; @@ -388,10 +391,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 +403,16 @@ 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; + SAFE_FREE(uni_dom_name); /* last change time */ pass.mod_time = time(NULL); @@ -415,7 +422,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 +665,101 @@ 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")); + tdb_search_list_free(keys); 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")); + tdb_search_list_free(keys); + 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")); + tdb_search_list_free(keys); + 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) { + tdb_search_list_free(keys); + 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; } /******************************************************************************* @@ -804,7 +774,7 @@ BOOL secrets_named_mutex(const char *name, unsigned int timeout) if (!secrets_init()) return False; - ret = tdb_lock_bystring(tdb, name, timeout); + ret = tdb_lock_bystring_with_timeout(tdb, name, timeout); if (ret == 0) DEBUG(10,("secrets_named_mutex: got mutex for %s\n", name )); @@ -821,35 +791,6 @@ void secrets_named_mutex_release(const char *name) DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name )); } -/********************************************************* - Check to see if we must talk to the PDC to avoid sam - sync delays - ********************************************************/ - -BOOL must_use_pdc( const char *domain ) -{ - time_t now = time(NULL); - time_t last_change_time; - unsigned char passwd[16]; - - if ( !secrets_fetch_trust_account_password(domain, passwd, &last_change_time, NULL) ) - return False; - - /* - * If the time the machine password has changed - * was less than about 15 minutes then we need to contact - * the PDC only, as we cannot be sure domain replication - * has yet taken place. Bug found by Gerald (way to go - * Gerald !). JRA. - */ - - if ( now - last_change_time < SAM_SYNC_WINDOW ) - return True; - - return False; - -} - /******************************************************************************* Store a complete AFS keyfile into secrets.tdb. *******************************************************************************/ @@ -959,7 +900,7 @@ static TDB_CONTEXT *open_schannel_session_store(TALLOC_CTX *mem_ctx) if (!tdb_sc) { DEBUG(0,("open_schannel_session_store: Failed to open %s\n", fname)); - talloc_free(fname); + TALLOC_FREE(fname); return NULL; } @@ -987,7 +928,7 @@ static TDB_CONTEXT *open_schannel_session_store(TALLOC_CTX *mem_ctx) } SAFE_FREE(vers.dptr); - talloc_free(fname); + TALLOC_FREE(fname); return tdb_sc; } @@ -997,13 +938,15 @@ static TDB_CONTEXT *open_schannel_session_store(TALLOC_CTX *mem_ctx) Note we must be root here. *******************************************************************************/ -BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinfo *pdc) +BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, + const char *remote_machine, + const struct dcinfo *pdc) { TDB_CONTEXT *tdb_sc = NULL; TDB_DATA value; BOOL ret; char *keystr = talloc_asprintf(mem_ctx, "%s/%s", SECRETS_SCHANNEL_STATE, - pdc->remote_machine); + remote_machine); if (!keystr) { return False; } @@ -1016,7 +959,7 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf 8, pdc->seed_chal.data, 8, pdc->clnt_chal.data, 8, pdc->srv_chal.data, - 8, pdc->sess_key, + 16, pdc->sess_key, 16, pdc->mach_pw, pdc->mach_acct, pdc->remote_machine, @@ -1024,7 +967,7 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf value.dptr = TALLOC(mem_ctx, value.dsize); if (!value.dptr) { - talloc_free(keystr); + TALLOC_FREE(keystr); return False; } @@ -1033,7 +976,7 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf 8, pdc->seed_chal.data, 8, pdc->clnt_chal.data, 8, pdc->srv_chal.data, - 8, pdc->sess_key, + 16, pdc->sess_key, 16, pdc->mach_pw, pdc->mach_acct, pdc->remote_machine, @@ -1041,8 +984,8 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf tdb_sc = open_schannel_session_store(mem_ctx); if (!tdb_sc) { - talloc_free(keystr); - talloc_free(value.dptr); + TALLOC_FREE(keystr); + TALLOC_FREE(value.dptr); return False; } @@ -1052,8 +995,8 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf keystr )); tdb_close(tdb_sc); - talloc_free(keystr); - talloc_free(value.dptr); + TALLOC_FREE(keystr); + TALLOC_FREE(value.dptr); return ret; } @@ -1064,7 +1007,7 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, const char *remote_machine, - struct dcinfo *pdc) + struct dcinfo **ppdc) { TDB_CONTEXT *tdb_sc = NULL; TDB_DATA value; @@ -1075,10 +1018,11 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, unsigned char *pmach_pw = NULL; uint32 l1, l2, l3, l4, l5; int ret; + struct dcinfo *pdc = NULL; char *keystr = talloc_asprintf(mem_ctx, "%s/%s", SECRETS_SCHANNEL_STATE, remote_machine); - ZERO_STRUCTP(pdc); + *ppdc = NULL; if (!keystr) { return False; @@ -1088,7 +1032,7 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, tdb_sc = open_schannel_session_store(mem_ctx); if (!tdb_sc) { - talloc_free(keystr); + TALLOC_FREE(keystr); return False; } @@ -1102,6 +1046,8 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, tdb_close(tdb_sc); + pdc = TALLOC_ZERO_P(mem_ctx, struct dcinfo); + /* Retrieve the record. */ ret = tdb_unpack(value.dptr, value.dsize, "dBBBBBfff", &pdc->sequence, @@ -1114,29 +1060,31 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, &pdc->remote_machine, &pdc->domain); - if (ret == -1 || l1 != 8 || l2 != 8 || l3 != 8 || l4 != 8 || l5 != 16) { - talloc_free(keystr); + if (ret == -1 || l1 != 8 || l2 != 8 || l3 != 8 || l4 != 16 || l5 != 16) { + /* Bad record - delete it. */ + tdb_delete_bystring(tdb_sc, keystr); + TALLOC_FREE(keystr); + TALLOC_FREE(pdc); SAFE_FREE(pseed_chal); SAFE_FREE(pclnt_chal); SAFE_FREE(psrv_chal); SAFE_FREE(psess_key); SAFE_FREE(pmach_pw); SAFE_FREE(value.dptr); - ZERO_STRUCTP(pdc); return False; } memcpy(pdc->seed_chal.data, pseed_chal, 8); memcpy(pdc->clnt_chal.data, pclnt_chal, 8); memcpy(pdc->srv_chal.data, psrv_chal, 8); - memcpy(pdc->sess_key, psess_key, 8); + memcpy(pdc->sess_key, psess_key, 16); memcpy(pdc->mach_pw, pmach_pw, 16); /* We know these are true so didn't bother to store them. */ pdc->challenge_sent = True; pdc->authenticated = True; - DEBUG(3,("secrets_store_schannel_session_info: restored schannel info key %s\n", + DEBUG(3,("secrets_restore_schannel_session_info: restored schannel info key %s\n", keystr )); SAFE_FREE(pseed_chal); @@ -1145,7 +1093,10 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, SAFE_FREE(psess_key); SAFE_FREE(pmach_pw); - talloc_free(keystr); + TALLOC_FREE(keystr); SAFE_FREE(value.dptr); + + *ppdc = pdc; + return True; } diff --git a/source/passdb/util_builtin.c b/source/passdb/util_builtin.c index 1f810ac37a1..9c59df1f687 100644 --- a/source/passdb/util_builtin.c +++ b/source/passdb/util_builtin.c @@ -20,6 +20,61 @@ #include "includes.h" +struct rid_name_map { + uint32 rid; + const char *name; +}; + +static const struct rid_name_map builtin_aliases[] = { + { BUILTIN_ALIAS_RID_ADMINS, "Administrators" }, + { BUILTIN_ALIAS_RID_USERS, "Users" }, + { BUILTIN_ALIAS_RID_GUESTS, "Guests" }, + { BUILTIN_ALIAS_RID_POWER_USERS, "Power Users" }, + { BUILTIN_ALIAS_RID_ACCOUNT_OPS, "Account Operators" }, + { BUILTIN_ALIAS_RID_SYSTEM_OPS, "Server Operators" }, + { BUILTIN_ALIAS_RID_PRINT_OPS, "Print Operators" }, + { BUILTIN_ALIAS_RID_BACKUP_OPS, "Backup Operators" }, + { BUILTIN_ALIAS_RID_REPLICATOR, "Replicator" }, + { BUILTIN_ALIAS_RID_RAS_SERVERS, "RAS Servers" }, + { BUILTIN_ALIAS_RID_PRE_2K_ACCESS, "Pre-Windows 2000 Compatible Access" }, + { 0, NULL}}; + +/******************************************************************* + Look up a rid in the BUILTIN domain + ********************************************************************/ +BOOL lookup_builtin_rid(TALLOC_CTX *mem_ctx, uint32 rid, const char **name) +{ + const struct rid_name_map *aliases = builtin_aliases; + + while (aliases->name != NULL) { + if (rid == aliases->rid) { + *name = talloc_strdup(mem_ctx, aliases->name); + return True; + } + aliases++; + } + + return False; +} + +/******************************************************************* + Look up a name in the BUILTIN domain + ********************************************************************/ +BOOL lookup_builtin_name(const char *name, uint32 *rid) +{ + const struct rid_name_map *aliases = builtin_aliases; + + while (aliases->name != NULL) { + if (strequal(name, aliases->name)) { + *rid = aliases->rid; + return True; + } + aliases++; + } + + return False; +} + /***************************************************************** Return the name of the BUILTIN domain *****************************************************************/ @@ -29,3 +84,27 @@ const char *builtin_domain_name(void) return "BUILTIN"; } +/***************************************************************** + Check if the SID is the builtin SID (S-1-5-32). +*****************************************************************/ + +BOOL sid_check_is_builtin(const DOM_SID *sid) +{ + return sid_equal(sid, &global_sid_Builtin); +} + +/***************************************************************** + Check if the SID is one of the builtin SIDs (S-1-5-32-a). +*****************************************************************/ + +BOOL sid_check_is_in_builtin(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_builtin(&dom_sid); +} + diff --git a/source/passdb/util_sam_sid.c b/source/passdb/util_sam_sid.c deleted file mode 100644 index 822b7f6a349..00000000000 --- a/source/passdb/util_sam_sid.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Samba utility functions - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Luke Kenneth Caseson Leighton 1998-1999 - Copyright (C) Jeremy Allison 1999 - - 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" - -#define MAX_SID_NAMES 7 - -typedef struct _known_sid_users { - uint32 rid; - enum SID_NAME_USE sid_name_use; - const char *known_user_name; -} known_sid_users; - -struct sid_name_map_info -{ - const DOM_SID *sid; - const char *name; - const known_sid_users *known_users; -}; - -static const known_sid_users everyone_users[] = { - { 0, SID_NAME_WKN_GRP, "Everyone" }, - {0, (enum SID_NAME_USE)0, NULL}}; - -static const known_sid_users creator_owner_users[] = { - { 0, SID_NAME_WKN_GRP, "Creator Owner" }, - { 1, SID_NAME_WKN_GRP, "Creator Group" }, - {0, (enum SID_NAME_USE)0, NULL}}; - -static const known_sid_users nt_authority_users[] = { - { 1, SID_NAME_WKN_GRP, "Dialup" }, - { 2, SID_NAME_WKN_GRP, "Network"}, - { 3, SID_NAME_WKN_GRP, "Batch"}, - { 4, SID_NAME_WKN_GRP, "Interactive"}, - { 6, SID_NAME_WKN_GRP, "Service"}, - { 7, SID_NAME_WKN_GRP, "AnonymousLogon"}, - { 8, SID_NAME_WKN_GRP, "Proxy"}, - { 9, SID_NAME_WKN_GRP, "ServerLogon"}, - { 10, SID_NAME_WKN_GRP, "Self"}, - { 11, SID_NAME_WKN_GRP, "Authenticated Users"}, - { 12, SID_NAME_WKN_GRP, "Restricted"}, - { 13, SID_NAME_WKN_GRP, "Terminal Server User"}, - { 14, SID_NAME_WKN_GRP, "Remote Interactive Logon"}, - { 15, SID_NAME_WKN_GRP, "This Organization"}, - { 18, SID_NAME_WKN_GRP, "SYSTEM"}, - { 19, SID_NAME_WKN_GRP, "Local Service"}, - { 20, SID_NAME_WKN_GRP, "Network Service"}, - { 0, (enum SID_NAME_USE)0, NULL}}; - -static const known_sid_users builtin_groups[] = { - { BUILTIN_ALIAS_RID_ADMINS, SID_NAME_ALIAS, "Administrators" }, - { BUILTIN_ALIAS_RID_USERS, SID_NAME_ALIAS, "Users" }, - { BUILTIN_ALIAS_RID_GUESTS, SID_NAME_ALIAS, "Guests" }, - { BUILTIN_ALIAS_RID_POWER_USERS, SID_NAME_ALIAS, "Power Users" }, - { BUILTIN_ALIAS_RID_ACCOUNT_OPS, SID_NAME_ALIAS, "Account Operators" }, - { BUILTIN_ALIAS_RID_SYSTEM_OPS, SID_NAME_ALIAS, "Server Operators" }, - { BUILTIN_ALIAS_RID_PRINT_OPS, SID_NAME_ALIAS, "Print Operators" }, - { BUILTIN_ALIAS_RID_BACKUP_OPS, SID_NAME_ALIAS, "Backup Operators" }, - { BUILTIN_ALIAS_RID_REPLICATOR, SID_NAME_ALIAS, "Replicator" }, - { BUILTIN_ALIAS_RID_RAS_SERVERS, SID_NAME_ALIAS, "RAS Servers" }, - { BUILTIN_ALIAS_RID_PRE_2K_ACCESS, SID_NAME_ALIAS, "Pre-Windows 2000 Compatible Access" }, - { 0, (enum SID_NAME_USE)0, NULL}}; - -static struct sid_name_map_info special_domains[] = { - { &global_sid_Builtin, "BUILTIN", builtin_groups }, - { &global_sid_World_Domain, "", everyone_users }, - { &global_sid_Creator_Owner_Domain, "", creator_owner_users }, - { &global_sid_NT_Authority, "NT Authority", nt_authority_users }, - { NULL, NULL, NULL }}; - -/************************************************************************** - Turns a domain SID into a name, returned in the nt_domain argument. -***************************************************************************/ - -BOOL map_domain_sid_to_name(const DOM_SID *sid, fstring nt_domain) -{ - fstring sid_str; - int i = 0; - - sid_to_string(sid_str, sid); - - DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str)); - - while (special_domains[i].sid != NULL) { - DEBUG(5,("map_domain_sid_to_name: compare: %s\n", - sid_string_static(special_domains[i].sid))); - if (sid_equal(special_domains[i].sid, sid)) { - fstrcpy(nt_domain, special_domains[i].name); - DEBUG(5,("map_domain_sid_to_name: found '%s'\n", - nt_domain)); - return True; - } - i++; - } - - DEBUG(5,("map_domain_sid_to_name: mapping for %s not found\n", - sid_string_static(sid))); - - return False; -} - -/************************************************************************** - Looks up a known username from one of the known domains. -***************************************************************************/ - -BOOL lookup_special_sid(const DOM_SID *sid, const char **domain, - const char **name, enum SID_NAME_USE *type) -{ - int i; - DOM_SID dom_sid; - uint32 rid; - const known_sid_users *users = NULL; - - sid_copy(&dom_sid, sid); - if (!sid_split_rid(&dom_sid, &rid)) { - DEBUG(2, ("Could not split rid from SID\n")); - return False; - } - - for (i=0; special_domains[i].sid != NULL; i++) { - if (sid_equal(&dom_sid, special_domains[i].sid)) { - *domain = special_domains[i].name; - users = special_domains[i].known_users; - break; - } - } - - if (users == NULL) { - DEBUG(10, ("SID %s is no special sid\n", - sid_string_static(sid))); - return False; - } - - for (i=0; users[i].known_user_name != NULL; i++) { - if (rid == users[i].rid) { - *name = users[i].known_user_name; - *type = users[i].sid_name_use; - return True; - } - } - - DEBUG(10, ("RID of special SID %s not found\n", - sid_string_static(sid))); - - return False; -} - -/******************************************************************* - Look up a rid in the BUILTIN domain - ********************************************************************/ -BOOL lookup_builtin_rid(uint32 rid, fstring name) -{ - const known_sid_users *aliases = builtin_groups; - int i; - - for (i=0; aliases[i].known_user_name != NULL; i++) { - if (rid == aliases[i].rid) { - fstrcpy(name, aliases[i].known_user_name); - return True; - } - } - - return False; -} - -/***************************************************************** - Check if the SID is our domain SID (S-1-5-21-x-y-z). -*****************************************************************/ - -BOOL sid_check_is_domain(const DOM_SID *sid) -{ - return sid_equal(sid, get_global_sam_sid()); -} - -/***************************************************************** - Check if the SID is our domain SID (S-1-5-21-x-y-z). -*****************************************************************/ - -BOOL sid_check_is_in_our_domain(const DOM_SID *sid) -{ - DOM_SID dom_sid; - uint32 rid; - - sid_copy(&dom_sid, sid); - sid_split_rid(&dom_sid, &rid); - - return sid_equal(&dom_sid, get_global_sam_sid()); -} - -/************************************************************************** - Try and map a name to one of the well known SIDs. -***************************************************************************/ - -BOOL map_name_to_wellknown_sid(DOM_SID *sid, enum SID_NAME_USE *use, const char *name) -{ - int i, j; - - DEBUG(10,("map_name_to_wellknown_sid: looking up %s\n", name)); - - for (i=0; special_domains[i].sid != NULL; i++) { - const known_sid_users *users = special_domains[i].known_users; - - if (users == NULL) - continue; - - for (j=0; users[j].known_user_name != NULL; j++) { - if ( strequal(users[j].known_user_name, name) ) { - sid_copy(sid, special_domains[i].sid); - sid_append_rid(sid, users[j].rid); - *use = users[j].sid_name_use; - return True; - } - } - } - - return False; -} - - diff --git a/source/passdb/util_unixsids.c b/source/passdb/util_unixsids.c new file mode 100644 index 00000000000..2a4818e3aec --- /dev/null +++ b/source/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/source/passdb/util_wellknown.c b/source/passdb/util_wellknown.c new file mode 100644 index 00000000000..9a6fa7def52 --- /dev/null +++ b/source/passdb/util_wellknown.c @@ -0,0 +1,175 @@ +/* + Unix SMB/CIFS implementation. + Lookup routines for well-known SIDs + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Luke Kenneth Caseson Leighton 1998-1999 + Copyright (C) Jeremy Allison 1999 + 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" + +struct rid_name_map { + uint32 rid; + const char *name; +}; + +struct sid_name_map_info +{ + const DOM_SID *sid; + const char *name; + const struct rid_name_map *known_users; +}; + +static const struct rid_name_map everyone_users[] = { + { 0, "Everyone" }, + { 0, NULL}}; + +static const struct rid_name_map creator_owner_users[] = { + { 0, "Creator Owner" }, + { 1, "Creator Group" }, + { 0, NULL}}; + +static const struct rid_name_map nt_authority_users[] = { + { 1, "Dialup" }, + { 2, "Network"}, + { 3, "Batch"}, + { 4, "Interactive"}, + { 6, "Service"}, + { 7, "AnonymousLogon"}, + { 8, "Proxy"}, + { 9, "ServerLogon"}, + { 10, "Self"}, + { 11, "Authenticated Users"}, + { 12, "Restricted"}, + { 13, "Terminal Server User"}, + { 14, "Remote Interactive Logon"}, + { 15, "This Organization"}, + { 18, "SYSTEM"}, + { 19, "Local Service"}, + { 20, "Network Service"}, + { 0, NULL}}; + +static struct sid_name_map_info special_domains[] = { + { &global_sid_World_Domain, "", everyone_users }, + { &global_sid_Creator_Owner_Domain, "", creator_owner_users }, + { &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; +} + +BOOL sid_check_is_in_wellknown_domain(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_wellknown_domain(&dom_sid, NULL); +} + +/************************************************************************** + Looks up a known username from one of the known domains. +***************************************************************************/ + +BOOL lookup_wellknown_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, + const char **domain, const char **name) +{ + int i; + DOM_SID dom_sid; + uint32 rid; + const struct rid_name_map *users = NULL; + + sid_copy(&dom_sid, sid); + if (!sid_split_rid(&dom_sid, &rid)) { + DEBUG(2, ("Could not split rid from SID\n")); + return False; + } + + for (i=0; special_domains[i].sid != NULL; i++) { + if (sid_equal(&dom_sid, special_domains[i].sid)) { + *domain = talloc_strdup(mem_ctx, + special_domains[i].name); + users = special_domains[i].known_users; + break; + } + } + + if (users == NULL) { + DEBUG(10, ("SID %s is no special sid\n", + sid_string_static(sid))); + return False; + } + + for (i=0; users[i].name != NULL; i++) { + if (rid == users[i].rid) { + *name = talloc_strdup(mem_ctx, users[i].name); + return True; + } + } + + DEBUG(10, ("RID of special SID %s not found\n", + sid_string_static(sid))); + + return False; +} + +/************************************************************************** + Try and map a name to one of the well known SIDs. +***************************************************************************/ + +BOOL lookup_wellknown_name(TALLOC_CTX *mem_ctx, const char *name, + DOM_SID *sid, const char **domain) +{ + int i, j; + + DEBUG(10,("map_name_to_wellknown_sid: looking up %s\n", name)); + + for (i=0; special_domains[i].sid != NULL; i++) { + const struct rid_name_map *users = + special_domains[i].known_users; + + if (users == NULL) + continue; + + for (j=0; users[j].name != NULL; j++) { + if ( strequal(users[j].name, name) ) { + sid_copy(sid, special_domains[i].sid); + sid_append_rid(sid, users[j].rid); + *domain = talloc_strdup( + mem_ctx, special_domains[i].name); + return True; + } + } + } + + return False; +} |