summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c21
-rw-r--r--source4/dsdb/samdb/ldb_modules/samldb.c36
-rw-r--r--source4/lib/ldb/common/ldb.c152
-rw-r--r--source4/setup/provision_init.ldif4
4 files changed, 185 insertions, 28 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index 0d4f0c6a0f..c1eb244e19 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -975,16 +975,25 @@ static int add_krb5_keys_from_NThash(struct ldb_module *module, struct ldb_messa
return LDB_SUCCESS;
}
-static int set_pwdLastSet(struct ldb_module *module, struct ldb_message *msg)
+static int set_pwdLastSet(struct ldb_module *module, struct ldb_message *msg, int is_mod)
{
NTTIME now_nt;
/* set it as now */
unix_to_nt_time(&now_nt, time(NULL));
- /* replace or add */
- if (ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE) != 0) {
- return LDB_ERR_OPERATIONS_ERROR;
+ if (!is_mod) {
+ /* be sure there isn't a 0 value set (eg. coming from the template) */
+ ldb_msg_remove_attr(msg, "pwdLastSet");
+ /* add */
+ if (ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_ADD) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ /* replace */
+ if (ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
if (samdb_msg_add_uint64(module->ldb, msg, msg, "pwdLastSet", now_nt) != 0) {
@@ -1326,7 +1335,7 @@ static int password_hash_add_async_do_add(struct ldb_async_handle *h) {
/* don't touch it if a value is set. It could be an incoming samsync */
if (ldb_msg_find_uint64(msg, "pwdLastSet", 0) == 0) {
- if (set_pwdLastSet(ac->module, msg) != LDB_SUCCESS) {
+ if (set_pwdLastSet(ac->module, msg, 0) != LDB_SUCCESS) {
return LDB_ERR_OPERATIONS_ERROR;
}
}
@@ -1630,7 +1639,7 @@ static int password_hash_mod_async_do_mod(struct ldb_async_handle *h) {
}
/* set change time */
- if (set_pwdLastSet(ac->module, msg) != LDB_SUCCESS) {
+ if (set_pwdLastSet(ac->module, msg, 1) != LDB_SUCCESS) {
return LDB_ERR_OPERATIONS_ERROR;
}
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index e662b2a663..9bf322f384 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -94,14 +94,35 @@ static BOOL samldb_msg_add_sid(struct ldb_module *module, struct ldb_message *ms
return (ldb_msg_add_value(msg, name, &v) == 0);
}
-static BOOL samldb_find_or_add_attribute(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value, const char *set_value)
+static BOOL samldb_find_or_add_value(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value, const char *set_value)
{
+ if (msg == NULL || name == NULL || value == NULL || set_value == NULL) {
+ return False;
+ }
+
if (samldb_find_attribute(msg, name, value) == NULL) {
return samldb_msg_add_string(module, msg, name, set_value);
}
return True;
}
+static BOOL samldb_find_or_add_attribute(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *set_value)
+{
+ int j;
+ struct ldb_message_element *el;
+
+ if (msg == NULL || name == NULL || set_value == NULL) {
+ return False;
+ }
+
+ el = ldb_msg_find_element(msg, name);
+ if (el) {
+ return True;
+ }
+
+ return samldb_msg_add_string(module, msg, name, set_value);
+}
+
/*
allocate a new id, attempting to do it atomically
return 0 on failure, the id on success
@@ -492,16 +513,15 @@ static int samldb_copy_template(struct ldb_module *module, struct ldb_message *m
strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
continue;
}
- if ( ! samldb_find_or_add_attribute(module, msg, el->name,
- (char *)el->values[j].data,
- (char *)el->values[j].data)) {
+ if ( ! samldb_find_or_add_value(module, msg, el->name,
+ (char *)el->values[j].data,
+ (char *)el->values[j].data)) {
ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
talloc_free(res);
return -1;
}
} else {
if ( ! samldb_find_or_add_attribute(module, msg, el->name,
- NULL,
(char *)el->values[j].data)) {
ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
talloc_free(res);
@@ -558,7 +578,7 @@ static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
- if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, name)) {
+ if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", name)) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -620,7 +640,7 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const
}
/* if the only attribute was: "objectclass: computer", then make sure we also add "user" objectclass */
- if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "user", "user")) {
+ if ( ! samldb_find_or_add_value(module, msg2, "objectclass", "user", "user")) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -633,7 +653,7 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
- if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, name)) {
+ if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", name)) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index 68e3c116fc..3d5f816fe8 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -2,6 +2,7 @@
ldb database library
Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Simo Sorce 2005-2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
@@ -251,6 +252,7 @@ int ldb_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type typ
return handle->module->ops->async_wait(handle, type);
}
+
/*
check for an error return from an op
if an op fails, but has not setup an error string, then setup one now
@@ -272,6 +274,7 @@ static int ldb_op_finish(struct ldb_context *ldb, int status)
/*
start an ldb request
autostarts a transacion if none active and the operation is not a search
+ does not work for ASYNC operations
NOTE: the request must be a talloc context.
returns LDB_ERR_* on errors.
*/
@@ -285,7 +288,7 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
req->op.search.res = NULL;
}
- /* start a transaction if needed */
+ /* start a transaction if not async and not search */
if ((!ldb->transaction_active) &&
(req->operation == LDB_REQ_ADD ||
req->operation == LDB_REQ_MODIFY ||
@@ -317,6 +320,71 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
Use talloc_free to free the ldb_message returned in 'res', if successful
*/
+static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
+{
+ struct ldb_result *res;
+ int n;
+
+ if (!context) {
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context in callback"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ res = *((struct ldb_result **)context);
+
+ if (!res || !ares) {
+ goto error;
+ }
+
+ if (ares->type == LDB_REPLY_ENTRY) {
+ res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2);
+ if (! res->msgs) {
+ goto error;
+ }
+
+ res->msgs[res->count + 1] = NULL;
+
+ res->msgs[res->count] = talloc_steal(res->msgs, ares->message);
+ if (! res->msgs[res->count]) {
+ goto error;
+ }
+
+ res->count++;
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ if (res->refs) {
+ for (n = 0; res->refs[n]; n++) /*noop*/ ;
+ } else {
+ n = 0;
+ }
+
+ res->refs = talloc_realloc(res, res->refs, char *, n + 2);
+ if (! res->refs) {
+ goto error;
+ }
+
+ res->refs[n] = talloc_steal(res->refs, ares->referral);
+ res->refs[n + 1] = NULL;
+ }
+
+ if (ares->controls) {
+ res->controls = talloc_steal(res, ares->controls);
+ if (! res->controls) {
+ goto error;
+ }
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+
+error:
+ talloc_free(ares);
+ talloc_free(res);
+ *((struct ldb_result **)context) = NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
int ldb_search(struct ldb_context *ldb,
const struct ldb_dn *base,
enum ldb_scope scope,
@@ -327,7 +395,10 @@ int ldb_search(struct ldb_context *ldb,
struct ldb_request *req;
int ret;
- (*res) = NULL;
+ *res = talloc_zero(ldb, struct ldb_result);
+ if (! *res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
req = talloc(ldb, struct ldb_request);
if (req == NULL) {
@@ -335,7 +406,7 @@ int ldb_search(struct ldb_context *ldb,
return LDB_ERR_OPERATIONS_ERROR;
}
- req->operation = LDB_REQ_SEARCH;
+ req->operation = LDB_ASYNC_SEARCH;
req->op.search.base = base;
req->op.search.scope = scope;
@@ -348,16 +419,53 @@ int ldb_search(struct ldb_context *ldb,
req->op.search.attrs = attrs;
req->controls = NULL;
+ req->creds = NULL;
+ req->async.context = res;
+ req->async.callback = ldb_search_callback;
+ req->async.timeout = 600; /* 10 minutes */
ret = ldb_request(ldb, req);
if (ret == LDB_SUCCESS) {
- (*res) = talloc_steal(ldb, req->op.search.res);
+ ret = ldb_async_wait(req->async.handle, LDB_WAIT_ALL);
}
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(*res);
+ *res = NULL;
+ }
+
talloc_free(req);
return ret;
}
+static int ldb_autotransaction_request(struct ldb_context *ldb, struct ldb_request *req)
+{
+ int ret, close_transaction;
+
+ close_transaction = 0;
+ if (!ldb->transaction_active) {
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ close_transaction = 1;
+ }
+
+ ret = ldb_request(ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_async_wait(req->async.handle, LDB_WAIT_ALL);
+ }
+
+ if (close_transaction) {
+ return ldb_op_finish(ldb, ret);
+ }
+
+ return ret;
+}
+
+
/*
add a record to the database. Will fail if a record with the given class and key
already exists
@@ -377,11 +485,16 @@ int ldb_add(struct ldb_context *ldb,
return LDB_ERR_OPERATIONS_ERROR;
}
- req->operation = LDB_REQ_ADD;
+ req->operation = LDB_ASYNC_ADD;
req->op.add.message = message;
req->controls = NULL;
+ req->creds = NULL;
+ req->async.context = NULL;
+ req->async.callback = NULL;
+ req->async.timeout = 600; /* 10 minutes */
- ret = ldb_request(ldb, req);
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
talloc_free(req);
return ret;
@@ -405,11 +518,16 @@ int ldb_modify(struct ldb_context *ldb,
return LDB_ERR_OPERATIONS_ERROR;
}
- req->operation = LDB_REQ_MODIFY;
+ req->operation = LDB_ASYNC_MODIFY;
req->op.add.message = message;
req->controls = NULL;
+ req->creds = NULL;
+ req->async.context = NULL;
+ req->async.callback = NULL;
+ req->async.timeout = 600; /* 10 minutes */
- ret = ldb_request(ldb, req);
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
talloc_free(req);
return ret;
@@ -430,11 +548,16 @@ int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn)
return LDB_ERR_OPERATIONS_ERROR;
}
- req->operation = LDB_REQ_DELETE;
+ req->operation = LDB_ASYNC_DELETE;
req->op.del.dn = dn;
req->controls = NULL;
+ req->creds = NULL;
+ req->async.context = NULL;
+ req->async.callback = NULL;
+ req->async.timeout = 600; /* 10 minutes */
- ret = ldb_request(ldb, req);
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
talloc_free(req);
return ret;
@@ -454,12 +577,17 @@ int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct
return LDB_ERR_OPERATIONS_ERROR;
}
- req->operation = LDB_REQ_RENAME;
+ req->operation = LDB_ASYNC_RENAME;
req->op.rename.olddn = olddn;
req->op.rename.newdn = newdn;
req->controls = NULL;
+ req->creds = NULL;
+ req->async.context = NULL;
+ req->async.callback = NULL;
+ req->async.timeout = 600; /* 10 minutes */
- ret = ldb_request(ldb, req);
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
talloc_free(req);
return ret;
diff --git a/source4/setup/provision_init.ldif b/source4/setup/provision_init.ldif
index ee09f73340..6698b27e33 100644
--- a/source4/setup/provision_init.ldif
+++ b/source4/setup/provision_init.ldif
@@ -82,8 +82,8 @@ vendorVersion: ${VERSION}
#
# Some Known ordering constraints:
# - rootdse must be first, as it makes redirects from "" -> cn=rootdse
-# - password_hash must be before samldb, or else the template code in samldb breaks setting the pwdLastSet attribute
+# - samldb must be before password_hash, because password_hash checks that the objectclass is of type person (filled in by samldb)
dn: @MODULES
-@LIST: rootdse,kludge_acl,paged_results,server_sort,extended_dn,asq,password_hash,samldb,operational,objectguid,rdn_name,objectclass
+@LIST: rootdse,kludge_acl,paged_results,server_sort,extended_dn,asq,samldb,password_hash,operational,objectguid,rdn_name,objectclass