X-Git-Url: http://git.samba.org/samba.git/?p=ira%2Fwip.git;a=blobdiff_plain;f=source4%2Fdsdb%2Fcommon%2Futil.c;h=189cb4ec8278d3ff3cb676ef7faaa4bdbab6c7a0;hp=5164f7d181c02e1024305d38323531f28f00a7e5;hb=43cfa69945c121b6929512a2ea607b2c3bfe0a74;hpb=eb78b7c8742d5d7b223c58d66ecd87323ddbb5c1 diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 5164f7d181c..189cb4ec827 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -6,30 +6,32 @@ Copyright (C) Volker Lendecke 2004 Copyright (C) Andrew Bartlett 2006 Copyright (C) Jelmer Vernooij 2007 - + 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 . */ #include "includes.h" +#include "events/events.h" #include "ldb.h" #include "ldb_errors.h" -#include "lib/util/util_ldb.h" +#include "../lib/util/util_ldb.h" +#include "../lib/crypto/crypto.h" #include "dsdb/samdb/samdb.h" #include "libcli/security/security.h" #include "librpc/gen_ndr/ndr_security.h" #include "librpc/gen_ndr/ndr_misc.h" -#include "dsdb/common/flags.h" +#include "../libds/common/flags.h" #include "dsdb/common/proto.h" #include "libcli/ldap/ldap_ndr.h" #include "param/param.h" @@ -104,7 +106,6 @@ const char *samdb_search_string_v(struct ldb_context *sam_ldb, return samdb_result_string(res[0], attr_name, NULL); } - /* search the sam for a single string attribute in exactly 1 record @@ -434,6 +435,22 @@ NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME def return ldb_msg_find_attr_as_uint64(msg, attr, default_value); } +/* + * Windows stores 0 for lastLogoff. + * But when a MS DC return the lastLogoff (as Logoff Time) + * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case + * cause windows 2008 and newer version to fail for SMB requests + */ +NTTIME samdb_result_last_logoff(struct ldb_message *msg) +{ + NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0); + + if (ret == 0) + ret = 0x7FFFFFFFFFFFFFFFULL; + + return ret; +} + /* * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to * indicate an account doesn't expire. @@ -528,7 +545,7 @@ NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, /* pull a samr_Password structutre from a result set. */ -struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) +struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr) { struct samr_Password *hash = NULL; const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); @@ -542,7 +559,7 @@ struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message /* pull an array of samr_Password structutres from a result set. */ -uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, +uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr, struct samr_Password **hashes) { uint_t count = 0; @@ -570,7 +587,7 @@ uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, return count; } -NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, +NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) { struct samr_Password *lmPwdHash, *ntPwdHash; @@ -586,14 +603,21 @@ NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, } } if (lm_pwd) { - int num_lm; - num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash); - if (num_lm == 0) { - *lm_pwd = NULL; - } else if (num_lm > 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; + /* Ensure that if we have turned off LM + * authentication, that we never use the LM hash, even + * if we store it */ + if (lp_lanman_auth(lp_ctx)) { + int num_lm; + num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash); + if (num_lm == 0) { + *lm_pwd = NULL; + } else if (num_lm > 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } else { + *lm_pwd = &lmPwdHash[0]; + } } else { - *lm_pwd = &lmPwdHash[0]; + *lm_pwd = NULL; } } return NT_STATUS_OK; @@ -632,13 +656,13 @@ uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ct struct ldb_message *msg, struct ldb_dn *domain_dn) { uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); - uint32_t acct_flags = samdb_uf2acb(userAccountControl); + uint32_t acct_flags = ds_uf2acb(userAccountControl); NTTIME must_change_time; NTTIME now; - + must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, domain_dn, msg); - + /* Test account expire time */ unix_to_nt_time(&now, time(NULL)); /* check for expired password */ @@ -648,6 +672,28 @@ uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ct return acct_flags; } +struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + const char *attr) +{ + struct lsa_BinaryString s; + const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); + + ZERO_STRUCT(s); + + if (!val) { + return s; + } + + s.array = talloc_array(mem_ctx, uint16_t, val->length/2); + if (!s.array) { + return s; + } + s.length = s.size = val->length/2; + memcpy(s.array, val->data, val->length); + + return s; +} /* Find an attribute, with a particular value */ @@ -691,7 +737,7 @@ int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg if (el) { return LDB_SUCCESS; } - + return samdb_msg_add_string(ldb, msg, msg, name, set_value); } @@ -872,7 +918,7 @@ int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr_name, uint32_t v) { - return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v)); + return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v)); } /* @@ -887,6 +933,17 @@ int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, return ldb_msg_add_value(msg, attr_name, &val, NULL); } +/* + add a parameters element to a message +*/ +int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct lsa_BinaryString *parameters) +{ + struct ldb_val val; + val.length = parameters->length * 2; + val.data = (uint8_t *)parameters->array; + return ldb_msg_add_value(msg, attr_name, &val, NULL); +} /* add a general value element to a message */ @@ -1023,12 +1080,12 @@ const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb) goto failed; } - ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*"); + ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*"); if (ret != LDB_SUCCESS) { goto failed; } - + if (res->count != 1) { goto failed; } @@ -1039,7 +1096,7 @@ const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb) } /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) { + if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) { goto failed; } @@ -1123,7 +1180,7 @@ struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb) int ret; struct ldb_result *root_res; struct ldb_dn *settings_dn; - + /* see if we have a cached copy */ settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn"); if (settings_dn) { @@ -1134,15 +1191,13 @@ struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb) if (tmp_ctx == NULL) { goto failed; } - - ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res); + ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL); if (ret) { DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", ldb_errstring(ldb))); goto failed; } - talloc_steal(tmp_ctx, root_res); if (root_res->count != 1) { goto failed; @@ -1176,7 +1231,7 @@ const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb) int ret; struct ldb_result *res; struct GUID *invocation_id; - + /* see if we have a cached copy */ invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id"); if (invocation_id) { @@ -1188,11 +1243,10 @@ const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb) goto failed; } - ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); + ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); if (ret) { goto failed; } - talloc_steal(tmp_ctx, res); if (res->count != 1) { goto failed; @@ -1270,7 +1324,7 @@ const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb) int ret; struct ldb_result *res; struct GUID *ntds_guid; - + /* see if we have a cached copy */ ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); if (ntds_guid) { @@ -1282,11 +1336,10 @@ const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb) goto failed; } - ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); + ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); if (ret) { goto failed; } - talloc_steal(tmp_ctx, res); if (res->count != 1) { goto failed; @@ -1320,7 +1373,7 @@ bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_ TALLOC_CTX *tmp_ctx; struct GUID *ntds_guid_new; struct GUID *ntds_guid_old; - + /* see if we have a cached copy */ ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); @@ -1396,14 +1449,13 @@ bool samdb_is_pdc(struct ldb_context *ldb) return false; } - ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res); + ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL); if (ret) { DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), ldb_errstring(ldb))); goto failed; } - talloc_steal(tmp_ctx, dom_res); if (dom_res->count != 1) { goto failed; } @@ -1443,17 +1495,17 @@ bool samdb_is_gc(struct ldb_context *ldb) } /* Query cn=ntds settings,.... */ - ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); + ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); if (ret) { + talloc_free(tmp_ctx); return false; } if (res->count != 1) { - talloc_free(res); + talloc_free(tmp_ctx); return false; } options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0); - talloc_free(res); talloc_free(tmp_ctx); /* if options attribute has the 0x00000001 flag set, then enable the global catlog */ @@ -1475,12 +1527,11 @@ int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, local_ctx = talloc_new(mem_ctx); if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR; - + while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { - ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, - "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))", attrs, &res); + ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs, + "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))"); if (ret == LDB_SUCCESS) { - talloc_steal(local_ctx, res); if (res->count == 1) { break; } @@ -1509,15 +1560,6 @@ int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, return ret; } -/* - check that a password is sufficiently complex -*/ -static bool samdb_password_complexity_ok(const char *pass) -{ - return check_password_quality(pass); -} - - /* set the user password using plaintext, obeying any user or domain @@ -1535,7 +1577,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *user_dn, struct ldb_dn *domain_dn, struct ldb_message *mod, - const char *new_pass, + const DATA_BLOB *new_password, struct samr_Password *lmNewHash, struct samr_Password *ntNewHash, bool user_change, @@ -1621,6 +1663,11 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0); + if (userAccountControl & UF_PASSWD_NOTREQD) { + /* see [MS-ADTS] 2.2.15 */ + minPwdLength = 0; + } + if (_dominfo) { struct samr_DomInfo1 *dominfo; /* on failure we need to fill in the reject reasons */ @@ -1636,40 +1683,46 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, *_dominfo = dominfo; } - if (restrictions && new_pass) { + if (restrictions && new_password) { + char *new_pass; /* check the various password restrictions */ - if (restrictions && minPwdLength > strlen_m(new_pass)) { + if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) { if (reject_reason) { *reject_reason = SAMR_REJECT_TOO_SHORT; } return NT_STATUS_PASSWORD_RESTRICTION; } - - /* possibly check password complexity */ - if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX && - !samdb_password_complexity_ok(new_pass)) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_COMPLEXITY; + + /* Create the NT hash */ + mdfour(local_ntNewHash.hash, new_password->data, new_password->length); + + ntNewHash = &local_ntNewHash; + + /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */ + if (convert_string_talloc_convenience(mem_ctx, + lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")), + CH_UTF16, CH_UNIX, + 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)) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_COMPLEXITY; + } + return NT_STATUS_PASSWORD_RESTRICTION; } - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* compute the new nt and lm hashes */ - if (E_deshash(new_pass, local_lmNewHash.hash)) { - lmNewHash = &local_lmNewHash; - } - if (!E_md4hash(new_pass, local_ntNewHash.hash)) { - /* If we can't convert this password to UCS2, then we should not accept it */ - if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; + + /* compute the new lm hashes (for checking history - case insenitivly!) */ + if (E_deshash(new_pass, local_lmNewHash.hash)) { + lmNewHash = &local_lmNewHash; } - return NT_STATUS_PASSWORD_RESTRICTION; } - ntNewHash = &local_ntNewHash; } - if (user_change) { + if (restrictions && user_change) { /* are all password changes disallowed? */ if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { if (reject_reason) { @@ -1677,7 +1730,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, } return NT_STATUS_PASSWORD_RESTRICTION; } - + /* can this user change password? */ if (userAccountControl & UF_PASSWD_CANT_CHANGE) { if (reject_reason) { @@ -1685,7 +1738,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, } return NT_STATUS_PASSWORD_RESTRICTION; } - + /* yes, this is a minus. The ages are in negative 100nsec units! */ if (pwdLastSet - minPwdAge > now_nt) { if (reject_reason) { @@ -1709,11 +1762,11 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, return NT_STATUS_PASSWORD_RESTRICTION; } } - + /* check the password history */ sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength); sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength); - + for (i=0; lmNewHash && ihash, sambaLMPwdHistory[i].hash, 16) == 0) { if (reject_reason) { @@ -1735,23 +1788,22 @@ 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_pass) { - /* if we know the cleartext, then only set it. + if (new_password) { + /* if we know the cleartext UTF16 password, then set it. * Modules in ldb will set all the appropriate * hashes */ - CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, - "sambaPassword", new_pass)); + CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL)); } else { /* We don't have the cleartext, so delete the old one * and set what we have of the hashes */ - CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword")); + CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword")); if (lmNewHash) { CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash)); } else { CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd")); } - + if (ntNewHash) { CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash)); } else { @@ -1773,7 +1825,7 @@ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, */ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid, - const char *new_pass, + const DATA_BLOB *new_pass, struct samr_Password *lmNewHash, struct samr_Password *ntNewHash, bool user_change, @@ -1823,7 +1875,7 @@ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, ldb_transaction_cancel(ctx); return nt_status; } - + /* modify the samdb record */ ret = samdb_replace(ctx, mem_ctx, msg); if (ret != 0) { @@ -1850,42 +1902,42 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA struct ldb_dn *basedn; const char *sidstr; int ret; - + sidstr = dom_sid_string(mem_ctx, sid); NT_STATUS_HAVE_NO_MEMORY(sidstr); - + /* We might have to create a ForeignSecurityPrincipal, even if this user * is in our own domain */ - + msg = ldb_msg_new(mem_ctx); if (msg == NULL) { return NT_STATUS_NO_MEMORY; } - + /* TODO: Hmmm. This feels wrong. How do I find the base dn to * put the ForeignSecurityPrincipals? d_state->domain_dn does * not work, this is wrong for the Builtin domain, there's no * cn=For...,cn=Builtin,dc={BASEDN}. -- vl */ - + basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL, "(&(objectClass=container)(cn=ForeignSecurityPrincipals))"); - + if (basedn == NULL) { DEBUG(0, ("Failed to find DN for " "ForeignSecurityPrincipal container\n")); return NT_STATUS_INTERNAL_DB_CORRUPTION; } - + /* add core elements to the ldb_message for the alias */ msg->dn = ldb_dn_copy(mem_ctx, basedn); if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) return NT_STATUS_NO_MEMORY; - + samdb_msg_add_string(sam_ctx, mem_ctx, msg, "objectClass", "foreignSecurityPrincipal"); - + /* create the alias */ ret = ldb_add(sam_ctx, msg); if (ret != 0) { @@ -1911,12 +1963,12 @@ struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_c const char *binary_encoded; const char **split_realm; struct ldb_dn *dn; - + if (!tmp_ctx) { return NULL; } - - split_realm = str_list_make(tmp_ctx, dns_domain, "."); + + split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, "."); if (!split_realm) { talloc_free(tmp_ctx); return NULL; @@ -1954,7 +2006,7 @@ struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_result *res_domain_ref; char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name); /* find the domain's DN */ - int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, + int ret_domain = ldb_search(ldb, mem_ctx, &res_domain_ref, samdb_partitions_dn(ldb, mem_ctx), LDB_SCOPE_ONELEVEL, @@ -1964,9 +2016,9 @@ struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, if (ret_domain != 0) { return NULL; } - + if (res_domain_ref->count == 0) { - ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, + ret_domain = ldb_search(ldb, mem_ctx, &res_domain_ref, samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name), LDB_SCOPE_BASE, @@ -1975,19 +2027,117 @@ struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, if (ret_domain != 0) { return NULL; } - + if (res_domain_ref->count == 1) { return res_domain_ref->msgs[0]->dn; } return NULL; } - + if (res_domain_ref->count > 1) { DEBUG(0,("Found %d records matching domain [%s]\n", ret_domain, domain_name)); return NULL; } - + return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL); } + + +/* + use a GUID to find a DN + */ +int dsdb_find_dn_by_guid(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const char *guid_str, struct ldb_dn **dn) +{ + int ret; + struct ldb_result *res; + const char *attrs[] = { NULL }; + struct ldb_request *search_req; + char *expression; + struct ldb_search_options_control *options; + + expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str); + if (!expression) { + DEBUG(0, (__location__ ": out of memory\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + + res = talloc_zero(mem_ctx, struct ldb_result); + if (!res) { + DEBUG(0, (__location__ ": out of memory\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&search_req, ldb, mem_ctx, + ldb_get_default_basedn(ldb), + LDB_SCOPE_SUBTREE, + expression, attrs, + NULL, + res, ldb_search_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* we need to cope with cross-partition links, so search for + the GUID over all partitions */ + options = talloc(search_req, struct ldb_search_options_control); + if (options == NULL) { + DEBUG(0, (__location__ ": out of memory\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT; + + ret = ldb_request_add_control(search_req, + LDB_CONTROL_SEARCH_OPTIONS_OID, + true, options); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(ldb, search_req); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_wait(search_req->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* this really should be exactly 1, but there is a bug in the + partitions module that can return two here with the + search_options control set */ + if (res->count < 1) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + *dn = res->msgs[0]->dn; + + return LDB_SUCCESS; +} + + +/* + use a DN to find a GUID + */ +int dsdb_find_guid_by_dn(struct ldb_context *ldb, + struct ldb_dn *dn, struct GUID *guid) +{ + int ret; + struct ldb_result *res; + const char *attrs[] = { "objectGUID", NULL }; + TALLOC_CTX *tmp_ctx = talloc_new(ldb); + + ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + *guid = samdb_result_guid(res->msgs[0], "objectGUID"); + talloc_free(tmp_ctx); + return LDB_SUCCESS; +}