diff options
author | Simo Sorce <idra@samba.org> | 2006-01-13 00:38:35 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:50:57 -0500 |
commit | a7a79d2b256c97bd6ffa6e9740d14366ebc7602e (patch) | |
tree | 3b7b912a8ae86a8f0a523fad0f697d6516d30f70 | |
parent | 0ac6b5232d1e52bab55227fc5251b363fd97b333 (diff) | |
download | samba-a7a79d2b256c97bd6ffa6e9740d14366ebc7602e.tar.gz samba-a7a79d2b256c97bd6ffa6e9740d14366ebc7602e.tar.xz samba-a7a79d2b256c97bd6ffa6e9740d14366ebc7602e.zip |
r12880: Remove ldap partitions useless now and probably we
will not use it anyway as we plan to support
partitions in ldb directly like with rootdse
Merge ldap_simple_ldb into ldap_backend, it is
not simple anymore and makes no sense to have
it separated now that ldap partitions are gone
Initial attempt at working to some limit to avoid DOSs
for the ldap server.
Simo.
(This used to be commit 97bff3e049eba48019f2b0f3eb5a19e32fef2e23)
-rw-r--r-- | source4/ldap_server/config.mk | 3 | ||||
-rw-r--r-- | source4/ldap_server/ldap_backend.c | 590 | ||||
-rw-r--r-- | source4/ldap_server/ldap_bind.c | 40 | ||||
-rw-r--r-- | source4/ldap_server/ldap_server.c | 43 | ||||
-rw-r--r-- | source4/ldap_server/ldap_server.h | 36 | ||||
-rw-r--r-- | source4/ldap_server/ldap_simple_ldb.c | 677 |
6 files changed, 604 insertions, 785 deletions
diff --git a/source4/ldap_server/config.mk b/source4/ldap_server/config.mk index 3bc283e06f1..826597cdcb2 100644 --- a/source4/ldap_server/config.mk +++ b/source4/ldap_server/config.mk @@ -6,8 +6,7 @@ OBJ_FILES = \ ldap_server.o \ ldap_backend.o \ - ldap_bind.o \ - ldap_simple_ldb.o + ldap_bind.o REQUIRED_SUBSYSTEMS = \ LIBCLI_LDAP SAMDB # End SUBSYSTEM SMB diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c index 1e6d05a9bdb..562263371bc 100644 --- a/source4/ldap_server/ldap_backend.c +++ b/source4/ldap_server/ldap_backend.c @@ -22,7 +22,79 @@ #include "ldap_server/ldap_server.h" #include "dlinklist.h" #include "libcli/ldap/ldap.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "dsdb/samdb/samdb.h" + +#define VALID_DN_SYNTAX(dn,i) do {\ + if (!(dn)) {\ + return NT_STATUS_NO_MEMORY;\ + } else if ((dn)->comp_num < (i)) {\ + result = LDAP_INVALID_DN_SYNTAX;\ + errstr = "Invalid DN (" #i " components needed for '" #dn "')";\ + goto reply;\ + }\ +} while(0) + +static int map_ldb_error(struct ldb_context *ldb, int err, const char **errstring) +{ + *errstring = ldb_errstring(ldb); + + /* its 1:1 for now */ + return err; +} + +/* + map controls +*/ +static int get_ldb_controls(void *mem_ctx, struct ldap_Control **controls, struct ldb_control ***lcontrols) +{ + struct ldb_control **lctrl; + int i, l; + + if (controls == NULL || controls[0] == NULL) { + *lcontrols = NULL; + return LDB_SUCCESS; + } + + l = 0; + lctrl = NULL; + *lcontrols = NULL; + + for (i = 0; controls[i] != NULL; i++) { + lctrl = talloc_realloc(mem_ctx, lctrl, struct ldb_control *, l + 2); + if (lctrl == NULL) { + return LDB_ERR_OTHER; + } + lctrl[l] = talloc(lctrl, struct ldb_control); + if (lctrl[l] == NULL) { + return LDB_ERR_OTHER; + } + lctrl[l]->oid = controls[i]->oid; + lctrl[l]->critical = controls[i]->critical; + lctrl[l]->data = controls[i]->value; + l++; + } + lctrl[l] = NULL; + *lcontrols = lctrl; + + return LDB_SUCCESS; +} + +/* + connect to the sam database +*/ +NTSTATUS ldapsrv_backend_Init(struct ldapsrv_connection *conn) +{ + conn->ldb = samdb_connect(conn, conn->session_info); + if (conn->ldb == NULL) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + ldb_set_opaque(conn->ldb, "server_credentials", conn->server_credentials); + + return NT_STATUS_OK; +} struct ldapsrv_reply *ldapsrv_init_reply(struct ldapsrv_call *call, uint8_t type) { @@ -50,11 +122,6 @@ void ldapsrv_queue_reply(struct ldapsrv_call *call, struct ldapsrv_reply *reply) DLIST_ADD_END(call->replies, reply, struct ldapsrv_reply *); } -struct ldapsrv_partition *ldapsrv_get_partition(struct ldapsrv_connection *conn, const char *dn, uint8_t scope) -{ - return conn->default_partition; -} - NTSTATUS ldapsrv_unwilling(struct ldapsrv_call *call, int error) { struct ldapsrv_reply *reply; @@ -83,120 +150,549 @@ NTSTATUS ldapsrv_unwilling(struct ldapsrv_call *call, int error) static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call) { struct ldap_SearchRequest *req = &call->request->r.SearchRequest; - struct ldapsrv_partition *part; + struct ldap_SearchResEntry *ent; + struct ldap_Result *done; + struct ldapsrv_reply *ent_r, *done_r; + void *local_ctx; + struct ldb_context *samdb = call->conn->ldb; + struct ldb_dn *basedn; + struct ldb_result *res = NULL; + struct ldb_request lreq; + enum ldb_scope scope = LDB_SCOPE_DEFAULT; + const char **attrs = NULL; + const char *errstr = NULL; + int success_limit = 1; + int result = LDAP_SUCCESS; + int ldb_ret; + int i, j, y; DEBUG(10, ("SearchRequest")); DEBUGADD(10, (" basedn: %s", req->basedn)); DEBUGADD(10, (" filter: %s\n", ldb_filter_from_tree(call, req->tree))); - part = ldapsrv_get_partition(call->conn, req->basedn, req->scope); + local_ctx = talloc_named(call, 0, "sldb_Search local memory context"); + NT_STATUS_HAVE_NO_MEMORY(local_ctx); + + basedn = ldb_dn_explode(local_ctx, req->basedn); + VALID_DN_SYNTAX(basedn, 0); + + DEBUG(10, ("SearchRequest: basedn: [%s]\n", req->basedn)); + DEBUG(10, ("SearchRequest: filter: [%s]\n", ldb_filter_from_tree(call, req->tree))); + + switch (req->scope) { + case LDAP_SEARCH_SCOPE_BASE: + DEBUG(10,("SearchRequest: scope: [BASE]\n")); + scope = LDB_SCOPE_BASE; + success_limit = 0; + break; + case LDAP_SEARCH_SCOPE_SINGLE: + DEBUG(10,("SearchRequest: scope: [ONE]\n")); + scope = LDB_SCOPE_ONELEVEL; + success_limit = 0; + break; + case LDAP_SEARCH_SCOPE_SUB: + DEBUG(10,("SearchRequest: scope: [SUB]\n")); + scope = LDB_SCOPE_SUBTREE; + success_limit = 0; + break; + } - if (!part->ops->Search) { - struct ldap_Result *done; - struct ldapsrv_reply *done_r; + if (req->num_attributes >= 1) { + attrs = talloc_array(samdb, const char *, req->num_attributes+1); + NT_STATUS_HAVE_NO_MEMORY(attrs); - done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone); - if (!done_r) { - return NT_STATUS_NO_MEMORY; + for (i=0; i < req->num_attributes; i++) { + DEBUG(10,("SearchRequest: attrs: [%s]\n",req->attributes[i])); + attrs[i] = req->attributes[i]; } + attrs[i] = NULL; + } + + DEBUG(5,("ldb_request dn=%s filter=%s\n", + req->basedn, ldb_filter_from_tree(call, req->tree))); - done = &done_r->msg->r.SearchResultDone; - done->resultcode = 53; - done->dn = NULL; - done->errormessage = NULL; - done->referral = NULL; + ZERO_STRUCT(lreq); + lreq.operation = LDB_REQ_SEARCH; + lreq.op.search.base = basedn; + lreq.op.search.scope = scope; + lreq.op.search.tree = req->tree; + lreq.op.search.attrs = attrs; - ldapsrv_queue_reply(call, done_r); - return NT_STATUS_OK; + ldb_ret = get_ldb_controls(local_ctx, call->request->controls, &lreq.controls); + + if (ldb_ret != LDB_SUCCESS) { + /* get_ldb_controls fails only on a critical internal error or when + * a control is defined as critical but it is not supported + */ + goto reply; } - return part->ops->Search(part, call); + ldb_ret = ldb_request(samdb, &lreq); + + res = talloc_steal(samdb, lreq.op.search.res); + + if (ldb_ret == LDB_SUCCESS) { + for (i = 0; i < res->count; i++) { + ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry); + NT_STATUS_HAVE_NO_MEMORY(ent_r); + + ent = &ent_r->msg->r.SearchResultEntry; + ent->dn = ldb_dn_linearize(ent_r, res->msgs[i]->dn); + ent->num_attributes = 0; + ent->attributes = NULL; + if (res->msgs[i]->num_elements == 0) { + goto queue_reply; + } + ent->num_attributes = res->msgs[i]->num_elements; + ent->attributes = talloc_array(ent_r, struct ldb_message_element, ent->num_attributes); + NT_STATUS_HAVE_NO_MEMORY(ent->attributes); + for (j=0; j < ent->num_attributes; j++) { + ent->attributes[j].name = talloc_steal(ent->attributes, res->msgs[i]->elements[j].name); + ent->attributes[j].num_values = 0; + ent->attributes[j].values = NULL; + if (req->attributesonly && (res->msgs[i]->elements[j].num_values == 0)) { + continue; + } + ent->attributes[j].num_values = res->msgs[i]->elements[j].num_values; + ent->attributes[j].values = talloc_array(ent->attributes, + DATA_BLOB, ent->attributes[j].num_values); + NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values); + for (y=0; y < ent->attributes[j].num_values; y++) { + ent->attributes[j].values[y].length = res->msgs[i]->elements[j].values[y].length; + ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values, + res->msgs[i]->elements[j].values[y].data); + } + } +queue_reply: + ldapsrv_queue_reply(call, ent_r); + } + } + +reply: + done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone); + NT_STATUS_HAVE_NO_MEMORY(done_r); + + done = &done_r->msg->r.SearchResultDone; + done->dn = NULL; + done->referral = NULL; + + if (ldb_ret == LDB_SUCCESS) { + if (res->count >= success_limit) { + DEBUG(10,("SearchRequest: results: [%d]\n", res->count)); + result = LDAP_SUCCESS; + errstr = NULL; + } else if (res->count == 0) { + DEBUG(10,("SearchRequest: no results\n")); + result = LDAP_NO_SUCH_OBJECT; + errstr = ldb_errstring(samdb); + } + if (res->controls) { + done_r->msg->controls = (struct ldap_Control **)(res->controls); + } + } else { + DEBUG(10,("SearchRequest: error\n")); + result = map_ldb_error(samdb, ldb_ret, &errstr); + } + + done->resultcode = result; + done->errormessage = (errstr?talloc_strdup(done_r, errstr):NULL); + + talloc_free(local_ctx); + + ldapsrv_queue_reply(call, done_r); + return NT_STATUS_OK; } static NTSTATUS ldapsrv_ModifyRequest(struct ldapsrv_call *call) { struct ldap_ModifyRequest *req = &call->request->r.ModifyRequest; - struct ldapsrv_partition *part; + struct ldap_Result *modify_result; + struct ldapsrv_reply *modify_reply; + void *local_ctx; + struct ldb_context *samdb = call->conn->ldb; + struct ldb_message *msg = NULL; + struct ldb_dn *dn; + const char *errstr = NULL; + int result = LDAP_SUCCESS; + int ldb_ret; + int i,j; DEBUG(10, ("ModifyRequest")); DEBUGADD(10, (" dn: %s", req->dn)); - part = ldapsrv_get_partition(call->conn, req->dn, LDAP_SEARCH_SCOPE_SUB); + local_ctx = talloc_named(call, 0, "ModifyRequest local memory context"); + NT_STATUS_HAVE_NO_MEMORY(local_ctx); + + dn = ldb_dn_explode(local_ctx, req->dn); + VALID_DN_SYNTAX(dn, 1); + + DEBUG(10, ("ModifyRequest: dn: [%s]\n", req->dn)); + + msg = talloc(local_ctx, struct ldb_message); + NT_STATUS_HAVE_NO_MEMORY(msg); + + msg->dn = dn; + msg->private_data = NULL; + msg->num_elements = 0; + msg->elements = NULL; + + if (req->num_mods > 0) { + msg->num_elements = req->num_mods; + msg->elements = talloc_array(msg, struct ldb_message_element, req->num_mods); + NT_STATUS_HAVE_NO_MEMORY(msg->elements); + + for (i=0; i < msg->num_elements; i++) { + msg->elements[i].name = discard_const_p(char, req->mods[i].attrib.name); + msg->elements[i].num_values = 0; + msg->elements[i].values = NULL; + + switch (req->mods[i].type) { + default: + result = LDAP_PROTOCOL_ERROR; + errstr = "Invalid LDAP_MODIFY_* type"; + goto reply; + case LDAP_MODIFY_ADD: + msg->elements[i].flags = LDB_FLAG_MOD_ADD; + break; + case LDAP_MODIFY_DELETE: + msg->elements[i].flags = LDB_FLAG_MOD_DELETE; + break; + case LDAP_MODIFY_REPLACE: + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + break; + } + + msg->elements[i].num_values = req->mods[i].attrib.num_values; + if (msg->elements[i].num_values > 0) { + msg->elements[i].values = talloc_array(msg, struct ldb_val, msg->elements[i].num_values); + NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values); + + for (j=0; j < msg->elements[i].num_values; j++) { + if (!(req->mods[i].attrib.values[j].length > 0)) { + result = LDAP_OTHER; + errstr = "Empty attribute values are not allowed"; + goto reply; + } + msg->elements[i].values[j].length = req->mods[i].attrib.values[j].length; + msg->elements[i].values[j].data = req->mods[i].attrib.values[j].data; + } + } + } + } else { + result = LDAP_OTHER; + errstr = "No mods are not allowed"; + goto reply; + } + +reply: + modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse); + NT_STATUS_HAVE_NO_MEMORY(modify_reply); - if (!part->ops->Modify) { - return ldapsrv_unwilling(call, 53); + if (result == LDAP_SUCCESS) { + ldb_ret = ldb_modify(samdb, msg); + result = map_ldb_error(samdb, ldb_ret, &errstr); } - return part->ops->Modify(part, call); + modify_result = &modify_reply->msg->r.AddResponse; + modify_result->dn = NULL; + modify_result->resultcode = result; + modify_result->errormessage = (errstr?talloc_strdup(modify_reply, errstr):NULL); + modify_result->referral = NULL; + + talloc_free(local_ctx); + + ldapsrv_queue_reply(call, modify_reply); + return NT_STATUS_OK; + } static NTSTATUS ldapsrv_AddRequest(struct ldapsrv_call *call) { struct ldap_AddRequest *req = &call->request->r.AddRequest; - struct ldapsrv_partition *part; + struct ldap_Result *add_result; + struct ldapsrv_reply *add_reply; + void *local_ctx; + struct ldb_context *samdb = call->conn->ldb; + struct ldb_message *msg = NULL; + struct ldb_dn *dn; + const char *errstr = NULL; + int result = LDAP_SUCCESS; + int ldb_ret; + int i,j; DEBUG(10, ("AddRequest")); DEBUGADD(10, (" dn: %s", req->dn)); - part = ldapsrv_get_partition(call->conn, req->dn, LDAP_SEARCH_SCOPE_SUB); + local_ctx = talloc_named(call, 0, "AddRequest local memory context"); + NT_STATUS_HAVE_NO_MEMORY(local_ctx); + + dn = ldb_dn_explode(local_ctx, req->dn); + VALID_DN_SYNTAX(dn,1); + + DEBUG(10, ("AddRequest: dn: [%s]\n", req->dn)); + + msg = talloc(local_ctx, struct ldb_message); + NT_STATUS_HAVE_NO_MEMORY(msg); + + msg->dn = dn; + msg->private_data = NULL; + msg->num_elements = 0; + msg->elements = NULL; + + if (req->num_attributes > 0) { + msg->num_elements = req->num_attributes; + msg->elements = talloc_array(msg, struct ldb_message_element, msg->num_elements); + NT_STATUS_HAVE_NO_MEMORY(msg->elements); + + for (i=0; i < msg->num_elements; i++) { + msg->elements[i].name = discard_const_p(char, req->attributes[i].name); + msg->elements[i].flags = 0; + msg->elements[i].num_values = 0; + msg->elements[i].values = NULL; + + if (req->attributes[i].num_values > 0) { + msg->elements[i].num_values = req->attributes[i].num_values; + msg->elements[i].values = talloc_array(msg, struct ldb_val, msg->elements[i].num_values); + NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values); + + for (j=0; j < msg->elements[i].num_values; j++) { + if (!(req->attributes[i].values[j].length > 0)) { + result = LDAP_OTHER; + errstr = "Empty attribute values are not allowed"; + goto reply; + } + msg->elements[i].values[j].length = req->attributes[i].values[j].length; + msg->elements[i].values[j].data = req->attributes[i].values[j].data; + } + } else { + result = LDAP_OTHER; + errstr = "No attribute values are not allowed"; + goto reply; + } + } + } else { + result = LDAP_OTHER; + errstr = "No attributes are not allowed"; + goto reply; + } + +reply: + add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse); + NT_STATUS_HAVE_NO_MEMORY(add_reply); - if (!part->ops->Add) { - return ldapsrv_unwilling(call, 53); + if (result == LDAP_SUCCESS) { + ldb_ret = ldb_add(samdb, msg); + result = map_ldb_error(samdb, ldb_ret, &errstr); } - return part->ops->Add(part, call); + add_result = &add_reply->msg->r.AddResponse; + add_result->dn = NULL; + add_result->resultcode = result; + add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL); + add_result->referral = NULL; + + talloc_free(local_ctx); + + ldapsrv_queue_reply(call, add_reply); + return NT_STATUS_OK; + } static NTSTATUS ldapsrv_DelRequest(struct ldapsrv_call *call) { struct ldap_DelRequest *req = &call->request->r.DelRequest; - struct ldapsrv_partition *part; + struct ldap_Result *del_result; + struct ldapsrv_reply *del_reply; + void *local_ctx; + struct ldb_context *samdb = call->conn->ldb; + struct ldb_dn *dn; + const char *errstr = NULL; + int result = LDAP_SUCCESS; + int ldb_ret; DEBUG(10, ("DelRequest")); DEBUGADD(10, (" dn: %s", req->dn)); - part = ldapsrv_get_partition(call->conn, req->dn, LDAP_SEARCH_SCOPE_SUB); + local_ctx = talloc_named(call, 0, "DelRequest local memory context"); + NT_STATUS_HAVE_NO_MEMORY(local_ctx); + + dn = ldb_dn_explode(local_ctx, req->dn); + VALID_DN_SYNTAX(dn,1); + + DEBUG(10, ("DelRequest: dn: [%s]\n", req->dn)); - if (!part->ops->Del) { - return ldapsrv_unwilling(call, 53); +reply: + del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse); + NT_STATUS_HAVE_NO_MEMORY(del_reply); + + if (result == LDAP_SUCCESS) { + ldb_ret = ldb_delete(samdb, dn); + result = map_ldb_error(samdb, ldb_ret, &errstr); } - return part->ops->Del(part, call); + del_result = &del_reply->msg->r.DelResponse; + del_result->dn = NULL; + del_result->resultcode = result; + del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL); + del_result->referral = NULL; + + talloc_free(local_ctx); + + ldapsrv_queue_reply(call, del_reply); + return NT_STATUS_OK; } static NTSTATUS ldapsrv_ModifyDNRequest(struct ldapsrv_call *call) { struct ldap_ModifyDNRequest *req = &call->request->r.ModifyDNRequest; - struct ldapsrv_partition *part; + struct ldap_Result *modifydn; + struct ldapsrv_reply *modifydn_r; + void *local_ctx; + struct ldb_context *samdb = call->conn->ldb; + struct ldb_dn *olddn, *newdn, *newrdn; + struct ldb_dn *parentdn = NULL; + const char *errstr = NULL; + int result = LDAP_SUCCESS; + int ldb_ret; DEBUG(10, ("ModifyDNRequrest")); DEBUGADD(10, (" dn: %s", req->dn)); DEBUGADD(10, (" newrdn: %s", req->newrdn)); - part = ldapsrv_get_partition(call->conn, req->dn, LDAP_SEARCH_SCOPE_SUB); + local_ctx = talloc_named(call, 0, "ModifyDNRequest local memory context"); + NT_STATUS_HAVE_NO_MEMORY(local_ctx); + + olddn = ldb_dn_explode(local_ctx, req->dn); + VALID_DN_SYNTAX(olddn, 2); + + newrdn = ldb_dn_explode(local_ctx, req->newrdn); + VALID_DN_SYNTAX(newrdn, 1); + + DEBUG(10, ("ModifyDNRequest: olddn: [%s]\n", req->dn)); + DEBUG(10, ("ModifyDNRequest: newrdn: [%s]\n", req->newrdn)); - if (!part->ops->ModifyDN) { - return ldapsrv_unwilling(call, 53); + /* we can't handle the rename if we should not remove the old dn */ + if (!req->deleteolddn) { + result = LDAP_UNWILLING_TO_PERFORM; + errstr = "Old RDN must be deleted"; + goto reply; } - return part->ops->ModifyDN(part, call); + if (newrdn->comp_num > 1) { + result = LDAP_NAMING_VIOLATION; + errstr = "Error new RDN invalid"; + goto reply; + } + + if (req->newsuperior) { + parentdn = ldb_dn_explode(local_ctx, req->newsuperior); + VALID_DN_SYNTAX(parentdn, 0); + DEBUG(10, ("ModifyDNRequest: newsuperior: [%s]\n", req->newsuperior)); + + if (parentdn->comp_num < 1) { + result = LDAP_AFFECTS_MULTIPLE_DSAS; + errstr = "Error new Superior DN invalid"; + goto reply; + } + } + + if (!parentdn) { + parentdn = ldb_dn_get_parent(local_ctx, olddn); + NT_STATUS_HAVE_NO_MEMORY(parentdn); + } + + newdn = ldb_dn_make_child(local_ctx, ldb_dn_get_rdn(local_ctx, newrdn), parentdn); + NT_STATUS_HAVE_NO_MEMORY(newdn); + +reply: + modifydn_r = ldapsrv_init_reply(call, LDAP_TAG_ModifyDNResponse); + NT_STATUS_HAVE_NO_MEMORY(modifydn_r); + + if (result == LDAP_SUCCESS) { + ldb_ret = ldb_rename(samdb, olddn, newdn); + result = map_ldb_error(samdb, ldb_ret, &errstr); + } + + modifydn = &modifydn_r->msg->r.ModifyDNResponse; + modifydn->dn = NULL; + modifydn->resultcode = result; + modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL); + modifydn->referral = NULL; + + talloc_free(local_ctx); + + ldapsrv_queue_reply(call, modifydn_r); + return NT_STATUS_OK; } static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call) { struct ldap_CompareRequest *req = &call->request->r.CompareRequest; - struct ldapsrv_partition *part; + struct ldap_Result *compare; + struct ldapsrv_reply *compare_r; + void *local_ctx; + struct ldb_context *samdb = call->conn->ldb; + struct ldb_result *res = NULL; + struct ldb_dn *dn; + const char *attrs[1]; + const char *errstr = NULL; + const char *filter = NULL; + int result = LDAP_SUCCESS; + int ldb_ret; DEBUG(10, ("CompareRequest")); DEBUGADD(10, (" dn: %s", req->dn)); - part = ldapsrv_get_partition(call->conn, req->dn, LDAP_SEARCH_SCOPE_SUB); - - if (!part->ops->Compare) { - return ldapsrv_unwilling(call, 53); + local_ctx = talloc_named(call, 0, "CompareRequest local_memory_context"); + NT_STATUS_HAVE_NO_MEMORY(local_ctx); + + dn = ldb_dn_explode(local_ctx, req->dn); + VALID_DN_SYNTAX(dn, 1); + + DEBUG(10, ("CompareRequest: dn: [%s]\n", req->dn)); + filter = talloc_asprintf(local_ctx, "(%s=%*s)", req->attribute, + (int)req->value.length, req->value.data); + NT_STATUS_HAVE_NO_MEMORY(filter); + + DEBUGADD(10, ("CompareRequest: attribute: [%s]\n", filter)); + + attrs[0] = NULL; + +reply: + compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse); + NT_STATUS_HAVE_NO_MEMORY(compare_r); + + if (result == LDAP_SUCCESS) { + ldb_ret = ldb_search(samdb, dn, LDB_SCOPE_BASE, filter, attrs, &res); + talloc_steal(samdb, res); + if (ldb_ret != LDB_SUCCESS) { + result = map_ldb_error(samdb, ldb_ret, &errstr); + DEBUG(10,("CompareRequest: error: %s\n", errstr)); + } else if (res->count == 0) { + DEBUG(10,("CompareRequest: doesn't matched\n")); + result = LDAP_COMPARE_FALSE; + errstr = NULL; + } else if (res->count == 1) { + DEBUG(10,("CompareRequest: matched\n")); + result = LDAP_COMPARE_TRUE; + errstr = NULL; + } else if (res->count > 1) { + result = LDAP_OTHER; + errstr = "too many objects match"; + DEBUG(10,("CompareRequest: %d results: %s\n", res->count, errstr)); + } } - return part->ops->Compare(part, call); + compare = &compare_r->msg->r.CompareResponse; + compare->dn = NULL; + compare->resultcode = result; + compare->errormessage = (errstr?talloc_strdup(compare_r,errstr):NULL); + compare->referral = NULL; + + talloc_free(local_ctx); + + ldapsrv_queue_reply(call, compare_r); + return NT_STATUS_OK; } static NTSTATUS ldapsrv_AbandonRequest(struct ldapsrv_call *call) diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c index 0f24ad9a042..cfd70d30d39 100644 --- a/source4/ldap_server/ldap_bind.c +++ b/source4/ldap_server/ldap_bind.c @@ -23,6 +23,8 @@ #include "auth/auth.h" #include "libcli/ldap/ldap.h" #include "smbd/service_stream.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" #include "dsdb/samdb/samdb.h" static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call) @@ -55,21 +57,20 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call) } if (NT_STATUS_IS_OK(status)) { - struct ldapsrv_partition *part; result = LDAP_SUCCESS; errstr = NULL; talloc_free(call->conn->session_info); call->conn->session_info = session_info; - for (part = call->conn->partitions; part; part = part->next) { - if (!part->ops->Bind) { - continue; - } - status = part->ops->Bind(part, call->conn); - if (!NT_STATUS_IS_OK(status)) { - result = LDAP_OPERATIONS_ERROR; - errstr = talloc_asprintf(reply, "Simple Bind: Failed to advise partition %s of new credentials: %s", part->base_dn, nt_errstr(status)); - } + + /* don't leak the old LDB */ + talloc_free(call->conn->ldb); + + status = ldapsrv_backend_Init(call->conn); + + if (!NT_STATUS_IS_OK(status)) { + result = LDAP_OPERATIONS_ERROR; + errstr = talloc_asprintf(reply, "Simple Bind: Failed to advise ldb new credentials: %s", nt_errstr(status)); } } else { status = auth_nt_status_squash(status); @@ -145,7 +146,6 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call) result = LDAP_SASL_BIND_IN_PROGRESS; errstr = NULL; } else if (NT_STATUS_IS_OK(status)) { - struct ldapsrv_partition *part; struct auth_session_info *old_session_info; result = LDAP_SUCCESS; @@ -163,15 +163,15 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call) errstr = talloc_asprintf(reply, "SASL:[%s]: Failed to get session info: %s", req->creds.SASL.mechanism, nt_errstr(status)); } else { talloc_free(old_session_info); - for (part = call->conn->partitions; part; part = part->next) { - if (!part->ops->Bind) { - continue; - } - status = part->ops->Bind(part, conn); - if (!NT_STATUS_IS_OK(status)) { - result = LDAP_OPERATIONS_ERROR; - errstr = talloc_asprintf(reply, "SASL:[%s]: Failed to advise partition %s of new credentials: %s", req->creds.SASL.mechanism, part->base_dn, nt_errstr(status)); - } + + /* don't leak the old LDB */ + talloc_free(call->conn->ldb); + + status = ldapsrv_backend_Init(call->conn); + + if (!NT_STATUS_IS_OK(status)) { + result = LDAP_OPERATIONS_ERROR; + errstr = talloc_asprintf(reply, "SASL:[%s]: Failed to advise samdb of new credentials: %s", req->creds.SASL.mechanism, nt_errstr(status)); } } } else { diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c index 28995f6eb2d..d8124e5f243 100644 --- a/source4/ldap_server/ldap_server.c +++ b/source4/ldap_server/ldap_server.c @@ -228,7 +228,12 @@ static void ldapsrv_recv(struct stream_connection *c, uint16_t flags) { struct ldapsrv_connection *conn = talloc_get_type(c->private, struct ldapsrv_connection); - + + if (conn->limits.ite) { + talloc_free(conn->limits.ite); + conn->limits.ite = NULL; + } + packet_recv(conn->packet); } @@ -257,13 +262,22 @@ static void ldapsrv_send(struct stream_connection *c, uint16_t flags) packet_queue_run(conn->packet); } +static void ldapsrv_conn_init_timeout(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private) +{ + struct ldapsrv_connection *conn = talloc_get_type(private, struct ldapsrv_connection); + + ldapsrv_terminate_connection(conn, "Timeout. No requests after initial connection"); +} + /* initialise a server_context from a open socket and register a event handler for reading from that socket */ static void ldapsrv_accept(struct stream_connection *c) { - struct ldapsrv_partition *part; struct ldapsrv_service *ldapsrv_service = talloc_get_type(c->private, struct ldapsrv_service); struct ldapsrv_connection *conn; @@ -337,23 +351,26 @@ static void ldapsrv_accept(struct stream_connection *c) return; } - part = talloc(conn, struct ldapsrv_partition); - if (part == NULL) { - ldapsrv_terminate_connection(conn, "talloc failed"); + if (!NT_STATUS_IS_OK(ldapsrv_backend_Init(conn))) { + ldapsrv_terminate_connection(conn, "backend Init failed"); return; } - part->base_dn = "*"; /* default partition */ - part->ops = ldapsrv_get_sldb_partition_ops(); - if (!NT_STATUS_IS_OK(part->ops->Init(part, conn))) { - ldapsrv_terminate_connection(conn, "default partition Init failed"); - return; - } + /* TODO: load limits from the conf partition */ + + conn->limits.initial_timeout = 10; + conn->limits.conn_idle_time = 60; + conn->limits.max_page_size = 100; + conn->limits.search_timeout = 10; - conn->default_partition = part; - DLIST_ADD_END(conn->partitions, part, struct ldapsrv_partition *); + /* register the server */ irpc_add_name(c->msg_ctx, "ldap_server"); + + /* set connections limits */ + conn->limits.ite = event_add_timed(c->event.ctx, conn, + timeval_current_ofs(conn->limits.initial_timeout, 0), + ldapsrv_conn_init_timeout, conn); } static const struct stream_server_ops ldap_stream_ops = { diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h index 267b6fb9a7e..1341b22948c 100644 --- a/source4/ldap_server/ldap_server.h +++ b/source4/ldap_server/ldap_server.h @@ -27,14 +27,22 @@ struct ldapsrv_connection { struct auth_session_info *session_info; struct ldapsrv_service *service; struct tls_context *tls; - struct ldapsrv_partition *default_partition; - struct ldapsrv_partition *partitions; struct cli_credentials *server_credentials; + struct ldb_context *ldb; /* are we using gensec wrapping? */ BOOL enable_wrap; struct packet_context *packet; + + struct { + int initial_timeout; + int conn_idle_time; + int max_page_size; + int search_timeout; + + struct timed_event *ite; + } limits; }; struct ldapsrv_call { @@ -47,30 +55,6 @@ struct ldapsrv_call { }; struct ldapsrv_service; -struct ldapsrv_partition; - -struct ldapsrv_partition_ops { - const char *name; - NTSTATUS (*Init)(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn); - NTSTATUS (*Bind)(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn); - NTSTATUS (*Search)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*Modify)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*Add)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*Del)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*ModifyDN)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*Compare)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*Abandon)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); - NTSTATUS (*Extended)(struct ldapsrv_partition *partition, struct ldapsrv_call *call); -}; - -struct ldapsrv_partition { - struct ldapsrv_partition *prev,*next; - - void *private; - const struct ldapsrv_partition_ops *ops; - - const char *base_dn; -}; struct ldapsrv_service { struct tls_params *tls_params; diff --git a/source4/ldap_server/ldap_simple_ldb.c b/source4/ldap_server/ldap_simple_ldb.c deleted file mode 100644 index fd89a197373..00000000000 --- a/source4/ldap_server/ldap_simple_ldb.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - Unix SMB/CIFS implementation. - LDAP server SIMPLE LDB implementation - Copyright (C) Stefan Metzmacher 2004 - Copyright (C) Simo Sorce 2004 - - 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 - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - 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. -*/ - -#include "includes.h" -#include "ldap_server/ldap_server.h" -#include "lib/ldb/include/ldb.h" -#include "lib/ldb/include/ldb_errors.h" -#include "dsdb/samdb/samdb.h" - -#define VALID_DN_SYNTAX(dn,i) do {\ - if (!(dn)) {\ - return NT_STATUS_NO_MEMORY;\ - } else if ((dn)->comp_num < (i)) {\ - result = LDAP_INVALID_DN_SYNTAX;\ - errstr = "Invalid DN (" #i " components needed for '" #dn "')";\ - goto reply;\ - }\ -} while(0) - - -/* - map an error code from ldb to ldap -*/ -static int sldb_map_error(struct ldapsrv_partition *partition, int ldb_ret, - const char **errstr) -{ - struct ldb_context *samdb = talloc_get_type(partition->private, - struct ldb_context); - *errstr = ldb_errstring(samdb); - - /* its 1:1 for now */ - return ldb_ret; -} - -static int sldb_get_ldb_controls(void *mem_ctx, struct ldap_Control **controls, struct ldb_control ***lcontrols) -{ - struct ldb_control **lctrl; - int i, l; - - if (controls == NULL || controls[0] == NULL) { - *lcontrols = NULL; - return LDB_SUCCESS; - } - - l = 0; - lctrl = NULL; - *lcontrols = NULL; - - for (i = 0; controls[i] != NULL; i++) { - lctrl = talloc_realloc(mem_ctx, lctrl, struct ldb_control *, l + 2); - if (lctrl == NULL) { - return LDB_ERR_OTHER; - } - lctrl[l] = talloc(lctrl, struct ldb_control); - if (lctrl[l] == NULL) { - return LDB_ERR_OTHER; - } - lctrl[l]->oid = controls[i]->oid; - lctrl[l]->critical = controls[i]->critical; - lctrl[l]->data = controls[i]->value; - l++; - } - lctrl[l] = NULL; - - *lcontrols = lctrl; - - return LDB_SUCCESS; -} - -/* - connect to the sam database -*/ -NTSTATUS sldb_Init(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn) -{ - TALLOC_CTX *mem_ctx = talloc_new(partition); - struct ldb_context *ldb; - ldb = samdb_connect(mem_ctx, conn->session_info); - if (ldb == NULL) { - talloc_free(mem_ctx); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - talloc_steal(partition, ldb); - partition->private = ldb; - talloc_free(mem_ctx); - - ldb_set_opaque(ldb, "server_credentials", conn->server_credentials); - - return NT_STATUS_OK; -} - -/* - Re-connect to the ldb after a bind (this does not handle the bind - itself, but just notes the change in credentials) -*/ -NTSTATUS sldb_Bind(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn) -{ - struct ldb_context *samdb = partition->private; - NTSTATUS status; - status = sldb_Init(partition, conn); - if (NT_STATUS_IS_OK(status)) { - /* don't leak the old LDB */ - talloc_free(samdb); - } - return status; -} - -static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call) -{ - struct ldap_SearchRequest *r = &call->request->r.SearchRequest; - void *local_ctx; - struct ldb_dn *basedn; - struct ldap_Result *done; - struct ldap_SearchResEntry *ent; - struct ldapsrv_reply *ent_r, *done_r; - int result = LDAP_SUCCESS; - struct ldb_context *samdb; - struct ldb_result *res = NULL; - int i, j, y, ret; - int success_limit = 1; - enum ldb_scope scope = LDB_SCOPE_DEFAULT; - const char **attrs = NULL; - const char *errstr = NULL; - struct ldb_request lreq; - - local_ctx = talloc_named(call, 0, "sldb_Search local memory context"); - NT_STATUS_HAVE_NO_MEMORY(local_ctx); - - samdb = talloc_get_type(partition->private, struct ldb_context); - - basedn = ldb_dn_explode(local_ctx, r->basedn); - VALID_DN_SYNTAX(basedn, 0); - - DEBUG(10, ("sldb_Search: basedn: [%s]\n", r->basedn)); - DEBUG(10, ("sldb_Search: filter: [%s]\n", ldb_filter_from_tree(call, r->tree))); - - switch (r->scope) { - case LDAP_SEARCH_SCOPE_BASE: - DEBUG(10,("sldb_Search: scope: [BASE]\n")); - scope = LDB_SCOPE_BASE; - success_limit = 0; - break; - case LDAP_SEARCH_SCOPE_SINGLE: - DEBUG(10,("sldb_Search: scope: [ONE]\n")); - scope = LDB_SCOPE_ONELEVEL; - success_limit = 0; - break; - case LDAP_SEARCH_SCOPE_SUB: - DEBUG(10,("sldb_Search: scope: [SUB]\n")); - scope = LDB_SCOPE_SUBTREE; - success_limit = 0; - break; - } - - if (r->num_attributes >= 1) { - attrs = talloc_array(samdb, const char *, r->num_attributes+1); - NT_STATUS_HAVE_NO_MEMORY(attrs); - - for (i=0; i < r->num_attributes; i++) { - DEBUG(10,("sldb_Search: attrs: [%s]\n",r->attributes[i])); - attrs[i] = r->attributes[i]; - } - attrs[i] = NULL; - } - - DEBUG(5,("ldb_request dn=%s filter=%s\n", - r->basedn, ldb_filter_from_tree(call, r->tree))); - - ZERO_STRUCT(lreq); - lreq.operation = LDB_REQ_SEARCH; - lreq.op.search.base = basedn; - lreq.op.search.scope = scope; - lreq.op.search.tree = r->tree; - lreq.op.search.attrs = attrs; - ret = sldb_get_ldb_controls(local_ctx, call->request->controls, &lreq.controls); - - if (ret != LDB_SUCCESS) { - /* get_ldb_controls fails only on a critical internal error or when - * a control is defined as critical but it is not supported - */ - goto reply; - } - - ret = ldb_request(samdb, &lreq); - - res = talloc_steal(samdb, lreq.op.search.res); - - if (ret == LDB_SUCCESS) { - for (i = 0; i < res->count; i++) { - ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry); - NT_STATUS_HAVE_NO_MEMORY(ent_r); - - ent = &ent_r->msg->r.SearchResultEntry; - ent->dn = ldb_dn_linearize(ent_r, res->msgs[i]->dn); - ent->num_attributes = 0; - ent->attributes = NULL; - if (res->msgs[i]->num_elements == 0) { - goto queue_reply; - } - ent->num_attributes = res->msgs[i]->num_elements; - ent->attributes = talloc_array(ent_r, struct ldb_message_element, ent->num_attributes); - NT_STATUS_HAVE_NO_MEMORY(ent->attributes); - for (j=0; j < ent->num_attributes; j++) { - ent->attributes[j].name = talloc_steal(ent->attributes, res->msgs[i]->elements[j].name); - ent->attributes[j].num_values = 0; - ent->attributes[j].values = NULL; - if (r->attributesonly && (res->msgs[i]->elements[j].num_values == 0)) { - continue; - } - ent->attributes[j].num_values = res->msgs[i]->elements[j].num_values; - ent->attributes[j].values = talloc_array(ent->attributes, - DATA_BLOB, ent->attributes[j].num_values); - NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values); - for (y=0; y < ent->attributes[j].num_values; y++) { - ent->attributes[j].values[y].length = res->msgs[i]->elements[j].values[y].length; - ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values, - res->msgs[i]->elements[j].values[y].data); - } - } -queue_reply: - ldapsrv_queue_reply(call, ent_r); - } - } - -reply: - done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone); - NT_STATUS_HAVE_NO_MEMORY(done_r); - - done = &done_r->msg->r.SearchResultDone; - done->dn = NULL; - done->referral = NULL; - - if (ret == LDB_SUCCESS) { - if (res->count >= success_limit) { - DEBUG(10,("sldb_Search: results: [%d]\n", res->count)); - result = LDAP_SUCCESS; - errstr = NULL; - } else if (res->count == 0) { - DEBUG(10,("sldb_Search: no results\n")); - result = LDAP_NO_SUCH_OBJECT; - errstr = ldb_errstring(samdb); - } - if (res->controls) { - done_r->msg->controls = (struct ldap_Control **)(res->controls); - } - } else { - DEBUG(10,("sldb_Search: error\n")); - result = ret; - errstr = ldb_errstring(samdb); - } - - done->resultcode = result; - done->errormessage = (errstr?talloc_strdup(done_r, errstr):NULL); - - talloc_free(local_ctx); - - ldapsrv_queue_reply(call, done_r); - return NT_STATUS_OK; -} - -static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call) -{ - struct ldap_AddRequest *r = &call->request->r.AddRequest; - void *local_ctx; - struct ldb_dn *dn; - struct ldap_Result *add_result; - struct ldapsrv_reply *add_reply; - int ldb_ret; - struct ldb_context *samdb; - struct ldb_message *msg = NULL; - int result = LDAP_SUCCESS; - const char *errstr = NULL; - int i,j; - - local_ctx = talloc_named(call, 0, "sldb_Add local memory context"); - NT_STATUS_HAVE_NO_MEMORY(local_ctx); - - samdb = talloc_get_type(partition->private, struct ldb_context); - - dn = ldb_dn_explode(local_ctx, r->dn); - VALID_DN_SYNTAX(dn,1); - - DEBUG(10, ("sldb_add: dn: [%s]\n", r->dn)); - - msg = talloc(local_ctx, struct ldb_message); - NT_STATUS_HAVE_NO_MEMORY(msg); - - msg->dn = dn; - msg->private_data = NULL; - msg->num_elements = 0; - msg->elements = NULL; - - if (r->num_attributes > 0) { - msg->num_elements = r->num_attributes; - msg->elements = talloc_array(msg, struct ldb_message_element, msg->num_elements); - NT_STATUS_HAVE_NO_MEMORY(msg->elements); - - for (i=0; i < msg->num_elements; i++) { - msg->elements[i].name = discard_const_p(char, r->attributes[i].name); - msg->elements[i].flags = 0; - msg->elements[i].num_values = 0; - msg->elements[i].values = NULL; - - if (r->attributes[i].num_values > 0) { - msg->elements[i].num_values = r->attributes[i].num_values; - msg->elements[i].values = talloc_array(msg, struct ldb_val, msg->elements[i].num_values); - NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values); - - for (j=0; j < msg->elements[i].num_values; j++) { - if (!(r->attributes[i].values[j].length > 0)) { - result = LDAP_OTHER; - errstr = "Empty attribute values are not allowed"; - goto reply; - } - msg->elements[i].values[j].length = r->attributes[i].values[j].length; - msg->elements[i].values[j].data = r->attributes[i].values[j].data; - } - } else { - result = LDAP_OTHER; - errstr = "No attribute values are not allowed"; - goto reply; - } - } - } else { - result = LDAP_OTHER; - errstr = "No attributes are not allowed"; - goto reply; - } - -reply: - add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse); - NT_STATUS_HAVE_NO_MEMORY(add_reply); - - if (result == LDAP_SUCCESS) { - ldb_ret = ldb_add(samdb, msg); - result = sldb_map_error(partition, ldb_ret, &errstr); - } - - add_result = &add_reply->msg->r.AddResponse; - add_result->dn = NULL; - add_result->resultcode = result; - add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL); - add_result->referral = NULL; - - talloc_free(local_ctx); - - ldapsrv_queue_reply(call, add_reply); - return NT_STATUS_OK; -} - -static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call) -{ - struct ldap_DelRequest *r = &call->request->r.DelRequest; - void *local_ctx; - struct ldb_dn *dn; - struct ldap_Result *del_result; - struct ldapsrv_reply *del_reply; - int ldb_ret; - struct ldb_context *samdb; - const char *errstr = NULL; - int result = LDAP_SUCCESS; - - local_ctx = talloc_named(call, 0, "sldb_Del local memory context"); - NT_STATUS_HAVE_NO_MEMORY(local_ctx); - - samdb = talloc_get_type(partition->private, struct ldb_context); - - dn = ldb_dn_explode(local_ctx, r->dn); - VALID_DN_SYNTAX(dn,1); - - DEBUG(10, ("sldb_Del: dn: [%s]\n", r->dn)); - -reply: - del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse); - NT_STATUS_HAVE_NO_MEMORY(del_reply); - - if (result == LDAP_SUCCESS) { - ldb_ret = ldb_delete(samdb, dn); - result = sldb_map_error(partition, ldb_ret, &errstr); - } - - del_result = &del_reply->msg->r.DelResponse; - del_result->dn = NULL; - del_result->resultcode = result; - del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL); - del_result->referral = NULL; - - talloc_free(local_ctx); - - ldapsrv_queue_reply(call, del_reply); - return NT_STATUS_OK; -} - -static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call) -{ - struct ldap_ModifyRequest *r = &call->request->r.ModifyRequest; - void *local_ctx; - struct ldb_dn *dn; - struct ldap_Result *modify_result; - struct ldapsrv_reply *modify_reply; - int ldb_ret; - struct ldb_context *samdb; - struct ldb_message *msg = NULL; - int result = LDAP_SUCCESS; - const char *errstr = NULL; - int i,j; - - local_ctx = talloc_named(call, 0, "sldb_Modify local memory context"); - NT_STATUS_HAVE_NO_MEMORY(local_ctx); - - samdb = talloc_get_type(partition->private, struct ldb_context); - - dn = ldb_dn_explode(local_ctx, r->dn); - VALID_DN_SYNTAX(dn, 1); - - DEBUG(10, ("sldb_modify: dn: [%s]\n", r->dn)); - - msg = talloc(local_ctx, struct ldb_message); - NT_STATUS_HAVE_NO_MEMORY(msg); - - msg->dn = dn; - msg->private_data = NULL; - msg->num_elements = 0; - msg->elements = NULL; - - if (r->num_mods > 0) { - msg->num_elements = r->num_mods; - msg->elements = talloc_array(msg, struct ldb_message_element, r->num_mods); - NT_STATUS_HAVE_NO_MEMORY(msg->elements); - - for (i=0; i < msg->num_elements; i++) { - msg->elements[i].name = discard_const_p(char, r->mods[i].attrib.name); - msg->elements[i].num_values = 0; - msg->elements[i].values = NULL; - - switch (r->mods[i].type) { - default: - result = LDAP_PROTOCOL_ERROR; - errstr = "Invalid LDAP_MODIFY_* type"; - goto reply; - case LDAP_MODIFY_ADD: - msg->elements[i].flags = LDB_FLAG_MOD_ADD; - break; - case LDAP_MODIFY_DELETE: - msg->elements[i].flags = LDB_FLAG_MOD_DELETE; - break; - case LDAP_MODIFY_REPLACE: - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; - break; - } - - msg->elements[i].num_values = r->mods[i].attrib.num_values; - if (msg->elements[i].num_values > 0) { - msg->elements[i].values = talloc_array(msg, struct ldb_val, msg->elements[i].num_values); - NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values); - - for (j=0; j < msg->elements[i].num_values; j++) { - if (!(r->mods[i].attrib.values[j].length > 0)) { - result = LDAP_OTHER; - errstr = "Empty attribute values are not allowed"; - goto reply; - } - msg->elements[i].values[j].length = r->mods[i].attrib.values[j].length; - msg->elements[i].values[j].data = r->mods[i].attrib.values[j].data; - } - } - } - } else { - result = LDAP_OTHER; - errstr = "No mods are not allowed"; - goto reply; - } - -reply: - modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse); - NT_STATUS_HAVE_NO_MEMORY(modify_reply); - - if (result == LDAP_SUCCESS) { - ldb_ret = ldb_modify(samdb, msg); - result = sldb_map_error(partition, ldb_ret, &errstr); - } - - modify_result = &modify_reply->msg->r.AddResponse; - modify_result->dn = NULL; - modify_result->resultcode = result; - modify_result->errormessage = (errstr?talloc_strdup(modify_reply,errstr):NULL); - modify_result->referral = NULL; - - talloc_free(local_ctx); - - ldapsrv_queue_reply(call, modify_reply); - return NT_STATUS_OK; -} - -static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call) -{ - struct ldap_CompareRequest *r = &call->request->r.CompareRequest; - void *local_ctx; - struct ldb_dn *dn; - struct ldap_Result *compare; - struct ldapsrv_reply *compare_r; - int result = LDAP_SUCCESS; - struct ldb_context *samdb; - struct ldb_result *res = NULL; - const char *attrs[1]; - const char *errstr = NULL; - const char *filter = NULL; - int ret; - - local_ctx = talloc_named(call, 0, "sldb_Compare local_memory_context"); - NT_STATUS_HAVE_NO_MEMORY(local_ctx); - - samdb = talloc_get_type(partition->private, struct ldb_context); - - dn = ldb_dn_explode(local_ctx, r->dn); - VALID_DN_SYNTAX(dn, 1); - - DEBUG(10, ("sldb_Compare: dn: [%s]\n", r->dn)); - filter = talloc_asprintf(local_ctx, "(%s=%*s)", r->attribute, - (int)r->value.length, r->value.data); - NT_STATUS_HAVE_NO_MEMORY(filter); - - DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter)); - - attrs[0] = NULL; - -reply: - compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse); - NT_STATUS_HAVE_NO_MEMORY(compare_r); - - if (result == LDAP_SUCCESS) { - ret = ldb_search(samdb, dn, LDB_SCOPE_BASE, filter, attrs, &res); - talloc_steal(samdb, res); - if (ret != LDB_SUCCESS) { - result = LDAP_OTHER; - errstr = ldb_errstring(samdb); - DEBUG(10,("sldb_Compare: error: %s\n", errstr)); - } else if (res->count == 0) { - DEBUG(10,("sldb_Compare: doesn't matched\n")); - result = LDAP_COMPARE_FALSE; - errstr = NULL; - } else if (res->count == 1) { - DEBUG(10,("sldb_Compare: matched\n")); - result = LDAP_COMPARE_TRUE; - errstr = NULL; - } else if (res->count > 1) { - result = LDAP_OTHER; - errstr = "too many objects match"; - DEBUG(10,("sldb_Compare: %d results: %s\n", res->count, errstr)); - } - } - - compare = &compare_r->msg->r.CompareResponse; - compare->dn = NULL; - compare->resultcode = result; - compare->errormessage = (errstr?talloc_strdup(compare_r,errstr):NULL); - compare->referral = NULL; - - talloc_free(local_ctx); - - ldapsrv_queue_reply(call, compare_r); - return NT_STATUS_OK; -} - -static NTSTATUS sldb_ModifyDN(struct ldapsrv_partition *partition, struct ldapsrv_call *call) -{ - struct ldap_ModifyDNRequest *r = &call->request->r.ModifyDNRequest; - void *local_ctx; - struct ldb_dn *olddn, *newdn, *newrdn; - struct ldb_dn *parentdn = NULL; - struct ldap_Result *modifydn; - struct ldapsrv_reply *modifydn_r; - int ldb_ret; - struct ldb_context *samdb; - const char *errstr = NULL; - int result = LDAP_SUCCESS; - - local_ctx = talloc_named(call, 0, "sldb_ModifyDN local memory context"); - NT_STATUS_HAVE_NO_MEMORY(local_ctx); - - samdb = talloc_get_type(partition->private, struct ldb_context); - - olddn = ldb_dn_explode(local_ctx, r->dn); - VALID_DN_SYNTAX(olddn, 2); - - newrdn = ldb_dn_explode(local_ctx, r->newrdn); - VALID_DN_SYNTAX(newrdn, 1); - - DEBUG(10, ("sldb_ModifyDN: olddn: [%s]\n", r->dn)); - DEBUG(10, ("sldb_ModifyDN: newrdn: [%s]\n", r->newrdn)); - - /* we can't handle the rename if we should not remove the old dn */ - if (!r->deleteolddn) { - result = LDAP_UNWILLING_TO_PERFORM; - errstr = "Old RDN must be deleted"; - goto reply; - } - - if (newrdn->comp_num > 1) { - result = LDAP_NAMING_VIOLATION; - errstr = "Error new RDN invalid"; - goto reply; - } - - if (r->newsuperior) { - parentdn = ldb_dn_explode(local_ctx, r->newsuperior); - VALID_DN_SYNTAX(parentdn, 0); - DEBUG(10, ("sldb_ModifyDN: newsuperior: [%s]\n", r->newsuperior)); - - if (parentdn->comp_num < 1) { - result = LDAP_AFFECTS_MULTIPLE_DSAS; - errstr = "Error new Superior DN invalid"; - goto reply; - } - } - - if (!parentdn) { - parentdn = ldb_dn_get_parent(local_ctx, olddn); - NT_STATUS_HAVE_NO_MEMORY(parentdn); - } - - newdn = ldb_dn_make_child(local_ctx, ldb_dn_get_rdn(local_ctx, newrdn), parentdn); - NT_STATUS_HAVE_NO_MEMORY(newdn); - -reply: - modifydn_r = ldapsrv_init_reply(call, LDAP_TAG_ModifyDNResponse); - NT_STATUS_HAVE_NO_MEMORY(modifydn_r); - - if (result == LDAP_SUCCESS) { - ldb_ret = ldb_rename(samdb, olddn, newdn); - result = sldb_map_error(partition, ldb_ret, &errstr); - } - - modifydn = &modifydn_r->msg->r.ModifyDNResponse; - modifydn->dn = NULL; - modifydn->resultcode = result; - modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL); - modifydn->referral = NULL; - - talloc_free(local_ctx); - - ldapsrv_queue_reply(call, modifydn_r); - return NT_STATUS_OK; -} - -static const struct ldapsrv_partition_ops sldb_ops = { - .Init = sldb_Init, - .Bind = sldb_Bind, - .Search = sldb_Search, - .Add = sldb_Add, - .Del = sldb_Del, - .Modify = sldb_Modify, - .Compare = sldb_Compare, - .ModifyDN = sldb_ModifyDN -}; - -const struct ldapsrv_partition_ops *ldapsrv_get_sldb_partition_ops(void) -{ - return &sldb_ops; -} |