#include "lib/util/tsort.h"
#include "dsdb/common/util.h"
#include "lib/socket/socket.h"
-#include "dsdb/samdb/ldb_modules/util.h"
+#include "librpc/gen_ndr/irpc.h"
+#include "libds/common/flag_mapping.h"
/*
search the sam for the specified attributes in a specific domain, filter on
return NULL;
}
- return samdb_result_string(res[0], attr_name, NULL);
+ return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
}
/*
return the count of the number of records in the sam matching the query
*/
int samdb_search_count(struct ldb_context *sam_ldb,
+ TALLOC_CTX *mem_ctx,
struct ldb_dn *basedn,
- const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
+ const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
{
va_list ap;
- struct ldb_message **res;
const char *attrs[] = { NULL };
int ret;
- TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
va_start(ap, format);
- ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
+ ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap);
va_end(ap);
- talloc_free(tmp_ctx);
return ret;
}
return default_value;
}
- return samdb_result_uint(res[0], attr_name, default_value);
+ return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
}
/*
return default_value;
}
- return samdb_result_int64(res[0], attr_name, default_value);
+ return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
}
/*
}
for (i=0;i<count;i++) {
- (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
+ (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
}
(*strs)[count] = NULL;
return count;
}
-/*
- pull a uint from a result set.
-*/
-unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
-{
- return ldb_msg_find_attr_as_uint(msg, attr, default_value);
-}
-
-/*
- pull a (signed) int64 from a result set.
-*/
-int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
-{
- return ldb_msg_find_attr_as_int64(msg, attr, default_value);
-}
-
-/*
- pull a string from a result set.
-*/
-const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
- const char *default_value)
-{
- return ldb_msg_find_attr_as_string(msg, attr, default_value);
-}
-
struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
const char *attr, struct ldb_dn *default_value)
{
struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
const char *attr)
{
+ bool ok;
const struct ldb_val *v;
struct dom_sid *sid;
- enum ndr_err_code ndr_err;
v = ldb_msg_find_ldb_val(msg, attr);
if (v == NULL) {
return NULL;
if (sid == NULL) {
return NULL;
}
- ndr_err = ndr_pull_struct_blob(v, sid, sid,
- (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ ok = sid_blob_parse(*v, sid);
+ if (!ok) {
talloc_free(sid);
return NULL;
}
return ret;
}
-/*
- pull a uint64_t from a result set.
-*/
-uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
- uint64_t default_value)
-{
- return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
-}
-
-
/*
construct the allow_password_change field from the PwdLastSet attribute and the
domain password settings
struct ldb_message *msg,
const char *attr)
{
- uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
+ uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
int64_t minPwdAge;
if (attr_time == 0) {
struct ldb_dn *domain_dn,
struct ldb_message *msg)
{
- int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
+ int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
"userAccountControl",
0);
return NULL;
}
-/*
- * This is intended for use by the "password hash" module since there
- * password changes can be specified through one message element with the
- * new password (to set) and another one with the old password (to unset).
- *
- * The first which sets a password (new value) can have flags
- * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
- * for entries). The latter (old value) has always specified
- * LDB_FLAG_MOD_DELETE.
- *
- * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
- * doesn't contain only one value (this is the Windows Server behaviour)
- * otherwise LDB_SUCCESS.
- */
-int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
- const char *name,
- const struct ldb_val **new_val,
- const struct ldb_val **old_val)
-{
- unsigned int i;
-
- *new_val = NULL;
- *old_val = NULL;
-
- if (msg == NULL) {
- return LDB_SUCCESS;
- }
-
- 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) {
- *old_val = &msg->elements[i].values[0];
- } else {
- *new_val = &msg->elements[i].values[0];
- }
- }
- }
-
- return LDB_SUCCESS;
-}
-
-int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
-{
- if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
- return samdb_msg_add_string(ldb, msg, msg, name, set_value);
- }
- return LDB_SUCCESS;
-}
-
int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
{
struct ldb_message_element *el;
return LDB_SUCCESS;
}
- return samdb_msg_add_string(ldb, msg, msg, name, set_value);
-}
-
-
-
-/*
- add a string element to a message
-*/
-int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
- const char *attr_name, const char *str)
-{
- char *s = talloc_strdup(mem_ctx, str);
- char *a = talloc_strdup(mem_ctx, attr_name);
- if (s == NULL || a == NULL) {
- return ldb_oom(sam_ldb);
- }
- return ldb_msg_add_string(msg, a, s);
+ return ldb_msg_add_string(msg, name, set_value);
}
/*
add a dom_sid element to a message
*/
int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
- const char *attr_name, struct dom_sid *sid)
+ const char *attr_name, const struct dom_sid *sid)
{
struct ldb_val v;
enum ndr_err_code ndr_err;
for (i = 0; i < msg->num_elements; i++) {
el = &msg->elements[i];
if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
- (el->flags == LDB_FLAG_MOD_ADD)) {
+ (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
found = true;
break;
}
}
}
- vals = talloc_realloc(msg, el->values, struct ldb_val,
+ vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
el->num_values + 1);
if (vals == NULL) {
return ldb_oom(sam_ldb);
for (i = 0; i < msg->num_elements; i++) {
el = &msg->elements[i];
if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
- (el->flags == LDB_FLAG_MOD_DELETE)) {
+ (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
found = true;
break;
}
}
}
- vals = talloc_realloc(msg, el->values, struct ldb_val,
+ vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
el->num_values + 1);
if (vals == NULL) {
return ldb_oom(sam_ldb);
const char *attr_name, int v)
{
const char *s = talloc_asprintf(mem_ctx, "%d", v);
- return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
+ if (s == NULL) {
+ return ldb_oom(sam_ldb);
+ }
+ return ldb_msg_add_string(msg, attr_name, s);
}
/*
- add a unsigned int element to a message
-*/
+ * Add an unsigned int element to a message
+ *
+ * The issue here is that we have not yet first cast to int32_t explicitly,
+ * before we cast to an signed int to printf() into the %d or cast to a
+ * int64_t before we then cast to a long long to printf into a %lld.
+ *
+ * There are *no* unsigned integers in Active Directory LDAP, even the RID
+ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
+ * (See the schema, and the syntax definitions in schema_syntax.c).
+ *
+ */
int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
const char *attr_name, unsigned int v)
{
const char *attr_name, int64_t v)
{
const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
- return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
+ if (s == NULL) {
+ return ldb_oom(sam_ldb);
+ }
+ return ldb_msg_add_string(msg, attr_name, s);
}
/*
- add a uint64_t element to a message
-*/
+ * Add an unsigned int64_t (uint64_t) element to a message
+ *
+ * The issue here is that we have not yet first cast to int32_t explicitly,
+ * before we cast to an signed int to printf() into the %d or cast to a
+ * int64_t before we then cast to a long long to printf into a %lld.
+ *
+ * There are *no* unsigned integers in Active Directory LDAP, even the RID
+ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
+ * (See the schema, and the syntax definitions in schema_syntax.c).
+ *
+ */
int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
const char *attr_name, uint64_t v)
{
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);
val.data = (uint8_t *)parameters->array;
return ldb_msg_add_value(msg, attr_name, &val, NULL);
}
-/*
- add a general value element to a message
-*/
-int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
- const char *attr_name, const struct ldb_val *val)
-{
- return ldb_msg_add_value(msg, attr_name, val, NULL);
-}
/*
sets a general value element to a message
if (el) {
el->num_values = 0;
}
- return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
+ return ldb_msg_add_string(msg, attr_name, str);
+}
+
+/*
+ * sets a signed integer in a message
+ */
+int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg, const char *attr_name, int v)
+{
+ struct ldb_message_element *el;
+
+ el = ldb_msg_find_element(msg, attr_name);
+ if (el) {
+ el->num_values = 0;
+ }
+ return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
+}
+
+/*
+ * Sets an unsigned int element in a message
+ *
+ * The issue here is that we have not yet first cast to int32_t explicitly,
+ * before we cast to an signed int to printf() into the %d or cast to a
+ * int64_t before we then cast to a long long to printf into a %lld.
+ *
+ * There are *no* unsigned integers in Active Directory LDAP, even the RID
+ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
+ * (See the schema, and the syntax definitions in schema_syntax.c).
+ *
+ */
+int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg, const char *attr_name,
+ unsigned int v)
+{
+ struct ldb_message_element *el;
+
+ el = ldb_msg_find_element(msg, attr_name);
+ if (el) {
+ el->num_values = 0;
+ }
+ return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
}
/*
struct ldb_dn *ntds_settings_dn_new;
struct ldb_dn *ntds_settings_dn_old;
- /* see if we have a cached copy */
+ /* see if we have a forced copy from provision */
ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
- "cache.ntds_settings_dn"), struct ldb_dn);
+ "forced.ntds_settings_dn"), struct ldb_dn);
tmp_ctx = talloc_new(ldb);
if (tmp_ctx == NULL) {
goto failed;
}
- /* cache the domain_sid in the ldb */
- if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
+ /* set the DN in the ldb to avoid lookups during provision */
+ if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
goto failed;
}
return false;
}
-/* Obtain the short name of the flexible single master operator
- * (FSMO), such as the PDC Emulator */
-const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
- const char *attr)
-{
- /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
- struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
- const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
- const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
-
- if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
- /* Ensure this matches the format. This gives us a
- * bit more confidence that a 'cn' value will be a
- * ascii string */
- return NULL;
- }
- if (val) {
- return (char *)val->data;
- }
- return NULL;
-}
-
/*
work out the ntds settings dn for the current open ldb
*/
struct ldb_dn *settings_dn;
/* see if we have a cached copy */
- settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
+ settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
if (settings_dn) {
return settings_dn;
}
settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
- /* cache the domain_sid in the ldb */
- if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
- goto failed;
- }
+ /* note that we do not cache the DN here, as that would mean
+ * we could not handle server renames at runtime. Only
+ * provision sets up forced.ntds_settings_dn */
talloc_steal(ldb, settings_dn);
talloc_free(tmp_ctx);
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);
+ if (rdn_val == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ (*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;
}
allow_list[0] = l_subnet_name;
- if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
+ if (socket_allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
res->msgs[i],
"siteObject");
* is for sure the same as our server site). If more sites do
* exist then we don't know which one to use and set the site
* name to "". */
- cnt = samdb_search_count(ldb, sites_container_dn,
+ cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn,
"(objectClass=site)");
if (cnt == 1) {
site_name = samdb_server_site_name(ldb, mem_ctx);
*/
bool samdb_is_gc(struct ldb_context *ldb)
{
- const char *attrs[] = { "options", NULL };
- int ret, options;
- struct ldb_result *res;
- TALLOC_CTX *tmp_ctx;
-
- tmp_ctx = talloc_new(ldb);
- if (tmp_ctx == NULL) {
- DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
+ uint32_t options;
+ if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
return false;
}
-
- /* Query cn=ntds settings,.... */
- ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return false;
- }
- if (res->count != 1) {
- talloc_free(tmp_ctx);
- return false;
- }
-
- options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
- talloc_free(tmp_ctx);
-
- /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
- if (options & 0x000000001) {
- return true;
- }
- return false;
+ return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
}
/* Find a domain object in the parents of a particular DN. */
/*
* 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 information 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) { \
if ((new_password != NULL)
&& ((lmNewHash == NULL) && (ntNewHash == NULL))) {
/* we have the password as plaintext UTF16 */
- CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
- "clearTextPassword", new_password));
+ CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
+ new_password, NULL));
el = ldb_msg_find_element(msg, "clearTextPassword");
el->flags = LDB_FLAG_MOD_REPLACE;
} else if ((new_password == NULL)
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 information 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);
return NT_STATUS_NO_MEMORY;
}
- samdb_msg_add_string(sam_ctx, msg, msg,
- "objectClass",
- "foreignSecurityPrincipal");
+ ret = ldb_msg_add_string(msg, "objectClass",
+ "foreignSecurityPrincipal");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(sidstr);
+ return NT_STATUS_NO_MEMORY;
+ }
/* create the alias */
ret = ldb_add(sam_ctx, msg);
return dn;
}
+
+/*
+ Find the DNS equivalent of a DN, in dotted DNS form
+*/
+char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
+{
+ int i, num_components = ldb_dn_get_comp_num(dn);
+ char *dns_name = talloc_strdup(mem_ctx, "");
+ if (dns_name == NULL) {
+ return NULL;
+ }
+
+ for (i=0; i<num_components; i++) {
+ const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
+ char *s;
+ if (v == NULL) {
+ talloc_free(dns_name);
+ return NULL;
+ }
+ s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
+ (int)v->length, (int)v->length, (char *)v->data);
+ if (s == NULL) {
+ talloc_free(dns_name);
+ return NULL;
+ }
+ dns_name = s;
+ }
+
+ /* remove the last '.' */
+ if (dns_name[0] != 0) {
+ dns_name[strlen(dns_name)-1] = 0;
+ }
+
+ return dns_name;
+}
+
+/*
+ Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
+ name is based on the forest DNS name
+*/
+char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *ntds_guid)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ const char *guid_str;
+ struct ldb_dn *forest_dn;
+ const char *dnsforest;
+ char *ret;
+
+ guid_str = GUID_string(tmp_ctx, ntds_guid);
+ if (guid_str == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ forest_dn = ldb_get_root_basedn(samdb);
+ if (forest_dn == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
+ if (dnsforest == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
/*
Find the DN of a domain, be it the netbios or DNS name
*/
attrs[0] = attribute;
attrs[1] = NULL;
- ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
+ ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_RECYCLED);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
{
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;
ZERO_STRUCTP(sid);
- ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
+ ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_RECYCLED);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
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;
int ret;
struct ldb_result *res;
const char *attrs[] = { NULL };
- char *sid_str = dom_sid_string(mem_ctx, sid);
+ char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
if (!sid_str) {
return ldb_operr(ldb);
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
DSDB_SEARCH_SHOW_EXTENDED_DN |
DSDB_SEARCH_ONE_ONLY,
- "objectSID=%s", sid_str);
+ "objectSid=%s", sid_str);
talloc_free(sid_str);
if (ret != LDB_SUCCESS) {
return ret;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
unsigned int i;
struct ldb_message_element *el;
+ int ret;
*r = NULL;
*count = 0;
- if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
- res->count < 1) {
- DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
+ ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* partition hasn't been replicated yet */
+ return WERR_OK;
+ }
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
talloc_free(tmp_ctx);
return WERR_DS_DRA_INTERNAL_ERROR;
}
el->values[i] = v;
}
- if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
+ if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
goto failed;
}
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
- if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
/* it hasn't been created yet, which means
an implicit value of zero */
*uSN = 0;
}
+/*
+ * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
+ * flags are DS_NTDSSETTINGS_OPT_*
+ */
+int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
+ uint32_t *options)
+{
+ int rc;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ struct ldb_dn *site_dn;
+ const char *attrs[] = { "options", NULL };
+
+ tmp_ctx = talloc_new(ldb_ctx);
+ if (tmp_ctx == NULL)
+ goto failed;
+
+ /* Retrieve the site dn for the ldb that we
+ * have open. This is our local site.
+ */
+ site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
+ if (site_dn == NULL)
+ goto failed;
+
+ /* Perform a one level (child) search from the local
+ * site distinguided name. We're looking for the
+ * "options" attribute within the nTDSSiteSettings
+ * object
+ */
+ rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "objectClass=nTDSSiteSettings");
+
+ if (rc != LDB_SUCCESS || res->count != 1)
+ goto failed;
+
+ *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
+
+ talloc_free(tmp_ctx);
+
+ return LDB_SUCCESS;
+
+failed:
+ DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_NO_SUCH_OBJECT;
+}
+
/*
return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
goto failed;
}
- *options = samdb_result_uint(res->msgs[0], "options", 0);
+ *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
talloc_free(tmp_ctx);
goto failed;
}
- return samdb_result_string(res->msgs[0], "objectCategory", NULL);
+ return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
failed:
DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
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;
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;
}
if (val->length < 13) {
return 0;
}
- p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
+ p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
if (!p) {
return 0;
}
*/
bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
{
- return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
+ return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
}
/*
return ldb_operr(samdb);
}
- ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
+ ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_RECYCLED);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
talloc_free(tmp_ctx);
return ret;
- }
+ }
- el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
- if (!el) {
- DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
- ldb_errstring(samdb)));
- talloc_free(tmp_ctx);
- return LDB_ERR_NO_SUCH_ATTRIBUTE;
- }
+ el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
+ if ((el == NULL) || (el->num_values < 3)) {
+ struct ldb_message *tmp_msg;
+
+ DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list."));
+
+ /* This generates a temporary list of NCs in order to let the
+ * provisioning work. */
+ tmp_msg = ldb_msg_new(tmp_ctx);
+ if (tmp_msg == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(samdb);
+ }
+ ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
+ ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
+ ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
+ ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ el = &tmp_msg->elements[0];
+ }
nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
if (!nc_dns) {
}
}
+ if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
+ ret = ldb_request_add_control(req,
+ DSDB_CONTROL_NO_GLOBAL_CATALOG,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
if (ret != LDB_SUCCESS) {
}
}
+ if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
+ ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
- ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
+ ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
if (ret != LDB_SUCCESS) {
return ret;
}
}
}
+ if (dsdb_flags & DSDB_PROVISION) {
+ ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
+ if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
+ ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
+ ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
return LDB_SUCCESS;
}
return ret;
}
+/*
+ a delete with a set of flags
+*/
+int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
+ uint32_t dsdb_flags)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_del_req(&req, ldb, ldb,
+ dn,
+ 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;
+}
+
/*
like dsdb_modify() but set all the element flags to
LDB_FLAG_MOD_REPLACE
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 (dn == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+
+ 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
*/
char *expression = NULL;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ /* cross-partitions searches with a basedn break multi-domain support */
+ SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
+
res = talloc_zero(tmp_ctx, struct ldb_result);
if (!res) {
talloc_free(tmp_ctx);
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;
}
}
return forest_name;
}
+/* returns back the default domain DNS name */
+const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
+{
+ const char *domain_name = ldb_dn_canonical_string(mem_ctx,
+ ldb_get_default_basedn(ldb));
+ char *p;
+
+ if (domain_name == NULL) {
+ return NULL;
+ }
+
+ p = strchr(domain_name, '/');
+ if (p) {
+ *p = '\0';
+ }
+
+ return domain_name;
+}
+
/*
validate that an DSA GUID belongs to the specified user sid.
The user SID must be a domain controller account (either RODC or
- 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
*/
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 * const secret_attributes[] = {
+ DSDB_SECRET_ATTRIBUTES,
+ 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 ldb_msg_find_attr_as_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;
+}
+
+bool is_attr_in_list(const char * const * attrs, const char *attr)
+{
+ unsigned int i;
+
+ for (i = 0; attrs[i]; i++) {
+ if (ldb_attr_cmp(attrs[i], attr) == 0)
+ return true;
+ }
+
return false;
}
+
+
+/*
+ map an ldb error code to an approximate NTSTATUS code
+ */
+NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
+{
+ switch (err) {
+ case LDB_SUCCESS:
+ return NT_STATUS_OK;
+
+ case LDB_ERR_PROTOCOL_ERROR:
+ return NT_STATUS_DEVICE_PROTOCOL_ERROR;
+
+ case LDB_ERR_TIME_LIMIT_EXCEEDED:
+ return NT_STATUS_IO_TIMEOUT;
+
+ case LDB_ERR_SIZE_LIMIT_EXCEEDED:
+ return NT_STATUS_BUFFER_TOO_SMALL;
+
+ case LDB_ERR_COMPARE_FALSE:
+ case LDB_ERR_COMPARE_TRUE:
+ return NT_STATUS_REVISION_MISMATCH;
+
+ case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
+ return NT_STATUS_NOT_SUPPORTED;
+
+ case LDB_ERR_STRONG_AUTH_REQUIRED:
+ case LDB_ERR_CONFIDENTIALITY_REQUIRED:
+ case LDB_ERR_SASL_BIND_IN_PROGRESS:
+ case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
+ case LDB_ERR_INVALID_CREDENTIALS:
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ case LDB_ERR_UNWILLING_TO_PERFORM:
+ return NT_STATUS_ACCESS_DENIED;
+
+ case LDB_ERR_NO_SUCH_OBJECT:
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ case LDB_ERR_REFERRAL:
+ case LDB_ERR_NO_SUCH_ATTRIBUTE:
+ return NT_STATUS_NOT_FOUND;
+
+ case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
+ return NT_STATUS_NOT_SUPPORTED;
+
+ case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
+ return NT_STATUS_BUFFER_TOO_SMALL;
+
+ case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
+ case LDB_ERR_INAPPROPRIATE_MATCHING:
+ case LDB_ERR_CONSTRAINT_VIOLATION:
+ case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
+ case LDB_ERR_INVALID_DN_SYNTAX:
+ case LDB_ERR_NAMING_VIOLATION:
+ case LDB_ERR_OBJECT_CLASS_VIOLATION:
+ case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
+ case LDB_ERR_NOT_ALLOWED_ON_RDN:
+ return NT_STATUS_INVALID_PARAMETER;
+
+ case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
+
+ case LDB_ERR_BUSY:
+ return NT_STATUS_NETWORK_BUSY;
+
+ case LDB_ERR_ALIAS_PROBLEM:
+ case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
+ case LDB_ERR_UNAVAILABLE:
+ case LDB_ERR_LOOP_DETECT:
+ case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
+ case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
+ case LDB_ERR_OTHER:
+ case LDB_ERR_OPERATIONS_ERROR:
+ break;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+/*
+ create a new naming context that will hold a partial replica
+ */
+int dsdb_create_partial_replica_NC(struct ldb_context *ldb, struct ldb_dn *dn)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+ struct ldb_message *msg;
+ int ret;
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+
+ msg->dn = dn;
+ ret = ldb_msg_add_string(msg, "objectClass", "top");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+
+ /* [MS-DRSR] implies that we should only add the 'top'
+ * objectclass, but that would cause lots of problems with our
+ * objectclass code as top is not structural, so we add
+ * 'domainDNS' as well to keep things sane. We're expecting
+ * this new NC to be of objectclass domainDNS after
+ * replication anyway
+ */
+ ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+
+ ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
+ INSTANCE_TYPE_IS_NC_HEAD|
+ INSTANCE_TYPE_NC_ABOVE|
+ INSTANCE_TYPE_UNINSTANT);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+
+ ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Failed to create new NC for %s - %s\n",
+ ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}