diff options
author | Jeremy Allison <jra@samba.org> | 2009-10-17 10:36:33 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2009-10-17 10:36:33 -0700 |
commit | 7c51fa6d699a653cafa90df8e44911b576118ebd (patch) | |
tree | 543bf9ca698e03eff81104898b33e77f1abed319 /source4/dsdb | |
parent | cc3a6770c77ec8fe1cd63bf4c682853c56201f0c (diff) | |
parent | 3e3214fd91471bca5b6c4d3782e922d252d588fb (diff) | |
download | samba-7c51fa6d699a653cafa90df8e44911b576118ebd.tar.gz samba-7c51fa6d699a653cafa90df8e44911b576118ebd.tar.bz2 samba-7c51fa6d699a653cafa90df8e44911b576118ebd.zip |
Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
Diffstat (limited to 'source4/dsdb')
38 files changed, 1228 insertions, 1153 deletions
diff --git a/source4/dsdb/common/sidmap.c b/source4/dsdb/common/sidmap.c deleted file mode 100644 index 3111a78e51..0000000000 --- a/source4/dsdb/common/sidmap.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - mapping routines for SID <-> unix uid/gid - - Copyright (C) Andrew Tridgell 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "system/passwd.h" -#include "../libds/common/flags.h" -#include "dsdb/samdb/samdb.h" -#include "auth/auth.h" -#include "libcli/ldap/ldap_ndr.h" -#include "lib/ldb/include/ldb.h" -#include "../lib/util/util_ldb.h" -#include "libcli/security/security.h" -#include "param/param.h" - -/* - these are used for the fallback local uid/gid to sid mapping - code. -*/ -#define SIDMAP_LOCAL_USER_BASE 0x80000000 -#define SIDMAP_LOCAL_GROUP_BASE 0xC0000000 -#define SIDMAP_MAX_LOCAL_UID 0x3fffffff -#define SIDMAP_MAX_LOCAL_GID 0x3fffffff - -/* - private context for sid mapping routines -*/ -struct sidmap_context { - struct ldb_context *samctx; -}; - -/* - open a sidmap context - use talloc_free to close -*/ -struct sidmap_context *sidmap_open(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, - struct loadparm_context *lp_ctx) -{ - struct sidmap_context *sidmap; - sidmap = talloc(mem_ctx, struct sidmap_context); - if (sidmap == NULL) { - return NULL; - } - sidmap->samctx = samdb_connect(sidmap, ev_ctx, lp_ctx, system_session(sidmap, lp_ctx)); - if (sidmap->samctx == NULL) { - talloc_free(sidmap); - return NULL; - } - - return sidmap; -} - - -/* - check the sAMAccountType field of a search result to see if - the account is a user account -*/ -static bool is_user_account(struct ldb_message *res) -{ - uint_t atype = samdb_result_uint(res, "sAMAccountType", 0); - if (atype && (!(atype & ATYPE_ACCOUNT))) { - return false; - } - return true; -} - -/* - check the sAMAccountType field of a search result to see if - the account is a group account -*/ -static bool is_group_account(struct ldb_message *res) -{ - uint_t atype = samdb_result_uint(res, "sAMAccountType", 0); - if (atype && atype == ATYPE_NORMAL_ACCOUNT) { - return false; - } - return true; -} - - - -/* - return the dom_sid of our primary domain -*/ -static NTSTATUS sidmap_primary_domain_sid(struct sidmap_context *sidmap, - TALLOC_CTX *mem_ctx, struct dom_sid **sid) -{ - const char *attrs[] = { "objectSid", NULL }; - int ret; - struct ldb_message **res = NULL; - - ret = gendb_search_dn(sidmap->samctx, mem_ctx, NULL, &res, attrs); - if (ret != 1) { - talloc_free(res); - return NT_STATUS_NO_SUCH_DOMAIN; - } - - *sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); - talloc_free(res); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - - -/* - map a sid to a unix uid -*/ -NTSTATUS sidmap_sid_to_unixuid(struct sidmap_context *sidmap, - const struct dom_sid *sid, uid_t *uid) -{ - const char *attrs[] = { "sAMAccountName", "uidNumber", - "sAMAccountType", "unixName", NULL }; - int ret; - const char *s; - TALLOC_CTX *tmp_ctx; - struct ldb_message **res; - struct dom_sid *domain_sid; - NTSTATUS status; - - tmp_ctx = talloc_new(sidmap); - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "objectSid=%s", - ldap_encode_ndr_dom_sid(tmp_ctx, sid)); - - if (ret != 1) { - goto allocated_sid; - } - - /* make sure its a user, not a group */ - if (!is_user_account(res[0])) { - DEBUG(0,("sid_to_unixuid: sid %s is not an account!\n", - dom_sid_string(tmp_ctx, sid))); - talloc_free(tmp_ctx); - return NT_STATUS_INVALID_SID; - } - - /* first try to get the uid directly */ - s = samdb_result_string(res[0], "uidNumber", NULL); - if (s != NULL) { - *uid = strtoul(s, NULL, 0); - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - - /* next try via the UnixName attribute */ - s = samdb_result_string(res[0], "unixName", NULL); - if (s != NULL) { - struct passwd *pwd = getpwnam(s); - if (!pwd) { - DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s, - dom_sid_string(tmp_ctx, sid))); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - } - *uid = pwd->pw_uid; - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - - /* finally try via the sAMAccountName attribute */ - s = samdb_result_string(res[0], "sAMAccountName", NULL); - if (s != NULL) { - struct passwd *pwd = getpwnam(s); - if (!pwd) { - DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n", - s, dom_sid_string(tmp_ctx, sid))); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - } - *uid = pwd->pw_uid; - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - - -allocated_sid: - status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_DOMAIN; - } - - if (dom_sid_in_domain(domain_sid, sid)) { - uint32_t rid = sid->sub_auths[sid->num_auths-1]; - if (rid >= SIDMAP_LOCAL_USER_BASE && - rid < SIDMAP_LOCAL_GROUP_BASE) { - *uid = rid - SIDMAP_LOCAL_USER_BASE; - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - } - - - DEBUG(0,("sid_to_unixuid: no uidNumber, unixName or sAMAccountName for sid %s\n", - dom_sid_string(tmp_ctx, sid))); - - talloc_free(tmp_ctx); - return NT_STATUS_NONE_MAPPED; -} - - -/* - see if a sid is a group - very inefficient! -*/ -bool sidmap_sid_is_group(struct sidmap_context *sidmap, struct dom_sid *sid) -{ - const char *attrs[] = { "sAMAccountType", NULL }; - int ret; - TALLOC_CTX *tmp_ctx; - struct ldb_message **res; - NTSTATUS status; - struct dom_sid *domain_sid; - bool is_group; - - tmp_ctx = talloc_new(sidmap); - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid)); - if (ret == 1) { - is_group = is_group_account(res[0]); - talloc_free(tmp_ctx); - return is_group; - } - - status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return false; - } - - if (dom_sid_in_domain(domain_sid, sid)) { - uint32_t rid = sid->sub_auths[sid->num_auths-1]; - if (rid >= SIDMAP_LOCAL_GROUP_BASE) { - talloc_free(tmp_ctx); - return true; - } - } - - talloc_free(tmp_ctx); - return false; -} - -/* - map a sid to a unix gid -*/ -NTSTATUS sidmap_sid_to_unixgid(struct sidmap_context *sidmap, - const struct dom_sid *sid, gid_t *gid) -{ - const char *attrs[] = { "sAMAccountName", "gidNumber", - "unixName", "sAMAccountType", NULL }; - int ret; - const char *s; - TALLOC_CTX *tmp_ctx; - struct ldb_message **res; - NTSTATUS status; - struct dom_sid *domain_sid; - - tmp_ctx = talloc_new(sidmap); - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid)); - if (ret != 1) { - goto allocated_sid; - } - - /* make sure its not a user */ - if (!is_group_account(res[0])) { - DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n", - dom_sid_string(tmp_ctx, sid))); - talloc_free(tmp_ctx); - return NT_STATUS_INVALID_SID; - } - - /* first try to get the gid directly */ - s = samdb_result_string(res[0], "gidNumber", NULL); - if (s != NULL) { - *gid = strtoul(s, NULL, 0); - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - - /* next try via the UnixName attribute */ - s = samdb_result_string(res[0], "unixName", NULL); - if (s != NULL) { - struct group *grp = getgrnam(s); - if (!grp) { - DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n", - s, dom_sid_string(tmp_ctx, sid))); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_GROUP; - } - *gid = grp->gr_gid; - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - - /* finally try via the sAMAccountName attribute */ - s = samdb_result_string(res[0], "sAMAccountName", NULL); - if (s != NULL) { - struct group *grp = getgrnam(s); - if (!grp) { - DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, dom_sid_string(tmp_ctx, sid))); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_GROUP; - } - *gid = grp->gr_gid; - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - -allocated_sid: - status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_DOMAIN; - } - - if (dom_sid_in_domain(domain_sid, sid)) { - uint32_t rid = sid->sub_auths[sid->num_auths-1]; - if (rid >= SIDMAP_LOCAL_GROUP_BASE) { - *gid = rid - SIDMAP_LOCAL_GROUP_BASE; - talloc_free(tmp_ctx); - return NT_STATUS_OK; - } - } - - DEBUG(0,("sid_to_unixgid: no gidNumber, unixName or sAMAccountName for sid %s\n", - dom_sid_string(tmp_ctx, sid))); - - talloc_free(tmp_ctx); - return NT_STATUS_NONE_MAPPED; -} - - -/* - map a unix uid to a dom_sid - the returned sid is allocated in the supplied mem_ctx -*/ -NTSTATUS sidmap_uid_to_sid(struct sidmap_context *sidmap, - TALLOC_CTX *mem_ctx, - const uid_t uid, struct dom_sid **sid) -{ - const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL }; - int ret, i; - TALLOC_CTX *tmp_ctx; - struct ldb_message **res; - struct passwd *pwd; - struct dom_sid *domain_sid; - NTSTATUS status; - - /* - we search for the mapping in the following order: - - - check if the uid is in the dynamic uid range assigned for winbindd - use. If it is, then look in winbindd sid mapping - database (not implemented yet) - - look for a user account in samdb that has uidNumber set to the - given uid - - look for a user account in samdb that has unixName or - sAMAccountName set to the name given by getpwuid() - - assign a SID by adding the uid to SIDMAP_LOCAL_USER_BASE in the local - domain - */ - - - tmp_ctx = talloc_new(mem_ctx); - - - /* - step 2: look for a user account in samdb that has uidNumber set to the - given uid - */ - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "uidNumber=%u", (unsigned int)uid); - for (i=0;i<ret;i++) { - if (!is_user_account(res[i])) continue; - - *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); - talloc_free(tmp_ctx); - NT_STATUS_HAVE_NO_MEMORY(*sid); - return NT_STATUS_OK; - } - - /* - step 3: look for a user account in samdb that has unixName - or sAMAccountName set to the name given by getpwuid() - */ - pwd = getpwuid(uid); - if (pwd == NULL) { - goto allocate_sid; - } - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "(|(unixName=%s)(sAMAccountName=%s))", - pwd->pw_name, pwd->pw_name); - for (i=0;i<ret;i++) { - if (!is_user_account(res[i])) continue; - - *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); - talloc_free(tmp_ctx); - NT_STATUS_HAVE_NO_MEMORY(*sid); - return NT_STATUS_OK; - } - - - /* - step 4: assign a SID by adding the uid to - SIDMAP_LOCAL_USER_BASE in the local domain - */ -allocate_sid: - if (uid > SIDMAP_MAX_LOCAL_UID) { - return NT_STATUS_NONE_MAPPED; - } - - status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return status; - } - - *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_USER_BASE + uid); - talloc_free(tmp_ctx); - - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - - -/* - map a unix gid to a dom_sid - the returned sid is allocated in the supplied mem_ctx -*/ -NTSTATUS sidmap_gid_to_sid(struct sidmap_context *sidmap, - TALLOC_CTX *mem_ctx, - const gid_t gid, struct dom_sid **sid) -{ - const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL }; - int ret, i; - TALLOC_CTX *tmp_ctx; - struct ldb_message **res; - struct group *grp; - struct dom_sid *domain_sid; - NTSTATUS status; - - /* - we search for the mapping in the following order: - - - check if the gid is in the dynamic gid range assigned for winbindd - use. If it is, then look in winbindd sid mapping - database (not implemented yet) - - look for a group account in samdb that has gidNumber set to the - given gid - - look for a group account in samdb that has unixName or - sAMAccountName set to the name given by getgrgid() - - assign a SID by adding the gid to SIDMAP_LOCAL_GROUP_BASE in the local - domain - */ - - - tmp_ctx = talloc_new(sidmap); - - - /* - step 2: look for a group account in samdb that has gidNumber set to the - given gid - */ - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "gidNumber=%u", (unsigned int)gid); - for (i=0;i<ret;i++) { - if (!is_group_account(res[i])) continue; - - *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); - talloc_free(tmp_ctx); - NT_STATUS_HAVE_NO_MEMORY(*sid); - return NT_STATUS_OK; - } - - /* - step 3: look for a group account in samdb that has unixName - or sAMAccountName set to the name given by getgrgid() - */ - grp = getgrgid(gid); - if (grp == NULL) { - goto allocate_sid; - } - - ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, - "(|(unixName=%s)(sAMAccountName=%s))", - grp->gr_name, grp->gr_name); - for (i=0;i<ret;i++) { - if (!is_group_account(res[i])) continue; - - *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); - talloc_free(tmp_ctx); - NT_STATUS_HAVE_NO_MEMORY(*sid); - return NT_STATUS_OK; - } - - - /* - step 4: assign a SID by adding the gid to - SIDMAP_LOCAL_GROUP_BASE in the local domain - */ -allocate_sid: - if (gid > SIDMAP_MAX_LOCAL_GID) { - return NT_STATUS_NONE_MAPPED; - } - - status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return status; - } - - *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_GROUP_BASE + gid); - talloc_free(tmp_ctx); - - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/* - check if a sid is in the range of auto-allocated SIDs from our primary domain, - and if it is, then return the name and atype -*/ -NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap, - TALLOC_CTX *mem_ctx, - const struct dom_sid *sid, - const char **name, - enum lsa_SidType *rtype) -{ - NTSTATUS status; - struct dom_sid *domain_sid; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - uint32_t rid, atype; - - status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); - if (!NT_STATUS_IS_OK(status)) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - if (!dom_sid_in_domain(domain_sid, sid)) { - talloc_free(tmp_ctx); - return NT_STATUS_NONE_MAPPED; - } - - talloc_free(tmp_ctx); - - rid = sid->sub_auths[sid->num_auths-1]; - if (rid < SIDMAP_LOCAL_USER_BASE) { - return NT_STATUS_NONE_MAPPED; - } - - if (rid < SIDMAP_LOCAL_GROUP_BASE) { - struct passwd *pwd; - uid_t uid = rid - SIDMAP_LOCAL_USER_BASE; - atype = ATYPE_NORMAL_ACCOUNT; - *rtype = ds_atype_map(atype); - - pwd = getpwuid(uid); - if (pwd == NULL) { - *name = talloc_asprintf(mem_ctx, "uid%u", uid); - } else { - *name = talloc_strdup(mem_ctx, pwd->pw_name); - } - } else { - struct group *grp; - gid_t gid = rid - SIDMAP_LOCAL_GROUP_BASE; - atype = ATYPE_LOCAL_GROUP; - *rtype = ds_atype_map(atype); - grp = getgrgid(gid); - if (grp == NULL) { - *name = talloc_asprintf(mem_ctx, "gid%u", gid); - } else { - *name = talloc_strdup(mem_ctx, grp->gr_name); - } - } - - if (*name == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 45f19e93bb..c9562b0de7 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -1433,63 +1433,6 @@ struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx } /* - * This works out if we are running on a supported forest/domain function - * level. Basically this means that we don't support mixed/interim (NT 4 DC - * support) levels. - * If errmsg isn't NULL we write in an adequate error message for printing out - * to the screen. - */ -bool samdb_is_capable_dc(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, - char **errmsg) -{ - int32_t level_forest, level_domain, level_domain_mixed; - bool ret = true; - - level_forest = (int32_t) samdb_search_int64(ldb, mem_ctx, -1, - samdb_partitions_dn(ldb, mem_ctx), "msDS-Behavior-Version", - NULL); - level_domain = (int32_t) samdb_search_int64(ldb, mem_ctx, -1, - samdb_base_dn(ldb), "msDS-Behavior-Version", NULL); - level_domain_mixed = (int32_t) samdb_search_int64(ldb, mem_ctx, -1, - samdb_base_dn(ldb), "nTMixedDomain", NULL); - - if (errmsg != NULL) - *errmsg = talloc_strdup(mem_ctx, ""); - - if (level_forest == -1 || level_domain == -1 || level_domain_mixed == -1) { - ret = false; - if (errmsg != NULL) - *errmsg = talloc_strdup_append(*errmsg, - "\nATTENTION: Invalid values for forest and/or domain function level!" - ); - } - - if (level_forest == DS_DOMAIN_FUNCTION_2003_MIXED) { - ret = false; - if (errmsg != NULL) - *errmsg = talloc_strdup_append(*errmsg, - "\nATTENTION: You run SAMBA 4 on the 2003 with mixed domains (NT4 DC support) forest level. This isn't supported!" - ); - } - if ((level_domain == DS_DOMAIN_FUNCTION_2000 && level_domain_mixed != 0) - || level_domain == DS_DOMAIN_FUNCTION_2003_MIXED) { - ret = false; - if (errmsg != NULL) - *errmsg = talloc_strdup_append(*errmsg, - "\nATTENTION: You run SAMBA 4 on a mixed/interim (NT4 DC support) domain level. This isn't supported!" - ); - } - - if ((!ret) && (errmsg != NULL)) { - *errmsg = talloc_strdup_append(*errmsg, - "\nPlease raise the domain and/or forest level to an adequate value. Use for this the 'domainlevel' tool, the MS AD MMC tools or manipulate the needed attributes directly." - ); - } - - return ret; -} - -/* work out if we are the PDC for the domain of the current open ldb */ bool samdb_is_pdc(struct ldb_context *ldb) @@ -1588,7 +1531,7 @@ int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs, - "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))"); + "(|(objectClass=domain)(objectClass=builtinDomain))"); if (ret == LDB_SUCCESS) { if (res->count == 1) { break; @@ -1640,21 +1583,22 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, struct samr_Password *param_lmNewHash, struct samr_Password *param_ntNewHash, bool user_change, - enum samr_RejectReason *reject_reason, + enum samPwdChangeReason *reject_reason, struct samr_DomInfo1 **_dominfo) { - const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", + const char * const user_attrs[] = { "userAccountControl", + "lmPwdHistory", "ntPwdHistory", "dBCSPwd", "unicodePwd", "objectSid", "pwdLastSet", NULL }; - const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", - "maxPwdAge", "minPwdAge", - "minPwdLength", NULL }; + const char * const domain_attrs[] = { "minPwdLength", "pwdProperties", + "pwdHistoryLength", + "maxPwdAge", "minPwdAge", NULL }; NTTIME pwdLastSet; - int64_t minPwdAge; - uint_t minPwdLength, pwdProperties, pwdHistoryLength; - uint_t userAccountControl; + uint32_t minPwdLength, pwdProperties, pwdHistoryLength; + int64_t maxPwdAge, minPwdAge; + uint32_t userAccountControl; struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash; struct samr_Password local_lmNewHash, local_ntNewHash; @@ -1675,14 +1619,14 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, if (count != 1) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } - userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0); - sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], - "lmPwdHistory", &sambaLMPwdHistory); - sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], - "ntPwdHistory", &sambaNTPwdHistory); - lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd"); - ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd"); - pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0); + userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0); + sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], + "lmPwdHistory", &sambaLMPwdHistory); + sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], + "ntPwdHistory", &sambaNTPwdHistory); + lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd"); + ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd"); + pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0); /* Copy parameters */ lmNewHash = param_lmNewHash; @@ -1695,9 +1639,10 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, |UF_WORKSTATION_TRUST_ACCOUNT |UF_SERVER_TRUST_ACCOUNT)); - if (domain_dn) { + if (domain_dn != NULL) { /* pull the domain parameters */ - count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs); + count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, + domain_attrs); if (count != 1) { DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", ldb_dn_get_linearized(domain_dn), @@ -1706,14 +1651,15 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, } } else { /* work out the domain sid, and pull the domain from there */ - domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid"); + domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], + "objectSid"); if (domain_sid == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, - "(objectSid=%s)", - ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); + "(objectSid=%s)", + ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); if (count != 1) { DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", dom_sid_string(mem_ctx, domain_sid), @@ -1722,17 +1668,18 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, } } - pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0); - pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0); - minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); - minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0); + minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); + pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0); + pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0); + maxPwdAge = samdb_result_int64(res[0], "maxPwdAge", 0); + minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0); - if (userAccountControl & UF_PASSWD_NOTREQD) { + if ((userAccountControl & UF_PASSWD_NOTREQD) != 0) { /* see [MS-ADTS] 2.2.15 */ minPwdLength = 0; } - if (_dominfo) { + if (_dominfo != NULL) { struct samr_DomInfo1 *dominfo; /* on failure we need to fill in the reject reasons */ dominfo = talloc(mem_ctx, struct samr_DomInfo1); @@ -1742,24 +1689,27 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, dominfo->min_password_length = minPwdLength; dominfo->password_properties = pwdProperties; dominfo->password_history_length = pwdHistoryLength; - dominfo->max_password_age = minPwdAge; + dominfo->max_password_age = maxPwdAge; dominfo->min_password_age = minPwdAge; *_dominfo = dominfo; } - if (restrictions && new_password) { + if ((restrictions != 0) && (new_password != 0)) { char *new_pass; - /* check the various password restrictions */ - if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) { + /* checks if the "minPwdLength" property is satisfied */ + if ((restrictions != 0) + && (minPwdLength > utf16_len_n( + new_password->data, new_password->length)/2)) { if (reject_reason) { - *reject_reason = SAMR_REJECT_TOO_SHORT; + *reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT; } return NT_STATUS_PASSWORD_RESTRICTION; } /* Create the NT hash */ - mdfour(local_ntNewHash.hash, new_password->data, new_password->length); + mdfour(local_ntNewHash.hash, new_password->data, + new_password->length); ntNewHash = &local_ntNewHash; @@ -1770,11 +1720,13 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, new_password->data, new_password->length, (void **)&new_pass, NULL, false)) { - /* possibly check password complexity */ - if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) && - !check_password_quality(new_pass)) { + /* checks the password complexity */ + if ((restrictions != 0) + && ((pwdProperties + & DOMAIN_PASSWORD_COMPLEX) != 0) + && (!check_password_quality(new_pass))) { if (reject_reason) { - *reject_reason = SAMR_REJECT_COMPLEXITY; + *reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX; } return NT_STATUS_PASSWORD_RESTRICTION; } @@ -1786,63 +1738,69 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, } } - if (restrictions && user_change) { + if ((restrictions != 0) && user_change) { /* are all password changes disallowed? */ - if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { + if ((pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) != 0) { if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; + *reject_reason = SAM_PWD_CHANGE_NO_ERROR; } return NT_STATUS_PASSWORD_RESTRICTION; } - /* can this user change password? */ - if (userAccountControl & UF_PASSWD_CANT_CHANGE) { + /* can this user change the password? */ + if ((userAccountControl & UF_PASSWD_CANT_CHANGE) != 0) { if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; + *reject_reason = SAM_PWD_CHANGE_NO_ERROR; } return NT_STATUS_PASSWORD_RESTRICTION; } - /* yes, this is a minus. The ages are in negative 100nsec units! */ + /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */ if (pwdLastSet - minPwdAge > now_nt) { if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; + *reject_reason = SAM_PWD_CHANGE_NO_ERROR; } return NT_STATUS_PASSWORD_RESTRICTION; } /* check the immediately past password */ if (pwdHistoryLength > 0) { - if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) { + if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, + lmPwdHash->hash, 16) == 0) { if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; + *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY; } return NT_STATUS_PASSWORD_RESTRICTION; } - if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) { + if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, + ntPwdHash->hash, 16) == 0) { if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; + *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY; } return NT_STATUS_PASSWORD_RESTRICTION; } } /* check the password history */ - sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength); - sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength); + sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, + pwdHistoryLength); + sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, + pwdHistoryLength); for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) { - if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) { + if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, + 16) == 0) { if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; + *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY; } return NT_STATUS_PASSWORD_RESTRICTION; } } for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) { - if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) { + if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, + 16) == 0) { if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; + *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY; } return NT_STATUS_PASSWORD_RESTRICTION; } @@ -1852,7 +1810,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0) /* the password is acceptable. Start forming the new fields */ - if (new_password) { + if (new_password != NULL) { /* if we know the cleartext UTF16 password, then set it. * Modules in ldb will set all the appropriate * hashes */ @@ -1875,6 +1833,9 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, } } + if (reject_reason) { + *reject_reason = SAM_PWD_CHANGE_NO_ERROR; + } return NT_STATUS_OK; } @@ -1893,7 +1854,7 @@ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, struct samr_Password *lmNewHash, struct samr_Password *ntNewHash, bool user_change, - enum samr_RejectReason *reject_reason, + enum samPwdChangeReason *reject_reason, struct samr_DomInfo1 **_dominfo) { NTSTATUS nt_status; @@ -2567,3 +2528,53 @@ int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1, { return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); } + +/* + see if we are a RODC + + TODO: This should take a sam_ctx, and lookup the right object (with + a cache) +*/ +bool samdb_rodc(struct loadparm_context *lp_ctx) +{ + return lp_parm_bool(lp_ctx, NULL, "repl", "RODC", false); +} + + +/* + return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 + + flags are DS_NTDS_OPTION_* +*/ +int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options) +{ + TALLOC_CTX *tmp_ctx; + const char *attrs[] = { "options", NULL }; + int ret; + struct ldb_result *res; + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); + if (ret) { + goto failed; + } + + if (res->count != 1) { + goto failed; + } + + *options = samdb_result_uint(res->msgs[0], "options", 0); + + talloc_free(tmp_ctx); + + return LDB_SUCCESS; + +failed: + DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n")); + talloc_free(tmp_ctx); + return LDB_ERR_NO_SUCH_OBJECT; +} diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index 4150ba0d54..59daa745e9 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -25,7 +25,6 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/samdb_proto.h,$(SAMDB_OB PRIVATE_DEPENDENCIES = LIBLDB SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \ - sidmap.o \ util.o) \ ../libds/common/flag_mapping.o $(eval $(call proto_header_template,$(dsdbsrcdir)/common/proto.h,$(SAMDB_COMMON_OBJ_FILES:.o=.c))) @@ -40,7 +39,8 @@ SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \ schema_syntax.o \ schema_description.o \ schema_convert_to_ol.o \ - schema_inferiors.o) + schema_inferiors.o \ + schema_prefixmap.o) $(eval $(call proto_header_template,$(dsdbsrcdir)/schema/proto.h,$(SAMDB_SCHEMA_OBJ_FILES:.o=.c))) # PUBLIC_HEADERS += dsdb/schema/schema.h diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c index 44e0c7ae8b..30d43033cb 100644 --- a/source4/dsdb/kcc/kcc_periodic.c +++ b/source4/dsdb/kcc/kcc_periodic.c @@ -152,7 +152,7 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c r1->other_info = talloc_zero(reps, struct repsFromTo1OtherInfo); r1->other_info->dns_name = talloc_asprintf(r1->other_info, "%s._msdcs.%s", GUID_string(mem_ctx, &ntds_guid), - lp_realm(s->task->lp_ctx)); + lp_dnsdomain(s->task->lp_ctx)); r1->source_dsa_obj_guid = ntds_guid; r1->source_dsa_invocation_id = invocation_id; r1->replica_flags = diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c index 5c63c111f3..c86956c42f 100644 --- a/source4/dsdb/repl/drepl_out_helpers.c +++ b/source4/dsdb/repl/drepl_out_helpers.c @@ -506,10 +506,9 @@ static void dreplsrv_update_refs_send(struct dreplsrv_op_pull_source_state *st) ntds_guid_str = GUID_string(r, &service->ntds_guid); if (composite_nomem(ntds_guid_str, c)) return; - /* lp_realm() is not really right here */ ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s", ntds_guid_str, - lp_realm(service->task->lp_ctx)); + lp_dnsdomain(service->task->lp_ctx)); if (composite_nomem(ntds_dns_name, c)) return; r->in.bind_handle = &drsuapi->bind_handle; @@ -520,7 +519,7 @@ static void dreplsrv_update_refs_send(struct dreplsrv_op_pull_source_state *st) r->in.req.req1.options = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE; - if (!lp_parm_bool(service->task->lp_ctx, NULL, "repl", "RODC", false)) { + if (!samdb_rodc(service->task->lp_ctx)) { r->in.req.req1.options |= DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE; } diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index 5d7ae11a57..ec5dcd4720 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -424,35 +424,78 @@ WERROR dsdb_origin_objects_commit(struct ldb_context *ldb, return WERR_OK; } + ret = ldb_transaction_start(ldb); + if (ret != LDB_SUCCESS) { + return WERR_DS_INTERNAL_FAILURE; + } + objects = talloc_array(mem_ctx, struct ldb_message *, num_objects); - W_ERROR_HAVE_NO_MEMORY(objects); + if (objects == NULL) { + status = WERR_NOMEM; + goto cancel; + } for (i=0, cur = first_object; cur; cur = cur->next_object, i++) { status = dsdb_convert_object(ldb, schema, cur, objects, &objects[i]); - W_ERROR_NOT_OK_RETURN(status); + if (!W_ERROR_IS_OK(status)) { + goto cancel; + } } ids = talloc_array(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier2, num_objects); - W_ERROR_HAVE_NO_MEMORY(objects); + if (ids == NULL) { + status = WERR_NOMEM; + goto cancel; + } for (i=0; i < num_objects; i++) { struct dom_sid *sid = NULL; + struct ldb_request *add_req; DEBUG(6,(__location__ ": adding %s\n", ldb_dn_get_linearized(objects[i]->dn))); + + ret = ldb_build_add_req(&add_req, + ldb, + objects, + objects[i], + NULL, + NULL, + ldb_op_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + status = WERR_DS_INTERNAL_FAILURE; + goto cancel; + } + + ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL); + if (ret != LDB_SUCCESS) { + status = WERR_DS_INTERNAL_FAILURE; + goto cancel; + } - ret = ldb_add(ldb, objects[i]); - if (ret != 0) { + ret = ldb_request(ldb, add_req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(add_req->handle, LDB_WAIT_ALL); + } + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed add of %s - %s\n", + ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb))); + status = WERR_DS_INTERNAL_FAILURE; goto cancel; } + + talloc_free(add_req); + ret = ldb_search(ldb, objects, &res, objects[i]->dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); - if (ret != 0) { + if (ret != LDB_SUCCESS) { + status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID"); @@ -464,13 +507,19 @@ WERROR dsdb_origin_objects_commit(struct ldb_context *ldb, } } + ret = ldb_transaction_commit(ldb); + if (ret != LDB_SUCCESS) { + return WERR_DS_INTERNAL_FAILURE; + } + talloc_free(objects); *_num = num_objects; *_ids = ids; return WERR_OK; + cancel: talloc_free(objects); ldb_transaction_cancel(ldb); - return WERR_FOOBAR; + return status; } diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c index 723f51356a..8f7f481e2d 100644 --- a/source4/dsdb/samdb/cracknames.c +++ b/source4/dsdb/samdb/cracknames.c @@ -1288,11 +1288,9 @@ NTSTATUS crack_name_to_nt4_name(TALLOC_CTX *mem_ctx, } p[0] = '\0'; - if (p[1]) { - *nt4_account = talloc_strdup(mem_ctx, &p[1]); - if (*nt4_account == NULL) { - return NT_STATUS_NO_MEMORY; - } + *nt4_account = talloc_strdup(mem_ctx, &p[1]); + if (*nt4_account == NULL) { + return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index 1b02abcb8e..2f123145db 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -802,6 +802,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } +/* TODO Is this really right? */ /* if (what_is_user(module) == SECURITY_SYSTEM) */ return ldb_next_request(module, req); @@ -813,7 +814,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) ac->user_type = what_is_user(module); ac->sec_result = LDB_SUCCESS; if (!is_root_base_dn(ldb, req->op.mod.message->dn) && parent && !is_root_base_dn(ldb, parent)){ - filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", + filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", ldb_dn_get_component_name(parent,0), ldb_dn_get_component_val(parent,0)->data, ldb_dn_get_component_name(req->op.mod.message->dn,0), diff --git a/source4/dsdb/samdb/ldb_modules/anr.c b/source4/dsdb/samdb/ldb_modules/anr.c index deeccac072..a5220b3f91 100644 --- a/source4/dsdb/samdb/ldb_modules/anr.c +++ b/source4/dsdb/samdb/ldb_modules/anr.c @@ -67,8 +67,10 @@ static struct ldb_parse_tree *make_parse_list(struct ldb_module *module, * Make an equality or prefix match tree, from the attribute, operation and matching value supplied */ static struct ldb_parse_tree *make_match_tree(struct ldb_module *module, - TALLOC_CTX *mem_ctx, enum ldb_parse_op op, - const char *attr, const DATA_BLOB *match) + TALLOC_CTX *mem_ctx, + enum ldb_parse_op op, + const char *attr, + struct ldb_val *match) { struct ldb_context *ldb; struct ldb_parse_tree *match_tree; @@ -123,7 +125,7 @@ struct anr_context { */ static int anr_replace_value(struct anr_context *ac, TALLOC_CTX *mem_ctx, - const struct ldb_val *match, + struct ldb_val *match, struct ldb_parse_tree **ntree) { struct ldb_parse_tree *tree = NULL; @@ -146,7 +148,7 @@ static int anr_replace_value(struct anr_context *ac, ac->found_anr = true; if (match->length > 1 && match->data[0] == '=') { - DATA_BLOB *match2 = talloc(mem_ctx, DATA_BLOB); + struct ldb_val *match2 = talloc(mem_ctx, struct ldb_val); *match2 = data_blob_const(match->data+1, match->length - 1); if (match2 == NULL){ ldb_oom(ldb); @@ -181,8 +183,8 @@ static int anr_replace_value(struct anr_context *ac, if (p) { struct ldb_parse_tree *first_split_filter, *second_split_filter, *split_filters, *match_tree_1, *match_tree_2; - DATA_BLOB *first_match = talloc(tree, DATA_BLOB); - DATA_BLOB *second_match = talloc(tree, DATA_BLOB); + struct ldb_val *first_match = talloc(tree, struct ldb_val); + struct ldb_val *second_match = talloc(tree, struct ldb_val); if (!first_match || !second_match) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index a49b238591..ea4e722822 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -1,4 +1,14 @@ ################################################ +# Start SUBSYSTEM DSDB_MODULE_HELPERS +[SUBSYSTEM::DSDB_MODULE_HELPERS] +PRIVATE_DEPENDENCIES = LIBLDB + +DSDB_MODULE_HELPERS_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/util.o + +$(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/ldb_modules/util_proto.h,$(DSDB_MODULE_HELPERS_OBJ_FILES:.o=.c))) + + +################################################ # Start MODULE ldb_objectguid [MODULE::ldb_objectguid] SUBSYSTEM = LIBLDB @@ -15,7 +25,7 @@ ldb_objectguid_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/objectguid.o SUBSYSTEM = LIBLDB PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS \ LIBNDR NDR_DRSUAPI \ - NDR_DRSBLOBS LIBNDR + NDR_DRSBLOBS LIBNDR DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(repl_meta_data) # End MODULE ldb_repl_meta_data ################################################ @@ -39,7 +49,7 @@ ldb_dsdb_cache_OBJ_FILES = \ # Start MODULE ldb_schema_fsmo [MODULE::ldb_schema_fsmo] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(schema_fsmo) # End MODULE ldb_schema_fsmo ################################################ @@ -51,7 +61,7 @@ ldb_schema_fsmo_OBJ_FILES = \ # Start MODULE ldb_naming_fsmo [MODULE::ldb_naming_fsmo] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(naming_fsmo) # End MODULE ldb_naming_fsmo ################################################ @@ -63,7 +73,7 @@ ldb_naming_fsmo_OBJ_FILES = \ # Start MODULE ldb_pdc_fsmo [MODULE::ldb_pdc_fsmo] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(pdc_fsmo) # End MODULE ldb_pdc_fsmo ################################################ @@ -220,7 +230,7 @@ ldb_show_deleted_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/show_deleted.o # Start MODULE ldb_partition [MODULE::ldb_partition] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS SAMDB DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(partition) # End MODULE ldb_partition ################################################ @@ -369,3 +379,15 @@ INIT_FUNCTION = LDB_MODULE(acl) ################################################ ldb_acl_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/acl.o + +################################################ +# Start MODULE ldb_lazy_commit +[MODULE::ldb_lazy_commit] +PRIVATE_DEPENDENCIES = SAMDB +SUBSYSTEM = LIBLDB +INIT_FUNCTION = LDB_MODULE(lazy_commit) + +# End MODULE ldb_lazy_commit +################################################ + +ldb_lazy_commit_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/lazy_commit.o diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c index f93090ace9..bb5e3795db 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c @@ -340,7 +340,8 @@ static int extended_callback(struct ldb_request *req, struct ldb_reply *ares) } /* Look to see if this attributeSyntax is a DN */ - if (strcmp(attribute->attributeSyntax_oid, "2.5.5.1") != 0) { + if (strcmp(attribute->attributeSyntax_oid, "2.5.5.1") != 0 && + strcmp(attribute->attributeSyntax_oid, "2.5.5.7") != 0) { continue; } @@ -617,7 +618,8 @@ static int extended_dn_out_dereference_init(struct ldb_module *module) NULL }; - if (strcmp(cur->syntax->attributeSyntax_oid, "2.5.5.1") != 0) { + if (strcmp(cur->syntax->attributeSyntax_oid, "2.5.5.1") != 0 && + strcmp(cur->syntax->attributeSyntax_oid, "2.5.5.7") != 0) { continue; } dereference_control->dereference diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_store.c b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c index 3234f6f269..122a9bb2b7 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn_store.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c @@ -303,7 +303,8 @@ static int extended_dn_add(struct ldb_module *module, struct ldb_request *req) } /* We only setup an extended DN GUID on these particular DN objects */ - if (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") != 0) { + if (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") != 0 && + strcmp(schema_attr->attributeSyntax_oid, "2.5.5.7") != 0) { continue; } @@ -376,7 +377,8 @@ static int extended_dn_modify(struct ldb_module *module, struct ldb_request *req } /* We only setup an extended DN GUID on these particular DN objects */ - if (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") != 0) { + if (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") != 0 && + strcmp(schema_attr->attributeSyntax_oid, "2.5.5.7") != 0) { continue; } diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c index de46c0a42a..201ed04412 100644 --- a/source4/dsdb/samdb/ldb_modules/instancetype.c +++ b/source4/dsdb/samdb/ldb_modules/instancetype.c @@ -77,8 +77,6 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) struct it_context *ac; uint32_t instance_type; int ret; - const struct ldb_control *partition_ctrl; - const struct dsdb_control_current_partition *partition; ldb = ldb_module_get_ctx(module); @@ -90,31 +88,19 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) } if (ldb_msg_find_element(req->op.add.message, "instanceType")) { + unsigned int instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0); + + if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) { + /* Do something in future */ + } + /* TODO: we need to validate and possibly create a new partition */ return ldb_next_request(module, req); } - partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID); - if (!partition_ctrl) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "instancetype_add: no current partition control found"); - return LDB_ERR_CONSTRAINT_VIOLATION; - } - - partition = talloc_get_type(partition_ctrl->data, - struct dsdb_control_current_partition); - SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION); - - ac = talloc(req, struct it_context); - if (ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ac->module = module; - ac->req = req; - /* we have to copy the message as the caller might have it as a const */ - msg = ldb_msg_copy_shallow(ac, req->op.add.message); + msg = ldb_msg_copy_shallow(req, req->op.add.message); if (msg == NULL) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; @@ -124,12 +110,6 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) * TODO: calculate correct instance type */ instance_type = INSTANCE_TYPE_WRITE; - if (ldb_dn_compare(partition->dn, msg->dn) == 0) { - instance_type |= INSTANCE_TYPE_IS_NC_HEAD; - if (ldb_dn_compare(msg->dn, samdb_base_dn(ldb)) != 0) { - instance_type |= INSTANCE_TYPE_NC_ABOVE; - } - } ret = ldb_msg_add_fmt(msg, "instanceType", "%u", instance_type); if (ret != LDB_SUCCESS) { @@ -137,10 +117,10 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - ret = ldb_build_add_req(&down_req, ldb, ac, + ret = ldb_build_add_req(&down_req, ldb, req, msg, req->controls, - ac, it_callback, + req->context, req->callback, req); if (ret != LDB_SUCCESS) { return ret; diff --git a/source4/dsdb/samdb/ldb_modules/kludge_acl.c b/source4/dsdb/samdb/ldb_modules/kludge_acl.c index 34f848de8a..79309e82bf 100644 --- a/source4/dsdb/samdb/ldb_modules/kludge_acl.c +++ b/source4/dsdb/samdb/ldb_modules/kludge_acl.c @@ -379,7 +379,7 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req) ac, kludge_acl_callback, req); if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; + return ret; } /* check if there's an SD_FLAGS control */ diff --git a/source4/dsdb/samdb/ldb_modules/lazy_commit.c b/source4/dsdb/samdb/ldb_modules/lazy_commit.c new file mode 100644 index 0000000000..69ac99e246 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/lazy_commit.c @@ -0,0 +1,132 @@ +/* + ldb database library + + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ldb lazy_commit module + * + * Description: module to pretend to support the 'lazy commit' control + * + * Author: Andrew Bartlett + */ + +#include "ldb_module.h" + +static int unlazy_op(struct ldb_module *module, struct ldb_request *req) +{ + int ret; + struct ldb_request *new_req; + struct ldb_control **saved_controls; + struct ldb_control *control = ldb_request_get_control(req, LDB_CONTROL_SERVER_LAZY_COMMIT); + if (!control) { + return ldb_next_request(module, req); + } + + switch (req->operation) { + case LDB_SEARCH: + ret = ldb_build_search_req_ex(&new_req, ldb_module_get_ctx(module), + req, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->controls, + req->context, req->callback, + req); + break; + case LDB_ADD: + ret = ldb_build_add_req(&new_req, ldb_module_get_ctx(module), req, + req->op.add.message, + req->controls, + req->context, req->callback, + req); + break; + case LDB_MODIFY: + ret = ldb_build_mod_req(&new_req, ldb_module_get_ctx(module), req, + req->op.mod.message, + req->controls, + req->context, req->callback, + req); + break; + case LDB_DELETE: + ret = ldb_build_del_req(&new_req, ldb_module_get_ctx(module), req, + req->op.del.dn, + req->controls, + req->context, req->callback, + req); + break; + case LDB_RENAME: + ret = ldb_build_rename_req(&new_req, ldb_module_get_ctx(module), req, + req->op.rename.olddn, + req->op.rename.newdn, + req->controls, + req->context, req->callback, + req); + break; + case LDB_EXTENDED: + ret = ldb_build_extended_req(&new_req, ldb_module_get_ctx(module), + req, + req->op.extended.oid, + req->op.extended.data, + req->controls, + req->context, req->callback, + req); + break; + default: + ldb_set_errstring(ldb_module_get_ctx(module), + "Unsupported request type!"); + ret = LDB_ERR_UNWILLING_TO_PERFORM; + } + + if (ret != LDB_SUCCESS) { + return ret; + } + + save_controls(control, req, &saved_controls); + return ldb_next_request(module, new_req); +} + +static int unlazy_init(struct ldb_module *module) +{ + int ret; + struct ldb_context *ldb; + ldb = ldb_module_get_ctx(module); + + ret = ldb_mod_register_control(module, LDB_CONTROL_SHOW_DELETED_OID); + if (ret != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "lazy_commit: Unable to register control with rootdse!\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_next_init(module); +} + +const struct ldb_module_ops ldb_lazy_commit_module_ops = { + .name = "lazy_commit", + .search = unlazy_op, + .add = unlazy_op, + .modify = unlazy_op, + .del = unlazy_op, + .rename = unlazy_op, + .request = unlazy_op, + .extended = unlazy_op, + .init_context = unlazy_init, +}; diff --git a/source4/dsdb/samdb/ldb_modules/local_password.c b/source4/dsdb/samdb/ldb_modules/local_password.c index 58c0f1f0d5..9c386b354d 100644 --- a/source4/dsdb/samdb/ldb_modules/local_password.c +++ b/source4/dsdb/samdb/ldb_modules/local_password.c @@ -633,8 +633,7 @@ static int lpdb_delete_callabck(struct ldb_request *req, ret = ldb_next_request(ac->module, search_req); if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + return ldb_module_done(ac->req, NULL, NULL, ret); } return LDB_SUCCESS; } @@ -1082,7 +1081,7 @@ static int local_password_search(struct ldb_module *module, struct ldb_request * ac, lpdb_remote_search_callback, req); if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; + return ret; } /* perform the search */ diff --git a/source4/dsdb/samdb/ldb_modules/naming_fsmo.c b/source4/dsdb/samdb/ldb_modules/naming_fsmo.c index 607bf054d2..15cad259ce 100644 --- a/source4/dsdb/samdb/ldb_modules/naming_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/naming_fsmo.c @@ -28,6 +28,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "../lib/util/dlinklist.h" +#include "dsdb/samdb/ldb_modules/util.h" static int naming_fsmo_init(struct ldb_module *module) { @@ -65,34 +66,15 @@ static int naming_fsmo_init(struct ldb_module *module) } ldb_module_set_private(module, naming_fsmo); - ret = ldb_search(ldb, mem_ctx, &naming_res, - naming_dn, LDB_SCOPE_BASE, - naming_attrs, NULL); + ret = dsdb_module_search_dn(module, mem_ctx, &naming_res, + naming_dn, + naming_attrs); if (ret == LDB_ERR_NO_SUCH_OBJECT) { ldb_debug(ldb, LDB_DEBUG_WARNING, "naming_fsmo_init: no partitions dn present: (skip loading of naming contexts details)\n"); talloc_free(mem_ctx); return ldb_next_init(module); } - if (ret != LDB_SUCCESS) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "naming_fsmo_init: failed to search the cross-ref container: %s: %s", - ldb_strerror(ret), ldb_errstring(ldb)); - talloc_free(mem_ctx); - return ret; - } - if (naming_res->count == 0) { - ldb_debug(ldb, LDB_DEBUG_WARNING, - "naming_fsmo_init: no cross-ref container present: (skip loading of naming contexts details)\n"); - talloc_free(mem_ctx); - return ldb_next_init(module); - } else if (naming_res->count > 1) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "naming_fsmo_init: [%u] cross-ref containers found on a base search", - naming_res->count); - talloc_free(mem_ctx); - return LDB_ERR_CONSTRAINT_VIOLATION; - } naming_fsmo->master_dn = ldb_msg_find_attr_as_dn(ldb, naming_fsmo, naming_res->msgs[0], "fSMORoleOwner"); if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), naming_fsmo->master_dn) == 0) { diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 3cf252c71a..003d6731d4 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Simo Sorce 2006-2008 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009 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 @@ -42,6 +42,7 @@ #include "libcli/security/security.h" #include "auth/auth.h" #include "param/param.h" +#include "../libds/common/flags.h" struct oc_context { @@ -138,7 +139,13 @@ static int objectclass_sort(struct ldb_module *module, if (!current->objectclass) { ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema", (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data); - return LDB_ERR_OBJECT_CLASS_VIOLATION; + /* This looks weird, but windows apparently returns this for invalid objectClass values */ + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } else if (current->objectclass->isDefunct) { + ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects", + (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data); + /* This looks weird, but windows apparently returns this for invalid objectClass values */ + return LDB_ERR_NO_SUCH_ATTRIBUTE; } /* this is the root of the tree. We will start @@ -323,6 +330,8 @@ static int fix_dn(TALLOC_CTX *mem_ctx, struct ldb_dn **fixed_dn) { char *upper_rdn_attr; + const struct ldb_val *rdn_val; + /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */ *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn); @@ -332,15 +341,21 @@ static int fix_dn(TALLOC_CTX *mem_ctx, if (!upper_rdn_attr) { return LDB_ERR_OPERATIONS_ERROR; } - + /* Create a new child */ if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) { return LDB_ERR_OPERATIONS_ERROR; } + /* AD doesn't allow the rDN to be longer than 64 characters */ + rdn_val = ldb_dn_get_rdn_val(newdn); + if (!rdn_val || rdn_val->length > 64) { + DEBUG(2,(__location__ ": rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn))); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + /* And replace it with CN=foo (we need the attribute in upper case */ - return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, - *ldb_dn_get_rdn_val(newdn)); + return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val); } /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */ @@ -355,7 +370,8 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch if (!attribute) { if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) { ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name); - return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE; + /* Apparently Windows sends exactly this behaviour */ + return LDB_ERR_NO_SUCH_ATTRIBUTE; } } else { msg->elements[i].name = attribute->lDAPDisplayName; @@ -374,7 +390,7 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) struct oc_context *ac; struct ldb_dn *parent_dn; int ret; - static const char * const parent_attrs[] = { "objectGUID", NULL }; + static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL }; ldb = ldb_module_get_ctx(module); @@ -458,7 +474,7 @@ static int objectclass_do_add(struct oc_context *ac) ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", ldb_dn_get_linearized(msg->dn)); talloc_free(mem_ctx); - return LDB_ERR_UNWILLING_TO_PERFORM; + return LDB_ERR_NO_SUCH_OBJECT; } } else { const struct ldb_val *parent_guid; @@ -484,9 +500,6 @@ static int objectclass_do_add(struct oc_context *ac) return LDB_ERR_UNWILLING_TO_PERFORM; } - /* TODO: Check this is a valid child to this parent, - * by reading the allowedChildClasses and - * allowedChildClasssesEffective attributes */ ret = ldb_msg_add_steal_value(msg, "parentGUID", discard_const(parent_guid)); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, failed to add parentGUID", @@ -547,7 +560,59 @@ static int objectclass_do_add(struct oc_context *ac) if (!current->next) { struct ldb_message_element *el; int32_t systemFlags = 0; - DATA_BLOB *sd; + const char *rdn_name = ldb_dn_get_rdn_name(msg->dn); + if (current->objectclass->rDNAttID + && ldb_attr_cmp(rdn_name, current->objectclass->rDNAttID) != 0) { + ldb_asprintf_errstring(ldb, + "RDN %s is not correct for most specific structural objectclass %s, should be %s", + rdn_name, current->objectclass->lDAPDisplayName, current->objectclass->rDNAttID); + return LDB_ERR_NAMING_VIOLATION; + } + + if (ac->search_res && ac->search_res->message) { + struct ldb_message_element *oc_el + = ldb_msg_find_element(ac->search_res->message, "objectClass"); + + bool allowed_class = false; + int i, j; + for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) { + const struct dsdb_class *sclass; + + sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]); + if (!sclass) { + /* We don't know this class? what is going on? */ + continue; + } + if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) { + for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) { + if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) { + allowed_class = true; + break; + } + } + } else { + for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) { + if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) { + allowed_class = true; + break; + } + } + } + } + + if (!allowed_class) { + ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s", + current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn)); + return LDB_ERR_NAMING_VIOLATION; + } + } + + if (current->objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) { + ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s", + current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + if (!ldb_msg_find_element(msg, "objectCategory")) { value = talloc_strdup(msg, current->objectclass->defaultObjectCategory); if (value == NULL) { @@ -649,7 +714,13 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req if (!schema) { return ldb_next_request(module, req); } - objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass"); + + /* As with the "real" AD we don't accept empty messages */ + if (req->op.mod.message->num_elements == 0) { + ldb_set_errstring(ldb, "objectclass: modify message must have " + "elements/attributes!"); + return LDB_ERR_UNWILLING_TO_PERFORM; + } ac = oc_init_context(module, req); if (ac == NULL) { @@ -658,6 +729,7 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req /* If no part of this touches the objectClass, then we don't * need to make any changes. */ + objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass"); /* If the only operation is the deletion of the objectClass * then go on with just fixing the attribute case */ @@ -824,6 +896,8 @@ static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares) LDB_ERR_OPERATIONS_ERROR); } + talloc_free(ares); + ret = ldb_build_search_req(&search_req, ldb, ac, ac->req->op.mod.message->dn, LDB_SCOPE_BASE, "(objectClass=*)", @@ -1032,6 +1106,7 @@ static int objectclass_rename_callback(struct ldb_request *req, struct ldb_reply ares->response, ares->error); } + talloc_free(ares); /* the ac->search_res should contain the new parents objectGUID */ parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID"); diff --git a/source4/dsdb/samdb/ldb_modules/objectguid.c b/source4/dsdb/samdb/ldb_modules/objectguid.c index 3d218edc76..12dd402617 100644 --- a/source4/dsdb/samdb/ldb_modules/objectguid.c +++ b/source4/dsdb/samdb/ldb_modules/objectguid.c @@ -209,7 +209,7 @@ static int objectguid_add(struct ldb_module *module, struct ldb_request *req) ac, og_op_callback, req); if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; + return ret; } /* go on with the call chain */ @@ -267,7 +267,7 @@ static int objectguid_modify(struct ldb_module *module, struct ldb_request *req) ac, og_op_callback, req); if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; + return ret; } /* go on with the call chain */ diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 6e86d4c484..c5bbdf8dce 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -829,14 +829,22 @@ static int partition_sequence_number(struct ldb_module *module, struct ldb_reque res, ldb_extended_default_callback, NULL); - ret = ldb_next_request(module, treq); - if (ret == LDB_SUCCESS) { - ret = ldb_wait(treq->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + talloc_free(res); + return ret; } + + ret = ldb_next_request(module, treq); if (ret != LDB_SUCCESS) { talloc_free(res); return ret; } + ret = ldb_wait(treq->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + talloc_free(res); + return ret; + } + seqr = talloc_get_type(res->extended->data, struct ldb_seqnum_result); if (seqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) { @@ -1083,7 +1091,7 @@ static int partition_extended_schema_update_now(struct ldb_module *module, struc } /* fire the first one */ - ret = partition_call_first(ac); + ret = partition_call_first(ac); if (ret != LDB_SUCCESS){ return ret; @@ -1385,14 +1393,14 @@ static int partition_init(struct ldb_module *module) if (ret != LDB_SUCCESS) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "partition: Unable to register control with rootdse!\n"); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID); if (ret != LDB_SUCCESS) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "partition: Unable to register control with rootdse!\n"); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } talloc_free(mem_ctx); diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index fdb044198b..a3c99f4222 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -87,9 +87,9 @@ struct domain_data { bool store_cleartext; uint_t pwdProperties; uint_t pwdHistoryLength; - char *netbios_domain; - char *dns_domain; - char *realm; + const char *netbios_domain; + const char *dns_domain; + const char *realm; }; struct setup_password_fields_io { @@ -1552,9 +1552,8 @@ static int get_domain_data_callback(struct ldb_request *req, struct ldb_context *ldb; struct domain_data *data; struct ph_context *ac; + struct loadparm_context *lp_ctx; int ret; - char *tmp; - char *p; ac = talloc_get_type(req->context, struct ph_context); ldb = ldb_module_get_ctx(ac->module); @@ -1591,43 +1590,13 @@ static int get_domain_data_callback(struct ldb_request *req, * but that doesn't really matter, as it's just used for salt * and kerberos principals, which don't exist here */ - tmp = ldb_dn_canonical_string(data, ares->message->dn); - if (!tmp) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } + lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), + struct loadparm_context); - /* But it puts a trailing (or just before 'builtin') / on things, so kill that */ - p = strchr(tmp, '/'); - if (p) { - p[0] = '\0'; - } - - data->dns_domain = strlower_talloc(data, tmp); - if (data->dns_domain == NULL) { - ldb_oom(ldb); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - data->realm = strupper_talloc(data, tmp); - if (data->realm == NULL) { - ldb_oom(ldb); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */ - p = strchr(tmp, '.'); - if (p) { - p[0] = '\0'; - } - data->netbios_domain = strupper_talloc(data, tmp); - if (data->netbios_domain == NULL) { - ldb_oom(ldb); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } + data->dns_domain = lp_dnsdomain(lp_ctx); + data->realm = lp_realm(lp_ctx); + data->netbios_domain = lp_workgroup(lp_ctx); - talloc_free(tmp); ac->domain = data; break; @@ -1673,7 +1642,7 @@ static int build_domain_data_request(struct ph_context *ac) ldb = ldb_module_get_ctx(ac->module); filter = talloc_asprintf(ac, - "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", + "(objectSid=%s)", ldap_encode_ndr_dom_sid(ac, ac->domain_sid)); if (filter == NULL) { ldb_oom(ldb); @@ -1682,7 +1651,7 @@ static int build_domain_data_request(struct ph_context *ac) return ldb_build_search_req(&ac->dom_req, ldb, ac, ldb_get_default_basedn(ldb), - LDB_SCOPE_SUBTREE, + LDB_SCOPE_BASE, filter, attrs, NULL, ac, get_domain_data_callback, diff --git a/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c b/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c index 950f87eb74..6d814f9334 100644 --- a/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c @@ -27,6 +27,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "../lib/util/dlinklist.h" +#include "dsdb/samdb/ldb_modules/util.h" static int pdc_fsmo_init(struct ldb_module *module) { @@ -64,9 +65,9 @@ static int pdc_fsmo_init(struct ldb_module *module) } ldb_module_set_private(module, pdc_fsmo); - ret = ldb_search(ldb, mem_ctx, &pdc_res, - pdc_dn, LDB_SCOPE_BASE, - pdc_attrs, NULL); + ret = dsdb_module_search_dn(module, mem_ctx, &pdc_res, + pdc_dn, + pdc_attrs); if (ret == LDB_ERR_NO_SUCH_OBJECT) { ldb_debug(ldb, LDB_DEBUG_WARNING, "pdc_fsmo_init: no domain object present: (skip loading of domain details)\n"); @@ -79,19 +80,6 @@ static int pdc_fsmo_init(struct ldb_module *module) talloc_free(mem_ctx); return ret; } - if (pdc_res->count == 0) { - ldb_debug(ldb, LDB_DEBUG_WARNING, - "pdc_fsmo_init: no domain object present: (skip loading of domain details)\n"); - talloc_free(mem_ctx); - return ldb_next_init(module); - } else if (pdc_res->count > 1) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "pdc_fsmo_init: [%u] domain objects found on a base search", - pdc_res->count); - DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb))); - talloc_free(mem_ctx); - return LDB_ERR_CONSTRAINT_VIOLATION; - } pdc_fsmo->master_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, pdc_res->msgs[0], "fSMORoleOwner"); if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc_fsmo->master_dn) == 0) { diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 253596ddea..74dd7e5bbb 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -457,11 +457,14 @@ static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares) static int replmd_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; + struct ldb_control *control; + struct ldb_control **saved_controls; struct replmd_replicated_request *ac; const struct dsdb_schema *schema; enum ndr_err_code ndr_err; struct ldb_request *down_req; struct ldb_message *msg; + const DATA_BLOB *guid_blob; struct GUID guid; struct ldb_val guid_value; struct replPropertyMetaDataBlob nmd; @@ -473,6 +476,14 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) char *time_str; int ret; uint32_t i, ni=0; + bool allow_add_guid = false; + bool remove_current_guid = false; + + /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */ + control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); + if (control) { + allow_add_guid = 1; + } /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.add.message->dn)) { @@ -498,26 +509,43 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) ac->schema = schema; - if (ldb_msg_find_element(req->op.add.message, "objectGUID") != NULL) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, + guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID"); + if ( guid_blob != NULL ) { + if( !allow_add_guid ) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, "replmd_add: it's not allowed to add an object with objectGUID\n"); - return LDB_ERR_UNWILLING_TO_PERFORM; + talloc_free(ac); + return LDB_ERR_UNWILLING_TO_PERFORM; + } else { + NTSTATUS status = GUID_from_data_blob(guid_blob,&guid); + if ( !NT_STATUS_IS_OK(status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "replmd_add: Unable to parse as a GUID the attribute objectGUID\n"); + talloc_free(ac); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + /* we remove this attribute as it can be a string and will not be treated + correctly and then we will readd it latter on in the good format*/ + remove_current_guid = true; + } + } else { + /* a new GUID */ + guid = GUID_random(); } /* Get a sequence number from the backend */ ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); if (ret != LDB_SUCCESS) { + talloc_free(ac); return ret; } - /* a new GUID */ - guid = GUID_random(); - /* get our invocationId */ our_invocation_id = samdb_ntds_invocation_id(ldb); if (!our_invocation_id) { ldb_debug_set(ldb, LDB_DEBUG_ERROR, "replmd_add: unable to find invocationId\n"); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } @@ -525,6 +553,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) msg = ldb_msg_copy_shallow(ac, req->op.add.message); if (msg == NULL) { ldb_oom(ldb); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } @@ -532,8 +561,13 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) unix_to_nt_time(&now, t); time_str = ldb_timestring(msg, t); if (!time_str) { + ldb_oom(ldb); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } + if (remove_current_guid) { + ldb_msg_remove_attr(msg,"objectGUID"); + } /* * remove autogenerated attributes @@ -548,7 +582,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) ret = ldb_msg_add_fmt(msg, "instanceType", "%u", INSTANCE_TYPE_WRITE); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } } @@ -558,7 +593,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) ret = ldb_msg_add_string(msg, "whenCreated", time_str); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } /* build the replication meta_data */ @@ -570,6 +606,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) nmd.ctr.ctr1.count); if (!nmd.ctr.ctr1.array) { ldb_oom(ldb); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } @@ -585,6 +622,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) ldb_debug_set(ldb, LDB_DEBUG_ERROR, "replmd_add: attribute '%s' not defined in schema\n", e->name); + talloc_free(ac); return LDB_ERR_NO_SUCH_ATTRIBUTE; } @@ -612,6 +650,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) */ ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, schema, msg->dn); if (ret != LDB_SUCCESS) { + talloc_free(ac); return ret; } @@ -622,6 +661,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) (ndr_push_flags_fn_t)ndr_push_GUID); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ldb_oom(ldb); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } ndr_err = ndr_push_struct_blob(&nmd_value, msg, @@ -630,6 +670,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ldb_oom(ldb); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } @@ -639,27 +680,32 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } ret = ldb_msg_add_string(msg, "whenChanged", time_str); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", seq_num); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL); if (ret != LDB_SUCCESS) { ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ac); + return ret; } /* @@ -673,14 +719,22 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) ac, replmd_op_callback, req); if (ret != LDB_SUCCESS) { + talloc_free(ac); return ret; } ret = replmd_notify(module, msg->dn, seq_num); if (ret != LDB_SUCCESS) { + talloc_free(ac); return ret; } + /* if a control is there remove if from the modified request */ + if (control && !save_controls(control, down_req, &saved_controls)) { + talloc_free(ac); + return LDB_ERR_OPERATIONS_ERROR; + } + /* go on with the call chain */ return ldb_next_request(module, down_req); } @@ -785,7 +839,7 @@ static int replmd_update_rpmd(struct ldb_module *module, /* search for the existing replPropertyMetaDataBlob */ ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs); - if (ret != LDB_SUCCESS || res->count < 1) { + if (ret != LDB_SUCCESS || res->count != 1) { DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n", ldb_dn_get_linearized(msg->dn))); return LDB_ERR_OPERATIONS_ERROR; @@ -880,9 +934,10 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) const struct dsdb_schema *schema; struct ldb_request *down_req; struct ldb_message *msg; - int ret; + struct ldb_result *res; time_t t = time(NULL); uint64_t seq_num = 0; + int ret; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -911,13 +966,12 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) /* we have to copy the message as the caller might have it as a const */ msg = ldb_msg_copy_shallow(ac, req->op.mod.message); if (msg == NULL) { + ldb_oom(ldb); talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } /* TODO: - * - get the whole old object - * - if the old object doesn't exist report an error * - give an error when a readonly attribute should * be modified * - merge the changed into the old object @@ -926,8 +980,15 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) * attribute was changed */ + ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(ac); + return ret; + } + ret = replmd_update_rpmd(module, msg, &seq_num); if (ret != LDB_SUCCESS) { + talloc_free(ac); return ret; } @@ -941,6 +1002,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) ac, replmd_op_callback, req); if (ret != LDB_SUCCESS) { + talloc_free(ac); return ret; } talloc_steal(down_req, msg); @@ -950,12 +1012,12 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) if (seq_num != 0) { if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { talloc_free(ac); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { talloc_free(ac); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } } diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index a8e08ec3ad..83e4e3b50e 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -722,9 +722,9 @@ static int rootdse_modify(struct ldb_module *module, struct ldb_request *req) } _PUBLIC_ const struct ldb_module_ops ldb_rootdse_module_ops = { - .name = "rootdse", + .name = "rootdse", .init_context = rootdse_init, .search = rootdse_search, - .request = rootdse_request, + .request = rootdse_request, .modify = rootdse_modify }; diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index e59b5dd1ce..2a0bb2dfe6 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -284,8 +284,7 @@ static int samldb_get_parent_domain(struct samldb_ctx *ac) ret = ldb_build_search_req(&req, ldb, ac, dn, LDB_SCOPE_BASE, "(|(objectClass=domain)" - "(objectClass=builtinDomain)" - "(objectClass=samba4LocalDomain))", + "(objectClass=builtinDomain))", attrs, NULL, ac, samldb_get_parent_domain_callback, @@ -559,10 +558,10 @@ static int samldb_get_sid_domain(struct samldb_ctx *ac) /* get the domain component part of the provided SID */ ac->domain_sid->num_auths--; - filter = talloc_asprintf(ac, "(&(objectSid=%s)" - "(|(objectClass=domain)" - "(objectClass=builtinDomain)" - "(objectClass=samba4LocalDomain)))", + filter = talloc_asprintf(ac, + "(&(objectSid=%s)" + "(|(objectClass=domain)" + "(objectClass=builtinDomain)))", ldap_encode_ndr_dom_sid(ac, ac->domain_sid)); if (filter == NULL) { return LDB_ERR_OPERATIONS_ERROR; @@ -699,8 +698,14 @@ static int samldb_check_primaryGroupID_1(struct samldb_ctx *ac) static int samldb_check_primaryGroupID_2(struct samldb_ctx *ac) { - if (ac->res_dn == NULL) + if (ac->res_dn == NULL) { + struct ldb_context *ldb; + ldb = ldb_module_get_ctx(ac->module); + ldb_asprintf_errstring(ldb, + "Failed to find group sid %s", + dom_sid_string(ac->sid, ac->sid)); return LDB_ERR_UNWILLING_TO_PERFORM; + } return samldb_next_step(ac); } @@ -1866,7 +1871,7 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) int ret; ldb = ldb_module_get_ctx(module); - ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n"); + ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n"); /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.add.message->dn)) { diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c index c482ab57df..2b6606c147 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c @@ -5,6 +5,7 @@ checkings, it also loads the dsdb_schema. Copyright (C) Stefan Metzmacher <metze@samba.org> 2007 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009 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 @@ -28,6 +29,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "param/param.h" +#include "dsdb/samdb/ldb_modules/util.h" static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, const struct dsdb_schema *schema); @@ -90,13 +92,107 @@ struct schema_fsmo_search_data { const struct dsdb_schema *schema; }; +/* + Given an LDB module (pointing at the schema DB), and the DN, set the populated schema +*/ + +static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *module, + struct smb_iconv_convenience *iconv_convenience, + struct ldb_dn *schema_dn, + struct dsdb_schema **schema) +{ + TALLOC_CTX *tmp_ctx; + char *error_string; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_result *schema_res; + struct ldb_result *a_res; + struct ldb_result *c_res; + static const char *schema_attrs[] = { + "prefixMap", + "schemaInfo", + "fSMORoleOwner", + NULL + }; + unsigned flags; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* we don't want to trace the schema load */ + flags = ldb_get_flags(ldb); + ldb_set_flags(ldb, flags & ~LDB_FLG_ENABLE_TRACING); + + /* + * setup the prefix mappings and schema info + */ + ret = dsdb_module_search_dn(module, tmp_ctx, &schema_res, + schema_dn, schema_attrs); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } else if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema: failed to search the schema head: %s", + ldb_errstring(ldb)); + goto failed; + } + + /* + * load the attribute definitions + */ + ret = dsdb_module_search(module, tmp_ctx, &a_res, + schema_dn, LDB_SCOPE_ONELEVEL, NULL, + "(objectClass=attributeSchema)"); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema: failed to search attributeSchema objects: %s", + ldb_errstring(ldb)); + goto failed; + } + + /* + * load the objectClass definitions + */ + ret = dsdb_module_search(module, tmp_ctx, &c_res, + schema_dn, LDB_SCOPE_ONELEVEL, NULL, + "(objectClass=classSchema)"); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema: failed to search attributeSchema objects: %s", + ldb_errstring(ldb)); + goto failed; + } + + ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb, + lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), + schema_res, a_res, c_res, schema, &error_string); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema load failed: %s", + error_string); + goto failed; + } + talloc_steal(mem_ctx, *schema); + +failed: + if (flags & LDB_FLG_ENABLE_TRACING) { + flags = ldb_get_flags(ldb); + ldb_set_flags(ldb, flags | LDB_FLG_ENABLE_TRACING); + } + talloc_free(tmp_ctx); + return ret; +} + + static int schema_fsmo_init(struct ldb_module *module) { struct ldb_context *ldb; TALLOC_CTX *mem_ctx; struct ldb_dn *schema_dn; struct dsdb_schema *schema; - char *error_string = NULL; int ret; struct schema_fsmo_private_data *data; @@ -134,9 +230,9 @@ static int schema_fsmo_init(struct ldb_module *module) return LDB_ERR_OPERATIONS_ERROR; } - ret = dsdb_schema_from_schema_dn(mem_ctx, ldb, + ret = dsdb_schema_from_schema_dn(mem_ctx, module, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - schema_dn, &schema, &error_string); + schema_dn, &schema); if (ret == LDB_ERR_NO_SUCH_OBJECT) { ldb_reset_err_string(ldb); @@ -147,9 +243,6 @@ static int schema_fsmo_init(struct ldb_module *module) } if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - "schema_fsmo_init: dsdb_schema load failed: %s", - error_string); talloc_free(mem_ctx); return ret; } @@ -246,7 +339,6 @@ static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *r struct ldb_context *ldb; struct ldb_dn *schema_dn; struct dsdb_schema *schema; - char *error_string = NULL; int ret; TALLOC_CTX *mem_ctx; @@ -270,9 +362,9 @@ static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *r return LDB_ERR_OPERATIONS_ERROR; } - ret = dsdb_schema_from_schema_dn(mem_ctx, ldb, + ret = dsdb_schema_from_schema_dn(mem_ctx, module, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - schema_dn, &schema, &error_string); + schema_dn, &schema); if (ret == LDB_ERR_NO_SUCH_OBJECT) { ldb_reset_err_string(ldb); @@ -283,9 +375,6 @@ static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *r } if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - "schema_fsmo_extended: dsdb_schema load failed: %s", - error_string); talloc_free(mem_ctx); return ldb_next_request(module, req); } diff --git a/source4/dsdb/samdb/ldb_modules/subtree_delete.c b/source4/dsdb/samdb/ldb_modules/subtree_delete.c index 241cc5f7d6..e1ce9c1fa8 100644 --- a/source4/dsdb/samdb/ldb_modules/subtree_delete.c +++ b/source4/dsdb/samdb/ldb_modules/subtree_delete.c @@ -55,6 +55,8 @@ static struct subtree_delete_context *subdel_ctx_init(struct ldb_module *module, ac->module = module; ac->req = req; + ac->num_children = 0; + return ac; } diff --git a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py index fe96b88221..c61d3973a1 100644 --- a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py +++ b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py @@ -313,6 +313,14 @@ class MapTestCase(MapBaseTestCase): # Add a set of split records self.ldb.add_ldif(""" +dn: """+ self.samba4.dn("cn=Domain Users") + """ +objectClass: group +cn: Domain Users +objectSid: S-1-5-21-4231626423-2410014848-2360679739-513 +""") + + # Add a set of split records + self.ldb.add_ldif(""" dn: """+ self.samba4.dn("cn=X") + """ objectClass: user cn: X @@ -459,7 +467,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # errors, letting the search fail with no results. #res = self.ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", scope=SCOPE_DEFAULT, attrs) res = self.ldb.search(expression="(objectSid=*)", base=None, scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon", "objectSid"]) - self.assertEquals(len(res), 3) + self.assertEquals(len(res), 4) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[0]["dnsHostName"]), "x") self.assertEquals(str(res[0]["lastLogon"]), "x") @@ -621,7 +629,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated local attribute res = self.ldb.search(expression="(!(revision=x))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 5) + self.assertEquals(len(res), 6) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") @@ -638,7 +646,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated remote attribute res = self.ldb.search(expression="(!(description=x))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 3) + self.assertEquals(len(res), 4) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[0]["dnsHostName"]), "z") self.assertEquals(str(res[0]["lastLogon"]), "z") @@ -649,7 +657,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated conjunction of local attributes res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 5) + self.assertEquals(len(res), 6) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") @@ -666,7 +674,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated conjunction of remote attributes res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 5) + self.assertEquals(len(res), 6) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[0]["dnsHostName"]), "y") self.assertEquals(str(res[0]["lastLogon"]), "y") @@ -683,7 +691,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated conjunction of local and remote attribute res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 5) + self.assertEquals(len(res), 6) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") @@ -716,7 +724,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated disjunction of remote attributes res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 4) + self.assertEquals(len(res), 5) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[0]["dnsHostName"]), "y") self.assertEquals(str(res[0]["lastLogon"]), "y") @@ -730,7 +738,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by negated disjunction of local and remote attribute res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 4) + self.assertEquals(len(res), 5) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") @@ -743,7 +751,7 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 # Search by complex parse tree res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(len(res), 6) + self.assertEquals(len(res), 7) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c new file mode 100644 index 0000000000..476eb08ed0 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -0,0 +1,128 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + + Copyright (C) Andrew Tridgell 2009 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "ldb.h" +#include "ldb_module.h" + +/* + search for attrs on one DN, in the modules below + */ +int dsdb_module_search_dn(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + struct ldb_result **_res, + struct ldb_dn *basedn, + const char * const *attrs) +{ + int ret; + struct ldb_request *req; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + + tmp_ctx = talloc_new(mem_ctx); + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx, + basedn, + LDB_SCOPE_BASE, + NULL, + attrs, + NULL, + res, + ldb_search_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_next_request(module, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + if (res->count != 1) { + /* we may be reading a DB that does not have the 'check base on search' option... */ + ret = LDB_ERR_NO_SUCH_OBJECT; + } else { + *_res = talloc_steal(mem_ctx, res); + } + talloc_free(tmp_ctx); + return ret; +} + +/* + search for attrs in the modules below + */ +int dsdb_module_search(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + struct ldb_result **_res, + struct ldb_dn *basedn, enum ldb_scope scope, + const char * const *attrs, + const char *expression) +{ + int ret; + struct ldb_request *req; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + + tmp_ctx = talloc_new(mem_ctx); + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx, + basedn, + scope, + expression, + attrs, + NULL, + res, + ldb_search_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_next_request(module, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + if (ret == LDB_SUCCESS) { + *_res = talloc_steal(mem_ctx, res); + } + talloc_free(tmp_ctx); + return ret; +} + diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h new file mode 100644 index 0000000000..0a1ab83c6d --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -0,0 +1,22 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + + Copyright (C) Andrew Tridgell 2009 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "dsdb/samdb/ldb_modules/util_proto.h" diff --git a/source4/dsdb/samdb/samdb_privilege.c b/source4/dsdb/samdb/samdb_privilege.c index e9c6f4c527..e7742c681c 100644 --- a/source4/dsdb/samdb/samdb_privilege.c +++ b/source4/dsdb/samdb/samdb_privilege.c @@ -26,11 +26,30 @@ #include "libcli/security/security.h" #include "../lib/util/util_ldb.h" #include "param/param.h" +#include "ldb_wrap.h" + +/* connect to the privilege database */ +struct ldb_context *privilege_connect(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct loadparm_context *lp_ctx) +{ + char *path; + struct ldb_context *pdb; + + path = private_path(mem_ctx, lp_ctx, "privilege.ldb"); + if (!path) return NULL; + + pdb = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, path, + NULL, NULL, 0, NULL); + talloc_free(path); + + return pdb; +} /* add privilege bits for one sid to a security_token */ -static NTSTATUS samdb_privilege_setup_sid(void *samctx, TALLOC_CTX *mem_ctx, +static NTSTATUS samdb_privilege_setup_sid(struct ldb_context *pdb, TALLOC_CTX *mem_ctx, struct security_token *token, const struct dom_sid *sid) { @@ -43,7 +62,7 @@ static NTSTATUS samdb_privilege_setup_sid(void *samctx, TALLOC_CTX *mem_ctx, sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid); NT_STATUS_HAVE_NO_MEMORY(sidstr); - ret = gendb_search(samctx, mem_ctx, NULL, &res, attrs, "objectSid=%s", sidstr); + ret = gendb_search(pdb, mem_ctx, NULL, &res, attrs, "objectSid=%s", sidstr); talloc_free(sidstr); if (ret != 1) { /* not an error to not match */ @@ -76,7 +95,7 @@ static NTSTATUS samdb_privilege_setup_sid(void *samctx, TALLOC_CTX *mem_ctx, NTSTATUS samdb_privilege_setup(struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct security_token *token) { - void *samctx; + struct ldb_context *pdb; TALLOC_CTX *mem_ctx; int i; NTSTATUS status; @@ -98,8 +117,8 @@ NTSTATUS samdb_privilege_setup(struct tevent_context *ev_ctx, } mem_ctx = talloc_new(token); - samctx = samdb_connect(mem_ctx, ev_ctx, lp_ctx, system_session(mem_ctx, lp_ctx)); - if (samctx == NULL) { + pdb = privilege_connect(mem_ctx, ev_ctx, lp_ctx); + if (pdb == NULL) { talloc_free(mem_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } @@ -107,7 +126,7 @@ NTSTATUS samdb_privilege_setup(struct tevent_context *ev_ctx, token->privilege_mask = 0; for (i=0;i<token->num_sids;i++) { - status = samdb_privilege_setup_sid(samctx, mem_ctx, + status = samdb_privilege_setup_sid(pdb, mem_ctx, token, token->sids[i]); if (!NT_STATUS_IS_OK(status)) { talloc_free(mem_ctx); diff --git a/source4/dsdb/schema/prefixmap.h b/source4/dsdb/schema/prefixmap.h new file mode 100644 index 0000000000..7b28c88749 --- /dev/null +++ b/source4/dsdb/schema/prefixmap.h @@ -0,0 +1,45 @@ +/* + Unix SMB/CIFS implementation. + + DRS::prefixMap data structures + + Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _DSDB_PREFIXMAP_H +#define _DSDB_PREFIXMAP_H + +/** + * oid-prefix in prefixmap + */ +struct dsdb_schema_prefixmap_oid { + uint32_t id; + DATA_BLOB *bin_oid; /* partial binary-oid prefix */ +}; + +/** + * DSDB prefixMap internal presentation + */ +struct dsdb_schema_prefixmap { + uint32_t length; + struct dsdb_schema_prefixmap_oid *prefixes; +}; + + +#include "dsdb/schema/proto.h" + + +#endif /* _DSDB_PREFIXMAP_H */ diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index 4e7e503931..ddd9b375f6 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -119,6 +119,7 @@ struct dsdb_class { const char **mustContain; const char **mayContain; const char **possibleInferiors; + const char **systemPossibleInferiors; const char *defaultSecurityDescriptor; diff --git a/source4/dsdb/schema/schema_inferiors.c b/source4/dsdb/schema/schema_inferiors.c index b02d557c58..ecac74a954 100644 --- a/source4/dsdb/schema/schema_inferiors.c +++ b/source4/dsdb/schema/schema_inferiors.c @@ -149,19 +149,22 @@ void schema_subclasses_order_recurse(struct dsdb_schema *schema, struct dsdb_cla return; } -static void schema_create_subclasses(struct dsdb_schema *schema) +static int schema_create_subclasses(struct dsdb_schema *schema) { - struct dsdb_class *schema_class; + struct dsdb_class *schema_class, *top; for (schema_class=schema->classes; schema_class; schema_class=schema_class->next) { struct dsdb_class *schema_class2 = dsdb_class_by_lDAPDisplayName(schema, schema_class->subClassOf); if (schema_class2 == NULL) { DEBUG(0,("ERROR: no subClassOf for '%s'\n", schema_class->lDAPDisplayName)); - continue; + return LDB_ERR_OPERATIONS_ERROR; } if (schema_class2 && schema_class != schema_class2) { if (schema_class2->subclasses_direct == NULL) { schema_class2->subclasses_direct = str_list_make_empty(schema_class2); + if (!schema_class2->subclasses_direct) { + return LDB_ERR_OPERATIONS_ERROR; + } } schema_class2->subclasses_direct = str_list_add_const(schema_class2->subclasses_direct, schema_class->lDAPDisplayName); @@ -175,7 +178,14 @@ static void schema_create_subclasses(struct dsdb_schema *schema) schema_class->subClass_order = 0; } - schema_subclasses_order_recurse(schema, dsdb_class_by_lDAPDisplayName(schema, "top"), 1); + top = dsdb_class_by_lDAPDisplayName(schema, "top"); + if (!top) { + DEBUG(0,("ERROR: no 'top' class in loaded schema\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + + schema_subclasses_order_recurse(schema, top, 1); + return LDB_SUCCESS; } static void schema_fill_possible_inferiors(struct dsdb_schema *schema, struct dsdb_class *schema_class) @@ -198,6 +208,25 @@ static void schema_fill_possible_inferiors(struct dsdb_schema *schema, struct ds schema_class->possibleInferiors = str_list_unique(schema_class->possibleInferiors); } +static void schema_fill_system_possible_inferiors(struct dsdb_schema *schema, struct dsdb_class *schema_class) +{ + struct dsdb_class *c2; + + for (c2=schema->classes; c2; c2=c2->next) { + char **superiors = schema_posssuperiors(schema, c2); + if (c2->objectClassCategory != 2 + && c2->objectClassCategory != 3 + && str_list_check(superiors, schema_class->lDAPDisplayName)) { + if (schema_class->systemPossibleInferiors == NULL) { + schema_class->systemPossibleInferiors = str_list_make_empty(schema_class); + } + schema_class->systemPossibleInferiors = str_list_add_const(schema_class->systemPossibleInferiors, + c2->lDAPDisplayName); + } + } + schema_class->systemPossibleInferiors = str_list_unique(schema_class->systemPossibleInferiors); +} + /* fill in a string class name from a governs_ID */ @@ -275,16 +304,21 @@ static void schema_fill_from_ids(struct dsdb_schema *schema) } } -void schema_fill_constructed(struct dsdb_schema *schema) +int schema_fill_constructed(struct dsdb_schema *schema) { + int ret; struct dsdb_class *schema_class; schema_fill_from_ids(schema); - schema_create_subclasses(schema); + ret = schema_create_subclasses(schema); + if (ret != LDB_SUCCESS) { + return ret; + } for (schema_class=schema->classes; schema_class; schema_class=schema_class->next) { schema_fill_possible_inferiors(schema, schema_class); + schema_fill_system_possible_inferiors(schema, schema_class); } /* free up our internal cache elements */ @@ -298,4 +332,5 @@ void schema_fill_constructed(struct dsdb_schema *schema) schema_class->subclasses = NULL; schema_class->posssuperiors = NULL; } + return LDB_SUCCESS; } diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index b876ab09fc..f8b7d5dd44 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -29,6 +29,9 @@ #include "librpc/gen_ndr/ndr_drsblobs.h" #include "param/param.h" #include "lib/ldb/include/ldb_module.h" +#include "../lib/util/asn1.h" + +static WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes); struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience) { @@ -50,11 +53,11 @@ WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct d W_ERROR_HAVE_NO_MEMORY(schema->prefixes); for (i=0, j=0; i < ctr->num_mappings; i++) { - if (ctr->mappings[i].oid.oid == NULL) { + if (ctr->mappings[i].oid.binary_oid == NULL) { return WERR_INVALID_PARAM; } - if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) { + if (ctr->mappings[i].oid.binary_oid[0] == 0xFF) { if (ctr->mappings[i].id_prefix != 0) { return WERR_INVALID_PARAM; } @@ -64,21 +67,33 @@ WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct d return WERR_INVALID_PARAM; } - if (ctr->mappings[i].oid.__ndr_size != 21) { + if (ctr->mappings[i].oid.length != 21) { return WERR_INVALID_PARAM; } - schema->schema_info = talloc_strdup(schema, ctr->mappings[i].oid.oid); + schema->schema_info = hex_encode_talloc(schema, + ctr->mappings[i].oid.binary_oid, + ctr->mappings[i].oid.length); W_ERROR_HAVE_NO_MEMORY(schema->schema_info); } else { + DATA_BLOB oid_blob; + const char *partial_oid = NULL; + /* the last array member should contain the magic value not a oid */ if (i == (ctr->num_mappings - 1)) { return WERR_INVALID_PARAM; } + oid_blob = data_blob_const(ctr->mappings[i].oid.binary_oid, + ctr->mappings[i].oid.length); + if (!ber_read_partial_OID_String(schema->prefixes, oid_blob, &partial_oid)) { + DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X", + ctr->mappings[i].id_prefix)); + return WERR_INVALID_PARAM; + } + schema->prefixes[j].id = ctr->mappings[i].id_prefix<<16; - schema->prefixes[j].oid = talloc_asprintf(schema->prefixes, "%s.", - ctr->mappings[i].oid.oid); + schema->prefixes[j].oid = partial_oid; W_ERROR_HAVE_NO_MEMORY(schema->prefixes[j].oid); schema->prefixes[j].oid_len = strlen(schema->prefixes[j].oid); j++; @@ -96,7 +111,7 @@ WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema, WERROR status; enum ndr_err_code ndr_err; struct prefixMapBlob pfm; - char *schema_info; + DATA_BLOB schema_info_blob; TALLOC_CTX *mem_ctx = talloc_new(schema); W_ERROR_HAVE_NO_MEMORY(mem_ctx); @@ -125,12 +140,12 @@ WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema, pfm.ctr.dsdb.num_mappings); W_ERROR_HAVE_NO_MEMORY(pfm.ctr.dsdb.mappings); - schema_info = data_blob_hex_string(pfm.ctr.dsdb.mappings, schemaInfo); - W_ERROR_HAVE_NO_MEMORY(schema_info); + schema_info_blob = data_blob_dup_talloc(pfm.ctr.dsdb.mappings, schemaInfo); + W_ERROR_HAVE_NO_MEMORY(schema_info_blob.data); pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].id_prefix = 0; - pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.__ndr_size = schemaInfo->length; - pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.oid = schema_info; + pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.length = schemaInfo->length; + pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.binary_oid = schema_info_blob.data; /* call the drsuapi version */ status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb); @@ -146,6 +161,7 @@ WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr) { + DATA_BLOB oid_blob; struct drsuapi_DsReplicaOIDMapping_Ctr *ctr; uint32_t i; @@ -158,18 +174,23 @@ WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema, W_ERROR_HAVE_NO_MEMORY(ctr->mappings); for (i=0; i < schema->num_prefixes; i++) { + if (!ber_write_partial_OID_String(ctr->mappings, &oid_blob, schema->prefixes[i].oid)) { + DEBUG(0, ("write_partial_OID failed for %s", schema->prefixes[i].oid)); + return WERR_INTERNAL_ERROR; + } + ctr->mappings[i].id_prefix = schema->prefixes[i].id>>16; - ctr->mappings[i].oid.oid = talloc_strndup(ctr->mappings, - schema->prefixes[i].oid, - schema->prefixes[i].oid_len - 1); - W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid); + ctr->mappings[i].oid.length = oid_blob.length; + ctr->mappings[i].oid.binary_oid = oid_blob.data; } if (include_schema_info) { + oid_blob = strhex_to_data_blob(ctr->mappings, schema->schema_info); + W_ERROR_HAVE_NO_MEMORY(oid_blob.data); + ctr->mappings[i].id_prefix = 0; - ctr->mappings[i].oid.oid = talloc_strdup(ctr->mappings, - schema->schema_info); - W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid); + ctr->mappings[i].oid.length = oid_blob.length; + ctr->mappings[i].oid.binary_oid = oid_blob.data; } *_ctr = ctr; @@ -209,13 +230,14 @@ WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema, WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr) { uint32_t i,j; + DATA_BLOB oid_blob; for (i=0; i < ctr->num_mappings; i++) { - if (ctr->mappings[i].oid.oid == NULL) { + if (ctr->mappings[i].oid.binary_oid == NULL) { return WERR_INVALID_PARAM; } - if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) { + if (ctr->mappings[i].oid.binary_oid[0] == 0xFF) { if (ctr->mappings[i].id_prefix != 0) { return WERR_INVALID_PARAM; } @@ -225,13 +247,19 @@ WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const return WERR_INVALID_PARAM; } - if (ctr->mappings[i].oid.__ndr_size != 21) { + if (ctr->mappings[i].oid.length != 21) { return WERR_INVALID_PARAM; } - if (strcasecmp(schema->schema_info, ctr->mappings[i].oid.oid) != 0) { + oid_blob = strhex_to_data_blob(NULL, schema->schema_info); + W_ERROR_HAVE_NO_MEMORY(oid_blob.data); + + if (memcmp(oid_blob.data, ctr->mappings[i].oid.binary_oid, 21) != 0) { + data_blob_free(&oid_blob); return WERR_DS_DRA_SCHEMA_MISMATCH; } + + data_blob_free(&oid_blob); } else { /* the last array member should contain the magic value not a oid */ if (i == (ctr->num_mappings - 1)) { @@ -239,21 +267,26 @@ WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const } for (j=0; j < schema->num_prefixes; j++) { - size_t oid_len; if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) { continue; } - oid_len = strlen(ctr->mappings[i].oid.oid); + if (!ber_write_partial_OID_String(NULL, &oid_blob, schema->prefixes[j].oid)) { + return WERR_INTERNAL_ERROR; + } - if (oid_len != (schema->prefixes[j].oid_len - 1)) { + if (oid_blob.length != ctr->mappings[j].oid.length) { + data_blob_free(&oid_blob); return WERR_DS_DRA_SCHEMA_MISMATCH; } - if (strncmp(ctr->mappings[i].oid.oid, schema->prefixes[j].oid, oid_len) != 0) { - return WERR_DS_DRA_SCHEMA_MISMATCH; + if (memcmp(ctr->mappings[i].oid.binary_oid, oid_blob.data, oid_blob.length) != 0) { + data_blob_free(&oid_blob); + return WERR_DS_DRA_SCHEMA_MISMATCH; } + data_blob_free(&oid_blob); + break; } @@ -282,7 +315,7 @@ WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CT continue; } - val = talloc_asprintf(mem_ctx, "%s%u", + val = talloc_asprintf(mem_ctx, "%s.%u", schema->prefixes[i].oid, in & 0xFFFF); W_ERROR_HAVE_NO_MEMORY(val); @@ -389,8 +422,6 @@ WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struc DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n")); return WERR_FOOBAR; } - /* Add one because we need to copy the dot */ - size += 1; /* Create a spot in the prefixMap for one more prefix*/ (*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes); @@ -410,37 +441,33 @@ WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struc WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out) { uint32_t i; + char *oid_prefix; + char *pstr; + char *end_str; + unsigned val; - for (i=0; i < num_prefixes; i++) { - const char *val_str; - char *end_str; - unsigned val; + /* make oid prefix, i.e. oid w/o last subidentifier */ + pstr = strrchr(in, '.'); + if (!pstr) return WERR_INVALID_PARAM; + if (pstr < in) return WERR_INVALID_PARAM; + if ((pstr - in) < 4) return WERR_INVALID_PARAM; - if (strncmp(prefixes[i].oid, in, prefixes[i].oid_len) != 0) { - continue; - } + oid_prefix = talloc_strndup(0, in, pstr - in); - val_str = in + prefixes[i].oid_len; - end_str = NULL; - errno = 0; - - if (val_str[0] == '\0') { - return WERR_INVALID_PARAM; + for (i=0; i < num_prefixes; i++) { + if (strcmp(prefixes[i].oid, oid_prefix) == 0) { + break; } + } - /* two '.' chars are invalid */ - if (val_str[0] == '.') { - return WERR_INVALID_PARAM; - } + talloc_free(oid_prefix); - val = strtoul(val_str, &end_str, 10); - if (end_str[0] == '.' && end_str[1] != '\0') { - /* - * if it's a '.' and not the last char - * then maybe an other mapping apply - */ - continue; - } else if (end_str[0] != '\0') { + if (i < num_prefixes) { + /* move next to '.' char */ + pstr++; + + val = strtoul(pstr, &end_str, 10); + if (end_str[0] != '\0') { return WERR_INVALID_PARAM; } else if (val > 0xFFFF) { return WERR_INVALID_PARAM; @@ -487,8 +514,16 @@ WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_co } for (i=0; i < schema->num_prefixes; i++) { - pm.ctr.dsdb.mappings[i].id_prefix = schema->prefixes[i].id>>16; - pm.ctr.dsdb.mappings[i].oid.oid = talloc_strdup(pm.ctr.dsdb.mappings, schema->prefixes[i].oid); + DATA_BLOB oid_blob; + + if (!ber_write_partial_OID_String(pm.ctr.dsdb.mappings, &oid_blob, schema->prefixes[i].oid)) { + DEBUG(0, ("write_partial_OID failed for %s", schema->prefixes[i].oid)); + return WERR_INTERNAL_ERROR; + } + + pm.ctr.dsdb.mappings[i].id_prefix = schema->prefixes[i].id>>16; + pm.ctr.dsdb.mappings[i].oid.length = oid_blob.length; + pm.ctr.dsdb.mappings[i].oid.binary_oid = oid_blob.data; } ndr_err = ndr_push_struct_blob(&ndr_blob, msg, @@ -519,14 +554,14 @@ WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_co return WERR_OK; } -WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes) +static WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes) { struct prefixMapBlob *blob; enum ndr_err_code ndr_err; uint32_t i; const struct ldb_val *prefix_val; struct ldb_dn *schema_dn; - struct ldb_result *schema_res; + struct ldb_result *schema_res = NULL; int ret; static const char *schema_attrs[] = { "prefixMap", @@ -586,10 +621,21 @@ WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, return WERR_NOMEM; } for (i=0; i < blob->ctr.dsdb.num_mappings; i++) { - char *oid; + DATA_BLOB oid_blob; + const char *partial_oid; + + oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid, + blob->ctr.dsdb.mappings[i].oid.length); + + if (!ber_read_partial_OID_String(mem_ctx, oid_blob, &partial_oid)) { + DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X", + blob->ctr.dsdb.mappings[i].id_prefix)); + talloc_free(blob); + return WERR_INVALID_PARAM; + } + (*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16; - oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid); - (*prefixes)[i].oid = talloc_asprintf_append(oid, "."); + (*prefixes)[i].oid = partial_oid; (*prefixes)[i].oid_len = strlen((*prefixes)[i].oid); } @@ -906,7 +952,7 @@ WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema, /* Create a DSDB schema from the ldb results provided. This is called directly when the schema is provisioned from an on-disk LDIF file, or - from dsdb_schema_from_schema_dn below + from dsdb_schema_from_schema_dn in schema_fsmo */ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, @@ -1013,115 +1059,6 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, return LDB_SUCCESS; } -/* - Given an LDB, and the DN, return a populated schema -*/ - -int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, - struct smb_iconv_convenience *iconv_convenience, - struct ldb_dn *schema_dn, - struct dsdb_schema **schema, - char **error_string_out) -{ - TALLOC_CTX *tmp_ctx; - char *error_string; - int ret; - - struct ldb_result *schema_res; - struct ldb_result *a_res; - struct ldb_result *c_res; - static const char *schema_attrs[] = { - "prefixMap", - "schemaInfo", - "fSMORoleOwner", - NULL - }; - unsigned flags; - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) { - dsdb_oom(error_string_out, mem_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* we don't want to trace the schema load */ - flags = ldb_get_flags(ldb); - ldb_set_flags(ldb, flags & ~LDB_FLG_ENABLE_TRACING); - - /* - * setup the prefix mappings and schema info - */ - ret = ldb_search(ldb, tmp_ctx, &schema_res, - schema_dn, LDB_SCOPE_BASE, schema_attrs, NULL); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - goto failed; - } else if (ret != LDB_SUCCESS) { - *error_string_out = talloc_asprintf(mem_ctx, - "dsdb_schema: failed to search the schema head: %s", - ldb_errstring(ldb)); - goto failed; - } - if (schema_res->count != 1) { - *error_string_out = talloc_asprintf(mem_ctx, - "dsdb_schema: [%u] schema heads found on a base search", - schema_res->count); - goto failed; - } - - /* - * load the attribute definitions - */ - ret = ldb_search(ldb, tmp_ctx, &a_res, - schema_dn, LDB_SCOPE_ONELEVEL, NULL, - "(objectClass=attributeSchema)"); - if (ret != LDB_SUCCESS) { - *error_string_out = talloc_asprintf(mem_ctx, - "dsdb_schema: failed to search attributeSchema objects: %s", - ldb_errstring(ldb)); - goto failed; - } - - /* - * load the objectClass definitions - */ - ret = ldb_search(ldb, tmp_ctx, &c_res, - schema_dn, LDB_SCOPE_ONELEVEL, NULL, - "(objectClass=classSchema)"); - if (ret != LDB_SUCCESS) { - *error_string_out = talloc_asprintf(mem_ctx, - "dsdb_schema: failed to search attributeSchema objects: %s", - ldb_errstring(ldb)); - goto failed; - } - - ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb, - lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - schema_res, a_res, c_res, schema, &error_string); - if (ret != LDB_SUCCESS) { - *error_string_out = talloc_asprintf(mem_ctx, - "dsdb_schema load failed: %s", - error_string); - goto failed; - } - talloc_steal(mem_ctx, *schema); - talloc_free(tmp_ctx); - - if (flags & LDB_FLG_ENABLE_TRACING) { - flags = ldb_get_flags(ldb); - ldb_set_flags(ldb, flags | LDB_FLG_ENABLE_TRACING); - } - - return LDB_SUCCESS; - -failed: - if (flags & LDB_FLG_ENABLE_TRACING) { - flags = ldb_get_flags(ldb); - ldb_set_flags(ldb, flags | LDB_FLG_ENABLE_TRACING); - } - talloc_free(tmp_ctx); - return ret; -} - static const struct { const char *name; diff --git a/source4/dsdb/schema/schema_prefixmap.c b/source4/dsdb/schema/schema_prefixmap.c new file mode 100644 index 0000000000..d24c5add00 --- /dev/null +++ b/source4/dsdb/schema/schema_prefixmap.c @@ -0,0 +1,22 @@ +/* + Unix SMB/CIFS implementation. + + DRS::prefixMap implementation + + Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index 6f09f63596..9f22b32334 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -346,7 +346,10 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) return ret; } - schema_fill_constructed(schema); + ret = schema_fill_constructed(schema); + if (ret != LDB_SUCCESS) { + return ret; + } ret = ldb_set_opaque(ldb, "dsdb_schema", schema); if (ret != LDB_SUCCESS) { diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index c564471d4b..cbbd4a8636 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -1204,6 +1204,8 @@ static WERROR dsdb_syntax_DN_ldb_to_drsuapi(struct ldb_context *ldb, return WERR_OK; } + + static WERROR dsdb_syntax_DN_BINARY_drsuapi_to_ldb(struct ldb_context *ldb, const struct dsdb_schema *schema, const struct dsdb_attribute *attr, @@ -1212,6 +1214,7 @@ static WERROR dsdb_syntax_DN_BINARY_drsuapi_to_ldb(struct ldb_context *ldb, struct ldb_message_element *out) { uint32_t i; + int ret; out->flags = 0; out->name = talloc_strdup(mem_ctx, attr->lDAPDisplayName); @@ -1222,39 +1225,81 @@ static WERROR dsdb_syntax_DN_BINARY_drsuapi_to_ldb(struct ldb_context *ldb, W_ERROR_HAVE_NO_MEMORY(out->values); for (i=0; i < out->num_values; i++) { - struct drsuapi_DsReplicaObjectIdentifier3Binary id3b; - char *binary; - char *str; + struct drsuapi_DsReplicaObjectIdentifier3Binary id3; enum ndr_err_code ndr_err; + DATA_BLOB guid_blob; + struct ldb_dn *dn; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + W_ERROR_HAVE_NO_MEMORY(tmp_ctx); + } if (in->value_ctr.values[i].blob == NULL) { + talloc_free(tmp_ctx); return WERR_FOOBAR; } if (in->value_ctr.values[i].blob->length == 0) { + talloc_free(tmp_ctx); return WERR_FOOBAR; } - ndr_err = ndr_pull_struct_blob_all(in->value_ctr.values[i].blob, - out->values, schema->iconv_convenience, &id3b, - (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary); + + /* windows sometimes sends an extra two pad bytes here */ + ndr_err = ndr_pull_struct_blob(in->value_ctr.values[i].blob, + tmp_ctx, schema->iconv_convenience, &id3, + (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + talloc_free(tmp_ctx); return ntstatus_to_werror(status); } - /* TODO: handle id3.guid and id3.sid */ - binary = data_blob_hex_string(out->values, &id3b.binary); - W_ERROR_HAVE_NO_MEMORY(binary); + dn = ldb_dn_new(tmp_ctx, ldb, id3.dn); + if (!dn) { + talloc_free(tmp_ctx); + /* If this fails, it must be out of memory, as it does not do much parsing */ + W_ERROR_HAVE_NO_MEMORY(dn); + } - str = talloc_asprintf(out->values, "B:%u:%s:%s", - (unsigned int)(id3b.binary.length * 2), /* because of 2 hex chars per byte */ - binary, - id3b.dn); - W_ERROR_HAVE_NO_MEMORY(str); + ndr_err = ndr_push_struct_blob(&guid_blob, tmp_ctx, schema->iconv_convenience, &id3.guid, + (ndr_push_flags_fn_t)ndr_push_GUID); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + talloc_free(tmp_ctx); + return ntstatus_to_werror(status); + } - /* TODO: handle id3.guid and id3.sid */ - out->values[i] = data_blob_string_const(str); + ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return WERR_FOOBAR; + } + + talloc_free(guid_blob.data); + + if (id3.__ndr_size_sid) { + DATA_BLOB sid_blob; + ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, schema->iconv_convenience, &id3.sid, + (ndr_push_flags_fn_t)ndr_push_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + talloc_free(tmp_ctx); + return ntstatus_to_werror(status); + } + + ret = ldb_dn_set_extended_component(dn, "SID", &sid_blob); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return WERR_FOOBAR; + } + } + + /* set binary stuff */ + ldb_dn_set_binary(dn, &id3.binary); + + out->values[i] = data_blob_string_const(ldb_dn_get_extended_linearized(out->values, dn, 1)); + talloc_free(tmp_ctx); } return WERR_OK; @@ -1285,27 +1330,72 @@ static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(struct ldb_context *ldb, W_ERROR_HAVE_NO_MEMORY(blobs); for (i=0; i < in->num_values; i++) { - struct drsuapi_DsReplicaObjectIdentifier3Binary id3b; + struct drsuapi_DsReplicaObjectIdentifier3Binary id3; enum ndr_err_code ndr_err; + const DATA_BLOB *guid_blob, *sid_blob; + struct ldb_dn *dn; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + W_ERROR_HAVE_NO_MEMORY(tmp_ctx); out->value_ctr.values[i].blob = &blobs[i]; - /* TODO: handle id3b.guid and id3b.sid, id3.binary */ - ZERO_STRUCT(id3b); - id3b.dn = (const char *)in->values[i].data; - id3b.binary = data_blob(NULL, 0); + dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &in->values[i]); + + W_ERROR_HAVE_NO_MEMORY(dn); + + guid_blob = ldb_dn_get_extended_component(dn, "GUID"); - ndr_err = ndr_push_struct_blob(&blobs[i], blobs, schema->iconv_convenience, &id3b, - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary); + ZERO_STRUCT(id3); + + if (guid_blob) { + ndr_err = ndr_pull_struct_blob_all(guid_blob, + tmp_ctx, schema->iconv_convenience, &id3.guid, + (ndr_pull_flags_fn_t)ndr_pull_GUID); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + talloc_free(tmp_ctx); + return ntstatus_to_werror(status); + } + } + + sid_blob = ldb_dn_get_extended_component(dn, "SID"); + if (sid_blob) { + + ndr_err = ndr_pull_struct_blob_all(sid_blob, + tmp_ctx, schema->iconv_convenience, &id3.sid, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + talloc_free(tmp_ctx); + return ntstatus_to_werror(status); + } + } + + id3.dn = ldb_dn_get_linearized(dn); + if (strncmp(id3.dn, "B:", 2) == 0) { + id3.dn = strchr(id3.dn, ':'); + id3.dn = strchr(id3.dn+1, ':'); + id3.dn = strchr(id3.dn+1, ':'); + id3.dn++; + } + + /* get binary stuff */ + ldb_dn_get_binary(dn, &id3.binary); + + ndr_err = ndr_push_struct_blob(&blobs[i], blobs, schema->iconv_convenience, &id3, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + talloc_free(tmp_ctx); return ntstatus_to_werror(status); } + talloc_free(tmp_ctx); } return WERR_OK; } + + static WERROR dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb(struct ldb_context *ldb, const struct dsdb_schema *schema, const struct dsdb_attribute *attr, |