This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ 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,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
if (!ldb) {
return NULL;
}
+ dsdb_make_schema_global(ldb);
return ldb;
}
*/
NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
{
- const char *str = ldb_msg_find_attr_as_string(msg, attr, NULL);
- if (!str) return default_value;
- return nttime_from_string(str);
+ return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
}
/*
struct samr_Password *lmPwdHash, *ntPwdHash;
if (nt_pwd) {
int num_nt;
- num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
+ num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
if (num_nt == 0) {
*nt_pwd = NULL;
} else if (num_nt > 1) {
}
if (lm_pwd) {
int num_lm;
- num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
+ num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
if (num_lm == 0) {
*lm_pwd = NULL;
} else if (num_lm > 1) {
/* Find an attribute, with a particular value */
+
+/* The current callers of this function expect a very specific
+ * behaviour: In particular, objectClass subclass equivilance is not
+ * wanted. This means that we should not lookup the schema for the
+ * comparison function */
struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
const struct ldb_message *msg,
const char *name, const char *value)
copy from a template record to a message
*/
int samdb_copy_template(struct ldb_context *ldb,
- struct ldb_message *msg, const char *filter,
+ struct ldb_message *msg, const char *name,
const char **errstring)
{
struct ldb_result *res;
*errstring = NULL;
+ if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
+ *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
+ name);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
/* pull the template record */
- ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
+ ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res);
talloc_free(basedn);
if (ret != LDB_SUCCESS) {
*errstring = talloc_steal(msg, ldb_errstring(ldb));
return ret;
}
if (res->count != 1) {
- *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter,
+ *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
+ name,
res->count);
talloc_free(res);
return LDB_ERR_OPERATIONS_ERROR;
for (i = 0; i < t->num_elements; i++) {
struct ldb_message_element *el = &t->elements[i];
/* some elements should not be copied from the template */
- if (strcasecmp(el->name, "cn") == 0 ||
- strcasecmp(el->name, "name") == 0 ||
- strcasecmp(el->name, "sAMAccountName") == 0 ||
- strcasecmp(el->name, "sAMAccountName") == 0 ||
- strcasecmp(el->name, "distinguishedName") == 0 ||
- strcasecmp(el->name, "objectGUID") == 0) {
+ if (ldb_attr_cmp(el->name, "cn") == 0 ||
+ ldb_attr_cmp(el->name, "name") == 0 ||
+ ldb_attr_cmp(el->name, "objectClass") == 0 ||
+ ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
+ ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
+ ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
+ ldb_attr_cmp(el->name, "objectGUID") == 0) {
continue;
}
for (j = 0; j < el->num_values; j++) {
- if (strcasecmp(el->name, "objectClass") == 0) {
- if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
- strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
- strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
- strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
- strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
- strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
- strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
- continue;
- }
- ret = samdb_find_or_add_value(ldb, msg, el->name,
- (char *)el->values[j].data);
- if (ret) {
- *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
- talloc_free(res);
- return ret;
- }
- } else {
- ret = samdb_find_or_add_attribute(ldb, msg, el->name,
- (char *)el->values[j].data);
- if (ret) {
- *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
- talloc_free(res);
- return ret;
- }
+ ret = samdb_find_or_add_attribute(ldb, msg, el->name,
+ (char *)el->values[j].data);
+ if (ret) {
+ *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
+ talloc_free(res);
+ return ret;
}
}
}
return ldb_get_default_basedn(sam_ctx);
}
+struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
+{
+ return ldb_get_config_basedn(sam_ctx);
+}
+
+struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
+{
+ return ldb_get_schema_basedn(sam_ctx);
+}
+
+struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
+{
+ return ldb_get_root_basedn(sam_ctx);
+}
struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
{
struct ldb_dn *new_dn;
- new_dn = ldb_dn_copy(mem_ctx, samdb_base_dn(sam_ctx));
- if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions,CN=Configuration")) {
+ new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
+ if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
talloc_free(new_dn);
return NULL;
}
{
struct ldb_dn *new_dn;
- new_dn = ldb_dn_copy(mem_ctx, samdb_base_dn(sam_ctx));
- if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites,CN=Configuration")) {
+ new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
+ if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
talloc_free(new_dn);
return NULL;
}
/*
work out the ntds settings dn for the current open ldb
*/
-const struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
+struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
{
TALLOC_CTX *tmp_ctx;
const char *root_attrs[] = { "dsServiceName", NULL };
ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
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;
return NULL;
}
+/*
+ work out the ntds settings invocationId for the current open ldb
+*/
+const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = { "invocationId", NULL };
+ int ret;
+ struct ldb_result *res;
+ struct GUID *invocation_id;
+
+ /* see if we have a cached copy */
+ invocation_id = ldb_get_opaque(ldb, "cache.invocation_id");
+ if (invocation_id) {
+ return invocation_id;
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
+ if (ret) {
+ goto failed;
+ }
+ talloc_steal(tmp_ctx, res);
+
+ if (res->count != 1) {
+ goto failed;
+ }
+
+ invocation_id = talloc(tmp_ctx, struct GUID);
+ if (!invocation_id) {
+ goto failed;
+ }
+
+ *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
+
+ /* cache the domain_sid in the ldb */
+ if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ talloc_steal(ldb, invocation_id);
+ talloc_free(tmp_ctx);
+
+ return invocation_id;
+
+failed:
+ DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct GUID *invocation_id_new;
+ struct GUID *invocation_id_old;
+
+ /* see if we have a cached copy */
+ invocation_id_old = ldb_get_opaque(ldb, "cache.invocation_id");
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ invocation_id_new = talloc(tmp_ctx, struct GUID);
+ if (!invocation_id_new) {
+ goto failed;
+ }
+
+ *invocation_id_new = *invocation_id_in;
+
+ /* cache the domain_sid in the ldb */
+ if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ talloc_steal(ldb, invocation_id_new);
+ talloc_free(tmp_ctx);
+ talloc_free(invocation_id_old);
+
+ return true;
+
+failed:
+ DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
+ talloc_free(tmp_ctx);
+ return false;
+}
+
+/*
+ work out the ntds settings objectGUID for the current open ldb
+*/
+const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = { "objectGUID", NULL };
+ int ret;
+ struct ldb_result *res;
+ struct GUID *ntds_guid;
+
+ /* see if we have a cached copy */
+ ntds_guid = ldb_get_opaque(ldb, "cache.ntds_guid");
+ if (ntds_guid) {
+ return ntds_guid;
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
+ if (ret) {
+ goto failed;
+ }
+ talloc_steal(tmp_ctx, res);
+
+ if (res->count != 1) {
+ goto failed;
+ }
+
+ ntds_guid = talloc(tmp_ctx, struct GUID);
+ if (!ntds_guid) {
+ goto failed;
+ }
+
+ *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
+
+ /* cache the domain_sid in the ldb */
+ if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ talloc_steal(ldb, ntds_guid);
+ talloc_free(tmp_ctx);
+
+ return ntds_guid;
+
+failed:
+ DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct GUID *ntds_guid_new;
+ struct GUID *ntds_guid_old;
+
+ /* see if we have a cached copy */
+ ntds_guid_old = ldb_get_opaque(ldb, "cache.ntds_guid");
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ ntds_guid_new = talloc(tmp_ctx, struct GUID);
+ if (!ntds_guid_new) {
+ goto failed;
+ }
+
+ *ntds_guid_new = *ntds_guid_in;
+
+ /* cache the domain_sid in the ldb */
+ if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ talloc_steal(ldb, ntds_guid_new);
+ talloc_free(tmp_ctx);
+ talloc_free(ntds_guid_old);
+
+ return true;
+
+failed:
+ DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
+ talloc_free(tmp_ctx);
+ return false;
+}
+
/*
work out the server dn for the current open ldb
*/
return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
}
+/*
+ work out the server dn for the current open ldb
+*/
+struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
+{
+ struct ldb_dn *server_dn;
+ struct ldb_dn *server_site_dn;
+
+ server_dn = samdb_server_dn(ldb, mem_ctx);
+ if (!server_dn) return NULL;
+
+ server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
+
+ talloc_free(server_dn);
+ return server_site_dn;
+}
+
/*
work out if we are the PDC for the domain of the current open ldb
*/
tmp_ctx = talloc_new(ldb);
if (tmp_ctx == NULL) {
- goto failed;
+ DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
+ return False;
}
ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
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);
struct samr_Password *lmNewHash,
struct samr_Password *ntNewHash,
BOOL user_change,
- BOOL restrictions,
enum samr_RejectReason *reject_reason,
struct samr_DomInfo1 **_dominfo)
{
- const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory",
- "sambaNTPwdHistory",
- "lmPwdHash", "ntPwdHash",
+ const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
+ "ntPwdHistory",
+ "dBCSPwd", "unicodePwd",
"objectSid",
"pwdLastSet", NULL };
const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
struct dom_sid *domain_sid;
struct ldb_message **res;
+ BOOL restrictions;
int count;
time_t now = time(NULL);
NTTIME now_nt;
}
userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
- "sambaLMPwdHistory", &sambaLMPwdHistory);
+ "lmPwdHistory", &sambaLMPwdHistory);
sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
- "sambaNTPwdHistory", &sambaNTPwdHistory);
- lmPwdHash = samdb_result_hash(mem_ctx, res[0], "lmPwdHash");
- ntPwdHash = samdb_result_hash(mem_ctx, res[0], "ntPwdHash");
+ "ntPwdHistory", &sambaNTPwdHistory);
+ lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
+ ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
+ /* Only non-trust accounts have restrictions (possibly this
+ * test is the wrong way around, but I like to be restrictive
+ * if possible */
+ restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
+ |UF_WORKSTATION_TRUST_ACCOUNT
+ |UF_SERVER_TRUST_ACCOUNT));
+
if (domain_dn) {
/* pull the domain parameters */
count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
*_dominfo = dominfo;
}
- if (new_pass) {
+ if (restrictions && new_pass) {
+
/* check the various password restrictions */
if (restrictions && minPwdLength > strlen_m(new_pass)) {
if (reject_reason) {
ntNewHash = &local_ntNewHash;
}
- if (restrictions && user_change) {
+ if (user_change) {
/* are all password changes disallowed? */
if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
if (reject_reason) {
CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
if (lmNewHash) {
- CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
+ CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
} else {
- CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
+ CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
}
if (ntNewHash) {
- CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
+ CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
} else {
- CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
+ CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
}
}
struct samr_Password *lmNewHash,
struct samr_Password *ntNewHash,
BOOL user_change,
- BOOL restrictions,
enum samr_RejectReason *reject_reason,
struct samr_DomInfo1 **_dominfo)
{
msg, new_pass,
lmNewHash, ntNewHash,
user_change, /* This is a password set, not change */
- restrictions, /* run restriction tests */
reject_reason, _dominfo);
if (!NT_STATUS_IS_OK(nt_status)) {
ldb_transaction_cancel(ctx);
return NT_STATUS_OK;
}
+
+/*
+ Find the DN of a domain, assuming it to be a dotted.dns name
+*/
+
+struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
+{
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ 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, ".");
+ if (!split_realm) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ dn = ldb_dn_new(mem_ctx, ldb, NULL);
+ for (i=0; split_realm[i]; i++) {
+ binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
+ if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
+ DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
+ binary_encoded, ldb_dn_get_linearized(dn)));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ }
+ if (!ldb_dn_validate(dn)) {
+ DEBUG(2, ("Failed to validated DN %s\n",
+ ldb_dn_get_linearized(dn)));
+ return NULL;
+ }
+ return dn;
+}
/*
Find the DN of a domain, be it the netbios or DNS name
*/
const char * const domain_ref_attrs[] = {
"ncName", NULL
};
+ const char * const domain_ref2_attrs[] = {
+ NULL
+ };
struct ldb_result *res_domain_ref;
char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
/* find the domain's DN */
samdb_partitions_dn(ldb, mem_ctx),
LDB_SCOPE_ONELEVEL,
domain_ref_attrs,
- "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
- escaped_domain, escaped_domain);
+ "(&(nETBIOSName=%s)(objectclass=crossRef))",
+ escaped_domain);
if (ret_domain != 0) {
return NULL;
}
if (res_domain_ref->count == 0) {
- DEBUG(3,("sam_search_user: Couldn't find domain [%s] in samdb.\n",
- domain_name));
+ ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
+ &res_domain_ref,
+ samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
+ LDB_SCOPE_BASE,
+ domain_ref2_attrs,
+ "(objectclass=domain)");
+ if (ret_domain != 0) {
+ return NULL;
+ }
+
+ if (res_domain_ref->count == 1) {
+ return res_domain_ref->msgs[0]->dn;
+ }
return NULL;
}