diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/password_hash.c | 21 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samldb.c | 36 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb.c | 152 | ||||
-rw-r--r-- | source4/setup/provision_init.ldif | 4 |
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 |