1/* 2 Unix SMB/CIFS implementation. 3 4 CLDAP server - rootdse handling 5 6 Copyright (C) Stefan Metzmacher 2006 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include <tevent.h> 24#include "libcli/ldap/ldap.h" 25#include "lib/ldb/include/ldb.h" 26#include "lib/ldb/include/ldb_errors.h" 27#include "smbd/service_task.h" 28#include "cldap_server/cldap_server.h" 29#include "librpc/gen_ndr/ndr_misc.h" 30#include "dsdb/samdb/samdb.h" 31#include "ldb_wrap.h" 32 33static void cldapd_rootdse_fill(struct cldapd_server *cldapd, 34 TALLOC_CTX *mem_ctx, 35 struct ldap_SearchRequest *search, 36 struct ldap_SearchResEntry **response, 37 struct ldap_Result *result) 38{ 39 struct ldap_SearchResEntry *ent = NULL; 40 struct ldb_dn *basedn; 41 struct ldb_result *res = NULL; 42 struct ldb_request *lreq; 43 enum ldb_scope scope = LDB_SCOPE_DEFAULT; 44 const char **attrs = NULL; 45 const char *errstr = NULL; 46 int ret = 0; 47 int ldb_ret = -1; 48 49 basedn = ldb_dn_new(mem_ctx, cldapd->samctx, NULL); 50 if (basedn == NULL) goto nomem; 51 scope = LDB_SCOPE_BASE; 52 53 if (search->num_attributes >= 1) { 54 int i; 55 56 attrs = talloc_array(mem_ctx, const char *, search->num_attributes+1); 57 if (attrs == NULL) goto nomem; 58 59 for (i=0; i < search->num_attributes; i++) { 60 attrs[i] = search->attributes[i]; 61 } 62 attrs[i] = NULL; 63 } 64 65 res = talloc_zero(mem_ctx, struct ldb_result); 66 if (res == NULL) goto nomem; 67 68 ldb_ret = ldb_build_search_req_ex(&lreq, cldapd->samctx, mem_ctx, 69 basedn, scope, 70 search->tree, attrs, 71 NULL, 72 res, ldb_search_default_callback, 73 NULL); 74 75 if (ldb_ret != LDB_SUCCESS) { 76 goto reply; 77 } 78 79 /* Copy the timeout from the incoming call */ 80 ldb_set_timeout(cldapd->samctx, lreq, search->timelimit); 81 82 ldb_ret = ldb_request(cldapd->samctx, lreq); 83 if (ldb_ret != LDB_SUCCESS) { 84 goto reply; 85 } 86 87 ldb_ret = ldb_wait(lreq->handle, LDB_WAIT_ALL); 88 if (ldb_ret != LDB_SUCCESS) { 89 goto reply; 90 } 91 92 if (res->count > 1) { 93 errstr = "Internal error: to much replies"; 94 ldb_ret = LDB_ERR_OTHER; 95 goto reply; 96 } else if (res->count == 1) { 97 int j; 98 99 ent = talloc(mem_ctx, struct ldap_SearchResEntry); 100 if (ent == NULL) goto nomem; 101 102 ent->dn = ldb_dn_alloc_linearized(ent, res->msgs[0]->dn); 103 if (ent->dn == NULL) goto nomem; 104 ent->num_attributes = 0; 105 ent->attributes = NULL; 106 if (res->msgs[0]->num_elements == 0) { 107 goto reply; 108 } 109 ent->num_attributes = res->msgs[0]->num_elements; 110 ent->attributes = talloc_array(ent, struct ldb_message_element, ent->num_attributes); 111 if (ent->attributes == NULL) goto nomem; 112 for (j=0; j < ent->num_attributes; j++) { 113 ent->attributes[j].name = talloc_steal(ent->attributes, res->msgs[0]->elements[j].name); 114 ent->attributes[j].num_values = 0; 115 ent->attributes[j].values = NULL; 116 if (search->attributesonly && (res->msgs[0]->elements[j].num_values == 0)) { 117 continue; 118 } 119 ent->attributes[j].num_values = res->msgs[0]->elements[j].num_values; 120 ent->attributes[j].values = res->msgs[0]->elements[j].values; 121 talloc_steal(ent->attributes, res->msgs[0]->elements[j].values); 122 } 123 } 124 125reply: 126 if (ret) { 127 /* nothing ... */ 128 } else if (ldb_ret == LDB_SUCCESS) { 129 ret = LDAP_SUCCESS; 130 errstr = NULL; 131 } else { 132 ret = ldb_ret; 133 errstr = ldb_errstring(cldapd->samctx); 134 } 135 goto done; 136nomem: 137 talloc_free(ent); 138 ret = LDAP_OPERATIONS_ERROR; 139 errstr = "No memory"; 140done: 141 *response = ent; 142 result->resultcode = ret; 143 result->errormessage = (errstr?talloc_strdup(mem_ctx, errstr):NULL); 144} 145 146/* 147 handle incoming cldap requests 148*/ 149void cldapd_rootdse_request(struct cldap_socket *cldap, 150 struct cldapd_server *cldapd, 151 TALLOC_CTX *tmp_ctx, 152 uint32_t message_id, 153 struct ldap_SearchRequest *search, 154 struct tsocket_address *src) 155{ 156 NTSTATUS status; 157 struct cldap_reply reply; 158 struct ldap_Result result; 159 160 ZERO_STRUCT(result); 161 162 reply.messageid = message_id; 163 reply.dest = src; 164 reply.response = NULL; 165 reply.result = &result; 166 167 cldapd_rootdse_fill(cldapd, tmp_ctx, search, &reply.response, reply.result); 168 169 status = cldap_reply_send(cldap, &reply); 170 if (!NT_STATUS_IS_OK(status)) { 171 DEBUG(2,("cldap rootdse query failed '%s' - %s\n", 172 ldb_filter_from_tree(tmp_ctx, search->tree), nt_errstr(status))); 173 } 174 175 return; 176} 177