#include "includes.h"
#include "events/events.h"
#include "ldb.h"
+#include "ldb_module.h"
#include "ldb_errors.h"
#include "../lib/util/util_ldb.h"
#include "../lib/crypto/crypto.h"
#include "dsdb/common/util.h"
#include "lib/socket/socket.h"
#include "dsdb/samdb/ldb_modules/util.h"
+#include "librpc/gen_ndr/irpc.h"
/*
search the sam for the specified attributes in a specific domain, filter on
struct ldb_dn *domain_dn,
struct ldb_message *msg)
{
- uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
- uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
+ int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
+ uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
+ "userAccountControl",
+ 0);
int64_t maxPwdAge;
/* Machine accounts don't expire, and there is a flag for 'no expiry' */
if (attr_time == 0) {
return 0;
}
+ if (attr_time == -1) {
+ return 0x7FFFFFFFFFFFFFFFULL;
+ }
- maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
+ maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
+ "maxPwdAge", NULL);
if (maxPwdAge == 0) {
return 0x7FFFFFFFFFFFFFFFULL;
} else {
return count;
}
-NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_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;
/* 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)) {
+ if (lpcfg_lanman_auth(lp_ctx)) {
unsigned int num_lm;
num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
if (num_lm == 0) {
for (i = 0; i < msg->num_elements; i++) {
if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
- if (msg->elements[i].flags == LDB_FLAG_MOD_DELETE) {
+ if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
*old_val = &msg->elements[i].values[0];
} else {
*new_val = &msg->elements[i].values[0];
char *s = talloc_strdup(mem_ctx, str);
char *a = talloc_strdup(mem_ctx, attr_name);
if (s == NULL || a == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(sam_ldb);
}
return ldb_msg_add_string(msg, a, s);
}
sid,
(ndr_push_flags_fn_t)ndr_push_dom_sid);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(sam_ldb);
}
return ldb_msg_add_value(msg, attr_name, &v, NULL);
}
}
/*
- add a add attribute value to a message
+ add an add attribute value to a message or enhance an existing attribute
+ which has the same name and the add flag set.
*/
-int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
- const char *attr_name, const char *value)
+int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg, const char *attr_name,
+ const char *value)
{
struct ldb_message_element *el;
- char *a, *v;
+ struct ldb_val val, *vals;
+ char *v;
+ unsigned int i;
+ bool found = false;
int ret;
- a = talloc_strdup(mem_ctx, attr_name);
- if (a == NULL)
- return LDB_ERR_OPERATIONS_ERROR;
+
v = talloc_strdup(mem_ctx, value);
- if (v == NULL)
- return LDB_ERR_OPERATIONS_ERROR;
- ret = ldb_msg_add_string(msg, a, v);
- if (ret != 0)
- return ret;
- el = ldb_msg_find_element(msg, a);
- if (el == NULL)
- return LDB_ERR_OPERATIONS_ERROR;
- el->flags = LDB_FLAG_MOD_ADD;
+ if (v == NULL) {
+ return ldb_oom(sam_ldb);
+ }
+
+ val.data = (uint8_t *) v;
+ val.length = strlen(v);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existent attributes */
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ el = &msg->elements[i];
+ if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
+ (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
+ &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ vals = talloc_realloc(msg, el->values, struct ldb_val,
+ el->num_values + 1);
+ if (vals == NULL) {
+ return ldb_oom(sam_ldb);
+ }
+ el->values = vals;
+ el->values[el->num_values] = val;
+ ++(el->num_values);
+
return LDB_SUCCESS;
}
/*
- add a delete attribute value to a message
+ add a delete attribute value to a message or enhance an existing attribute
+ which has the same name and the delete flag set.
*/
-int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
- const char *attr_name, const char *value)
+int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg, const char *attr_name,
+ const char *value)
{
struct ldb_message_element *el;
- char *a, *v;
+ struct ldb_val val, *vals;
+ char *v;
+ unsigned int i;
+ bool found = false;
int ret;
- a = talloc_strdup(mem_ctx, attr_name);
- if (a == NULL)
- return LDB_ERR_OPERATIONS_ERROR;
+
v = talloc_strdup(mem_ctx, value);
- if (v == NULL)
- return LDB_ERR_OPERATIONS_ERROR;
- ret = ldb_msg_add_string(msg, a, v);
- if (ret != 0)
- return ret;
- el = ldb_msg_find_element(msg, a);
- if (el == NULL)
- return LDB_ERR_OPERATIONS_ERROR;
- el->flags = LDB_FLAG_MOD_DELETE;
+ if (v == NULL) {
+ return ldb_oom(sam_ldb);
+ }
+
+ val.data = (uint8_t *) v;
+ val.length = strlen(v);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existent attributes */
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ el = &msg->elements[i];
+ if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
+ (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
+ &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ vals = talloc_realloc(msg, el->values, struct ldb_val,
+ el->num_values + 1);
+ if (vals == NULL) {
+ return ldb_oom(sam_ldb);
+ }
+ el->values = vals;
+ el->values[el->num_values] = val;
+ ++(el->num_values);
+
return LDB_SUCCESS;
}
add a samr_Password element to a message
*/
int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
- const char *attr_name, struct samr_Password *hash)
+ const char *attr_name, const struct samr_Password *hash)
{
struct ldb_val val;
val.data = talloc_memdup(mem_ctx, hash->hash, 16);
if (!val.data) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(sam_ldb);
}
val.length = 16;
return ldb_msg_add_value(msg, attr_name, &val, NULL);
/*
add a samr_Password array to a message
*/
-int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+int samdb_msg_add_hashes(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx, struct ldb_message *msg,
const char *attr_name, struct samr_Password *hashes,
unsigned int count)
{
val.data = talloc_array_size(mem_ctx, 16, count);
val.length = count*16;
if (!val.data) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
for (i=0;i<count;i++) {
memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
return server_site_dn;
}
+/*
+ find the site name from a computers DN record
+ */
+int samdb_find_site_for_computer(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
+ const char **site_name)
+{
+ int ret;
+ struct ldb_dn *dn;
+ const struct ldb_val *rdn_val;
+
+ *site_name = NULL;
+
+ ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (!ldb_dn_remove_child_components(dn, 2)) {
+ talloc_free(dn);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ rdn_val = ldb_dn_get_rdn_val(dn);
+ (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
+ talloc_free(dn);
+ if (!*site_name) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ find the NTDS GUID from a computers DN record
+ */
+int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
+ struct GUID *ntds_guid)
+{
+ int ret;
+ struct ldb_dn *dn;
+
+ *ntds_guid = GUID_zero();
+
+ ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
+ talloc_free(dn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
+ talloc_free(dn);
+ return ret;
+}
+
/*
find a 'reference' DN that points at another object
(eg. serverReference, rIDManagerReference etc)
attrs[0] = attribute;
attrs[1] = NULL;
- ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
+ ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
if (ret != LDB_SUCCESS) {
return ret;
}
- if (res->count != 1) {
- talloc_free(res);
- return LDB_ERR_NO_SUCH_OBJECT;
- }
*dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
if (!*dn) {
+ if (!ldb_msg_find_element(res->msgs[0], attribute)) {
+ ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
+ ldb_dn_get_linearized(base));
+ } else {
+ ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
+ ldb_dn_get_linearized(base));
+ }
talloc_free(res);
return LDB_ERR_NO_SUCH_ATTRIBUTE;
}
}
ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
- if (ret) {
+ if (ret != LDB_SUCCESS) {
DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
ldb_errstring(ldb)));
/* Query cn=ntds settings,.... */
ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
- if (ret) {
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return false;
}
TALLOC_CTX *local_ctx;
struct ldb_dn *sdn = dn;
struct ldb_result *res = NULL;
- int ret = 0;
+ int ret = LDB_SUCCESS;
const char *attrs[] = { NULL };
local_ctx = talloc_new(mem_ctx);
- if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
+ if (local_ctx == NULL) return ldb_oom(ldb);
while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
/*
* Sets the user password using plaintext UTF16 (attribute "new_password") or
* LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
- * as parameter if it's a user change or not ("userChange"). The "rejectReason"
- * gives some more informations if the changed failed.
+ * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
+ * user change or not. The "rejectReason" gives some more informations if the
+ * change failed.
*
- * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
- * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
+ * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
* NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
*/
NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
const DATA_BLOB *new_password,
- struct samr_Password *lmNewHash,
- struct samr_Password *ntNewHash,
- bool user_change,
+ const struct samr_Password *lmNewHash,
+ const struct samr_Password *ntNewHash,
+ const struct samr_Password *lmOldHash,
+ const struct samr_Password *ntOldHash,
enum samPwdChangeReason *reject_reason,
struct samr_DomInfo1 **_dominfo)
{
struct ldb_request *req;
struct dsdb_control_password_change_status *pwd_stat = NULL;
int ret;
- NTSTATUS status;
+ NTSTATUS status = NT_STATUS_OK;
#define CHECK_RET(x) \
if (x != LDB_SUCCESS) { \
return NT_STATUS_NO_MEMORY;
}
- if (user_change) {
- /* a user password change and we've checked already the old
- * password somewhere else (callers responsability) */
+ /* A password change operation */
+ if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
+ struct dsdb_control_password_change *change;
+
+ change = talloc(req, struct dsdb_control_password_change);
+ if (change == NULL) {
+ talloc_free(req);
+ talloc_free(msg);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ change->old_nt_pwd_hash = ntOldHash;
+ change->old_lm_pwd_hash = lmOldHash;
+
ret = ldb_request_add_control(req,
- DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID,
- true, NULL);
+ DSDB_CONTROL_PASSWORD_CHANGE_OID,
+ true, change);
if (ret != LDB_SUCCESS) {
talloc_free(req);
talloc_free(msg);
talloc_free(pwd_stat);
}
- /* TODO: Error results taken from "password_hash" module. Are they
- correct? */
- if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ const char *errmsg = ldb_errstring(ldb);
+ char *endptr = NULL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ status = NT_STATUS_UNSUCCESSFUL;
+ if (errmsg != NULL) {
+ werr = W_ERROR(strtol(errmsg, &endptr, 16));
+ }
+ if (endptr != errmsg) {
+ if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
+ status = NT_STATUS_WRONG_PASSWORD;
+ }
+ if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
+ status = NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+ } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* don't let the caller know if an account doesn't exist */
status = NT_STATUS_WRONG_PASSWORD;
- } else if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
- status = NT_STATUS_PASSWORD_RESTRICTION;
} else if (ret != LDB_SUCCESS) {
status = NT_STATUS_UNSUCCESSFUL;
- } else {
- status = NT_STATUS_OK;
}
return status;
/*
* Sets the user password using plaintext UTF16 (attribute "new_password") or
* LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
- * as parameter if it's a user change or not ("userChange"). The "rejectReason"
- * gives some more informations if the changed failed.
+ * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
+ * user change or not. The "rejectReason" gives some more informations if the
+ * change failed.
*
* This wrapper function for "samdb_set_password" takes a SID as input rather
* than a user DN.
*
* Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
* NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
- * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
+ * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
+ * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
*/
NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
const struct dom_sid *user_sid,
const DATA_BLOB *new_password,
- struct samr_Password *lmNewHash,
- struct samr_Password *ntNewHash,
- bool user_change,
+ const struct samr_Password *lmNewHash,
+ const struct samr_Password *ntNewHash,
+ const struct samr_Password *lmOldHash,
+ const struct samr_Password *ntOldHash,
enum samPwdChangeReason *reject_reason,
struct samr_DomInfo1 **_dominfo)
{
user_dn, NULL,
new_password,
lmNewHash, ntNewHash,
- user_change,
+ lmOldHash, ntOldHash,
reject_reason, _dominfo);
if (!NT_STATUS_IS_OK(nt_status)) {
ldb_transaction_cancel(ldb);
domain_ref_attrs,
"(&(nETBIOSName=%s)(objectclass=crossRef))",
escaped_domain);
- if (ret_domain != 0) {
+ if (ret_domain != LDB_SUCCESS) {
return NULL;
}
LDB_SCOPE_BASE,
domain_ref2_attrs,
"(objectclass=domain)");
- if (ret_domain != 0) {
+ if (ret_domain != LDB_SUCCESS) {
return NULL;
}
char *guid_str = GUID_string(mem_ctx, guid);
if (!guid_str) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
{
int ret;
struct ldb_result *res;
- const char *attrs[] = { "objectSID", NULL };
+ const char *attrs[] = { "objectSid", NULL };
TALLOC_CTX *tmp_ctx = talloc_new(ldb);
struct dom_sid *s;
talloc_free(tmp_ctx);
return LDB_ERR_NO_SUCH_OBJECT;
}
- s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
+ s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
if (s == NULL) {
talloc_free(tmp_ctx);
return LDB_ERR_NO_SUCH_OBJECT;
return LDB_SUCCESS;
}
+/*
+ use a SID to find a DN
+ */
+int dsdb_find_dn_by_sid(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct dom_sid *sid, struct ldb_dn **dn)
+{
+ int ret;
+ struct ldb_result *res;
+ const char *attrs[] = { NULL };
+ char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
+
+ if (!sid_str) {
+ return ldb_operr(ldb);
+ }
+
+ ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
+ DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
+ DSDB_SEARCH_SHOW_EXTENDED_DN |
+ DSDB_SEARCH_ONE_ONLY,
+ "objectSid=%s", sid_str);
+ talloc_free(sid_str);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
+ talloc_free(res);
+
+ return LDB_SUCCESS;
+}
/*
load a repsFromTo blob list for a given partition GUID
res = talloc_zero(tmp_ctx, struct ldb_result);
if (!res) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
ret = ldb_build_search_req(&req, ldb, tmp_ctx,
p_ctrl = talloc(req, struct dsdb_control_current_partition);
if (p_ctrl == NULL) {
- talloc_free(res);
- return LDB_ERR_OPERATIONS_ERROR;
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
}
p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
p_ctrl->dn = dn;
-
ret = ldb_request_add_control(req,
DSDB_CONTROL_CURRENT_PARTITION_OID,
false, p_ctrl);
config_dn = ldb_get_config_basedn(sam_ctx);
if (!config_dn) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(sam_ctx);
}
ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
objectGUID = samdb_ntds_objectGUID(sam_ctx);
if (!objectGUID) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(sam_ctx);
}
ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
cached = talloc(sam_ctx, bool);
if (cached == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(sam_ctx);
}
*cached = *am_rodc;
ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
if (ret != LDB_SUCCESS) {
talloc_free(cached);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(sam_ctx);
}
return LDB_SUCCESS;
}
ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
- if (ret) {
+ if (ret != LDB_SUCCESS) {
goto failed;
}
struct ldb_result *res;
ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
- if (ret) {
+ if (ret != LDB_SUCCESS) {
goto failed;
}
}
/*
- return domain functional level
- returns DS_DOMAIN_FUNCTION_*
+ * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
*/
int dsdb_functional_level(struct ldb_context *ldb)
{
int *domainFunctionality =
talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
if (!domainFunctionality) {
- DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
+ /* this is expected during initial provision */
+ DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
return DS_DOMAIN_FUNCTION_2000;
}
return *domainFunctionality;
}
+/*
+ * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
+ */
+int dsdb_forest_functional_level(struct ldb_context *ldb)
+{
+ int *forestFunctionality =
+ talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
+ if (!forestFunctionality) {
+ DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
+ return DS_DOMAIN_FUNCTION_2000;
+ }
+ return *forestFunctionality;
+}
+
/*
set a GUID in an extended DN structure
*/
struct TALLOC_CTX *tmp_ctx;
enum ndr_err_code ndr_err;
- sid_blob = ldb_dn_get_extended_component(dn, "SID");
+ sid_blob = ldb_dn_get_extended_component(dn, component_name);
if (!sid_blob) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
return RMD_FLAGS directly from a ldb_val for a DN
returns 0 if RMD_FLAGS is not found
*/
-uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val)
+uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
{
const char *p;
uint32_t flags;
/*
return true if a ldb_val containing a DN in storage form is deleted
*/
-bool dsdb_dn_is_deleted_val(struct ldb_val *val)
+bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
{
return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
}
wk_guid, ldb_dn_get_linearized(nc_root));
if (!wkguid_dn) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(samdb);
}
ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
tmp_ctx = talloc_new(samdb);
if (tmp_ctx == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(samdb);
}
ret = ldb_search(samdb, tmp_ctx, &root_res,
ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
- if (ret) {
+ if (ret != LDB_SUCCESS) {
DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
talloc_free(tmp_ctx);
return ret;
nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
if (!nc_dns) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(samdb);
}
for (i=0; i<el->num_values; i++) {
nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
if (nc_dns[i] == NULL) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(samdb);
}
}
}
dn = ldb_dn_copy(ldb, dn);
if (!dn) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
/* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
be a wellknown GUID for this */
if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
talloc_free(dn);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
*lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
if (!our_invocation_id) {
DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
talloc_free(*cursors);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(samdb);
}
ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
(*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
if (! *cursors) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(samdb);
}
(*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
{
struct drsuapi_DsReplicaCursor2 *v2;
- unsigned int i;
+ uint32_t i;
int ret;
ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
*cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
if (*cursors == NULL) {
talloc_free(v2);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(samdb);
}
for (i=0; i<*count; i++) {
}
}
+ if (dsdb_flags & DSDB_TREE_DELETE) {
+ ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
return LDB_SUCCESS;
}
+/*
+ an add with a set of controls
+*/
+int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
+ uint32_t dsdb_flags)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_add_req(&req, ldb, ldb,
+ message,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ ret = dsdb_request_add_controls(req, dsdb_flags);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(req);
+ return ret;
+ }
+
+ ret = dsdb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
/*
a modify with a set of controls
*/
res = talloc_zero(mem_ctx, struct ldb_result);
if (!res) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
ret = ldb_build_search_req(&req, ldb, res,
return LDB_SUCCESS;
}
+/*
+ search for attrs on one DN, by the GUID of the DN, allowing for
+ dsdb_flags controls
+ */
+int dsdb_search_by_dn_guid(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result **_res,
+ const struct GUID *guid,
+ const char * const *attrs,
+ uint32_t dsdb_flags)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct ldb_dn *dn;
+ int ret;
+
+ dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
+ if (!ldb_dn_validate(dn)) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
/*
general search with dsdb_flags for controls
*/
res = talloc_zero(tmp_ctx, struct ldb_result);
if (!res) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
if (exp_fmt) {
if (!expression) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
}
ret = dsdb_request_add_controls(req, dsdb_flags);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
+ ldb_reset_err_string(ldb);
return ret;
}
if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
if (res->count == 0) {
talloc_free(tmp_ctx);
+ ldb_reset_err_string(ldb);
return LDB_ERR_NO_SUCH_OBJECT;
}
if (res->count != 1) {
talloc_free(tmp_ctx);
+ ldb_reset_err_string(ldb);
return LDB_ERR_CONSTRAINT_VIOLATION;
}
}
res = talloc_zero(tmp_ctx, struct ldb_result);
if (!res) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
if (exp_fmt) {
if (!expression) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_oom(ldb);
}
ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
dsdb_flags, "%s", expression);
- remove "NTDS Settings" component from DN
- do a base search on that DN for serverReference with
extended-dn enabled
- - extract objectSID from resulting serverReference
+ - extract objectSid from resulting serverReference
attribute
- check this sid matches the sid argument
*/
DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
dn = msg->dn;
if (!ldb_dn_remove_child_components(dn, 1)) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
if (!dom_sid_equal(sid, &sid2)) {
dom_sid_string(tmp_ctx, sid),
dom_sid_string(tmp_ctx, &sid2)));
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_operr(ldb);
}
talloc_free(tmp_ctx);
return LDB_SUCCESS;
}
-const char *rodc_fas_list[] = {"ms-PKI-DPAPIMasterKeys",
- "ms-PKI-AccountCredentials",
- "ms-PKI-RoamingTimeStamp",
- "ms-FVE-KeyPackage",
- "ms-FVE-RecoveryGuid",
- "ms-FVE-RecoveryInformation",
- "ms-FVE-RecoveryPassword",
- "ms-FVE-VolumeGuid",
- "ms-TPM-OwnerInformation",
- NULL};
+static const char *secret_attributes[] = {
+ "currentValue",
+ "dBCSPwd",
+ "initialAuthIncoming",
+ "initialAuthOutgoing",
+ "lmPwdHistory",
+ "ntPwdHistory",
+ "priorValue",
+ "supplementalCredentials",
+ "trustAuthIncoming",
+ "trustAuthOutgoing",
+ "unicodePwd",
+ NULL
+};
+
/*
check if the attribute belongs to the RODC filtered attribute set
+ Note that attributes that are in the filtered attribute set are the
+ ones that _are_ always sent to a RODC
*/
-bool dsdb_attr_in_rodc_fas(uint32_t replica_flags, const struct dsdb_attribute *sa)
+bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
{
- int rodc_filtered_flags = SEARCH_FLAG_RODC_ATTRIBUTE | SEARCH_FLAG_CONFIDENTIAL;
- bool drs_write_replica = ((replica_flags & DRSUAPI_DRS_WRIT_REP) == 0);
+ /* they never get secret attributes */
+ if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
+ return false;
+ }
- if (drs_write_replica && (sa->searchFlags & rodc_filtered_flags)) {
+ /* they do get non-secret critical attributes */
+ if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
return true;
}
- if (drs_write_replica && is_attr_in_list(rodc_fas_list, sa->cn)) {
+
+ /* they do get non-secret attributes marked as being in the FAS */
+ if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
return true;
}
+
+ /* other attributes are denied */
return false;
}
+
+/* return fsmo role dn and role owner dn for a particular role*/
+WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
+ struct ldb_context *ldb,
+ uint32_t role,
+ struct ldb_dn **fsmo_role_dn,
+ struct ldb_dn **role_owner_dn)
+{
+ int ret;
+ switch (role) {
+ case DREPL_NAMING_MASTER:
+ *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
+ ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
+ ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ break;
+ case DREPL_INFRASTRUCTURE_MASTER:
+ *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
+ ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
+ ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ break;
+ case DREPL_RID_MASTER:
+ ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+
+ ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
+ ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ break;
+ case DREPL_SCHEMA_MASTER:
+ *fsmo_role_dn = ldb_get_schema_basedn(ldb);
+ ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
+ ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ break;
+ case DREPL_PDC_MASTER:
+ *fsmo_role_dn = ldb_get_default_basedn(ldb);
+ ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
+ ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ break;
+ default:
+ return WERR_DS_DRA_INTERNAL_ERROR;
+ }
+ return WERR_OK;
+}
+
+const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *server_dn)
+{
+ int ldb_ret;
+ struct ldb_result *res = NULL;
+ const char * const attrs[] = { "dNSHostName", NULL};
+
+ ldb_ret = ldb_search(ldb, mem_ctx, &res,
+ server_dn,
+ LDB_SCOPE_BASE,
+ attrs, NULL);
+ if (ldb_ret != LDB_SUCCESS) {
+ DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
+ ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
+ return NULL;
+ }
+
+ return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
+}
+
+/*
+ returns true if an attribute is in the filter,
+ false otherwise, provided that attribute value is provided with the expression
+*/
+bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
+ const char *attr)
+{
+ unsigned int i;
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
+ attr))
+ return true;
+ }
+ return false;
+ case LDB_OP_NOT:
+ return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
+ case LDB_OP_EQUALITY:
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_APPROX:
+ if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
+ return true;
+ }
+ return false;
+ case LDB_OP_SUBSTRING:
+ if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
+ return true;
+ }
+ return false;
+ case LDB_OP_PRESENT:
+ /* (attrname=*) is not filtered out */
+ return false;
+ case LDB_OP_EXTENDED:
+ if (tree->u.extended.attr &&
+ ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+