1/* 2 ldb database library 3 4 Copyright (C) Andrew Tridgell 2004 5 6 ** NOTE! The following LGPL license applies to the ldb 7 ** library. This does NOT imply that all of Samba is released 8 ** under the LGPL 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 3 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, see <http://www.gnu.org/licenses/>. 22*/ 23 24/* 25 * Name: ldb 26 * 27 * Component: ldb search functions 28 * 29 * Description: functions to search ldb+tdb databases 30 * 31 * Author: Andrew Tridgell 32 */ 33 34#include "includes.h" 35#include "ldb/include/includes.h" 36 37#include "ldb/ldb_tdb/ldb_tdb.h" 38 39/* 40 add one element to a message 41*/ 42static int msg_add_element(struct ldb_message *ret, 43 const struct ldb_message_element *el, 44 int check_duplicates) 45{ 46 unsigned int i; 47 struct ldb_message_element *e2, *elnew; 48 49 if (check_duplicates && ldb_msg_find_element(ret, el->name)) { 50 /* its already there */ 51 return 0; 52 } 53 54 e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1); 55 if (!e2) { 56 return -1; 57 } 58 ret->elements = e2; 59 60 elnew = &e2[ret->num_elements]; 61 62 elnew->name = talloc_strdup(ret->elements, el->name); 63 if (!elnew->name) { 64 return -1; 65 } 66 67 if (el->num_values) { 68 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values); 69 if (!elnew->values) { 70 return -1; 71 } 72 } else { 73 elnew->values = NULL; 74 } 75 76 for (i=0;i<el->num_values;i++) { 77 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]); 78 if (elnew->values[i].length != el->values[i].length) { 79 return -1; 80 } 81 } 82 83 elnew->num_values = el->num_values; 84 85 ret->num_elements++; 86 87 return 0; 88} 89 90/* 91 add the special distinguishedName element 92*/ 93static int msg_add_distinguished_name(struct ldb_message *msg) 94{ 95 struct ldb_message_element el; 96 struct ldb_val val; 97 int ret; 98 99 el.flags = 0; 100 el.name = "distinguishedName"; 101 el.num_values = 1; 102 el.values = &val; 103 val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn); 104 val.length = strlen((char *)val.data); 105 106 ret = msg_add_element(msg, &el, 1); 107 return ret; 108} 109 110/* 111 add all elements from one message into another 112 */ 113static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret, 114 const struct ldb_message *msg) 115{ 116 struct ldb_context *ldb = module->ldb; 117 unsigned int i; 118 int check_duplicates = (ret->num_elements != 0); 119 120 if (msg_add_distinguished_name(ret) != 0) { 121 return -1; 122 } 123 124 for (i=0;i<msg->num_elements;i++) { 125 const struct ldb_attrib_handler *h; 126 h = ldb_attrib_handler(ldb, msg->elements[i].name); 127 if (h->flags & LDB_ATTR_FLAG_HIDDEN) { 128 continue; 129 } 130 if (msg_add_element(ret, &msg->elements[i], 131 check_duplicates) != 0) { 132 return -1; 133 } 134 } 135 136 return 0; 137} 138 139 140/* 141 pull the specified list of attributes from a message 142 */ 143static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 144 TALLOC_CTX *mem_ctx, 145 const struct ldb_message *msg, 146 const char * const *attrs) 147{ 148 struct ldb_message *ret; 149 int i; 150 151 ret = talloc(mem_ctx, struct ldb_message); 152 if (!ret) { 153 return NULL; 154 } 155 156 ret->dn = ldb_dn_copy(ret, msg->dn); 157 if (!ret->dn) { 158 talloc_free(ret); 159 return NULL; 160 } 161 162 ret->num_elements = 0; 163 ret->elements = NULL; 164 165 if (!attrs) { 166 if (msg_add_all_elements(module, ret, msg) != 0) { 167 talloc_free(ret); 168 return NULL; 169 } 170 return ret; 171 } 172 173 for (i=0;attrs[i];i++) { 174 struct ldb_message_element *el; 175 176 if (strcmp(attrs[i], "*") == 0) { 177 if (msg_add_all_elements(module, ret, msg) != 0) { 178 talloc_free(ret); 179 return NULL; 180 } 181 continue; 182 } 183 184 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) { 185 if (msg_add_distinguished_name(ret) != 0) { 186 return NULL; 187 } 188 continue; 189 } 190 191 el = ldb_msg_find_element(msg, attrs[i]); 192 if (!el) { 193 continue; 194 } 195 if (msg_add_element(ret, el, 1) != 0) { 196 talloc_free(ret); 197 return NULL; 198 } 199 } 200 201 return ret; 202} 203 204 205/* 206 search the database for a single simple dn, returning all attributes 207 in a single message 208 209 return 1 on success, 0 on record-not-found and -1 on error 210*/ 211int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg) 212{ 213 struct ltdb_private *ltdb = 214 (struct ltdb_private *)module->private_data; 215 int ret; 216 TDB_DATA tdb_key, tdb_data; 217 218 memset(msg, 0, sizeof(*msg)); 219 220 /* form the key */ 221 tdb_key = ltdb_key(module, dn); 222 if (!tdb_key.dptr) { 223 return -1; 224 } 225 226 tdb_data = tdb_fetch(ltdb->tdb, tdb_key); 227 talloc_free(tdb_key.dptr); 228 if (!tdb_data.dptr) { 229 return 0; 230 } 231 232 msg->num_elements = 0; 233 msg->elements = NULL; 234 235 ret = ltdb_unpack_data(module, &tdb_data, msg); 236 free(tdb_data.dptr); 237 if (ret == -1) { 238 return -1; 239 } 240 241 if (!msg->dn) { 242 msg->dn = ldb_dn_copy(msg, dn); 243 } 244 if (!msg->dn) { 245 return -1; 246 } 247 248 return 1; 249} 250 251/* 252 lock the database for read - use by ltdb_search 253*/ 254static int ltdb_lock_read(struct ldb_module *module) 255{ 256 struct ltdb_private *ltdb = 257 (struct ltdb_private *)module->private_data; 258 return tdb_lockall_read(ltdb->tdb); 259} 260 261/* 262 unlock the database after a ltdb_lock_read() 263*/ 264static int ltdb_unlock_read(struct ldb_module *module) 265{ 266 struct ltdb_private *ltdb = 267 (struct ltdb_private *)module->private_data; 268 return tdb_unlockall_read(ltdb->tdb); 269} 270 271/* 272 add a set of attributes from a record to a set of results 273 return 0 on success, -1 on failure 274*/ 275int ltdb_add_attr_results(struct ldb_module *module, 276 TALLOC_CTX *mem_ctx, 277 struct ldb_message *msg, 278 const char * const attrs[], 279 unsigned int *count, 280 struct ldb_message ***res) 281{ 282 struct ldb_message *msg2; 283 struct ldb_message **res2; 284 285 /* pull the attributes that the user wants */ 286 msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs); 287 if (!msg2) { 288 return -1; 289 } 290 291 /* add to the results list */ 292 res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2); 293 if (!res2) { 294 talloc_free(msg2); 295 return -1; 296 } 297 298 (*res) = res2; 299 300 (*res)[*count] = talloc_move(*res, &msg2); 301 (*res)[(*count)+1] = NULL; 302 (*count)++; 303 304 return 0; 305} 306 307 308 309/* 310 filter the specified list of attributes from a message 311 removing not requested attrs. 312 */ 313int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs) 314{ 315 int i, keep_all = 0; 316 317 if (attrs) { 318 /* check for special attrs */ 319 for (i = 0; attrs[i]; i++) { 320 if (strcmp(attrs[i], "*") == 0) { 321 keep_all = 1; 322 break; 323 } 324 325 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) { 326 if (msg_add_distinguished_name(msg) != 0) { 327 return -1; 328 } 329 } 330 } 331 } else { 332 keep_all = 1; 333 } 334 335 if (keep_all) { 336 if (msg_add_distinguished_name(msg) != 0) { 337 return -1; 338 } 339 return 0; 340 } 341 342 for (i = 0; i < msg->num_elements; i++) { 343 int j, found; 344 345 for (j = 0, found = 0; attrs[j]; j++) { 346 if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) { 347 found = 1; 348 break; 349 } 350 } 351 352 if (!found) { 353 ldb_msg_remove_attr(msg, msg->elements[i].name); 354 i--; 355 } 356 } 357 358 return 0; 359} 360 361/* 362 search function for a non-indexed search 363 */ 364static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) 365{ 366 struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle); 367 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); 368 struct ldb_reply *ares = NULL; 369 int ret; 370 371 if (key.dsize < 4 || 372 strncmp((char *)key.dptr, "DN=", 3) != 0) { 373 return 0; 374 } 375 376 ares = talloc_zero(ac, struct ldb_reply); 377 if (!ares) { 378 handle->status = LDB_ERR_OPERATIONS_ERROR; 379 handle->state = LDB_ASYNC_DONE; 380 return -1; 381 } 382 383 ares->message = ldb_msg_new(ares); 384 if (!ares->message) { 385 handle->status = LDB_ERR_OPERATIONS_ERROR; 386 handle->state = LDB_ASYNC_DONE; 387 talloc_free(ares); 388 return -1; 389 } 390 391 /* unpack the record */ 392 ret = ltdb_unpack_data(ac->module, &data, ares->message); 393 if (ret == -1) { 394 talloc_free(ares); 395 return -1; 396 } 397 398 if (!ares->message->dn) { 399 ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3); 400 if (ares->message->dn == NULL) { 401 handle->status = LDB_ERR_OPERATIONS_ERROR; 402 handle->state = LDB_ASYNC_DONE; 403 talloc_free(ares); 404 return -1; 405 } 406 } 407 408 /* see if it matches the given expression */ 409 if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, 410 ac->base, ac->scope)) { 411 talloc_free(ares); 412 return 0; 413 } 414 415 /* filter the attributes that the user wants */ 416 ret = ltdb_filter_attrs(ares->message, ac->attrs); 417 418 if (ret == -1) { 419 handle->status = LDB_ERR_OPERATIONS_ERROR; 420 handle->state = LDB_ASYNC_DONE; 421 talloc_free(ares); 422 return -1; 423 } 424 425 ares->type = LDB_REPLY_ENTRY; 426 handle->state = LDB_ASYNC_PENDING; 427 handle->status = ac->callback(ac->module->ldb, ac->context, ares); 428 429 if (handle->status != LDB_SUCCESS) { 430 /* don't try to free ares here, the callback is in charge of that */ 431 return -1; 432 } 433 434 return 0; 435} 436 437 438/* 439 search the database with a LDAP-like expression. 440 this is the "full search" non-indexed variant 441*/ 442static int ltdb_search_full(struct ldb_handle *handle) 443{ 444 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); 445 struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); 446 int ret; 447 448 ret = tdb_traverse_read(ltdb->tdb, search_func, handle); 449 450 if (ret == -1) { 451 handle->status = LDB_ERR_OPERATIONS_ERROR; 452 } 453 454 handle->state = LDB_ASYNC_DONE; 455 return LDB_SUCCESS; 456} 457 458/* 459 search the database with a LDAP-like expression. 460 choses a search method 461*/ 462int ltdb_search(struct ldb_module *module, struct ldb_request *req) 463{ 464 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); 465 struct ltdb_context *ltdb_ac; 466 struct ldb_reply *ares; 467 int ret; 468 469 if ((req->op.search.base == NULL || ldb_dn_get_comp_num(req->op.search.base) == 0) && 470 (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) 471 return LDB_ERR_OPERATIONS_ERROR; 472 473 if (ltdb_lock_read(module) != 0) { 474 return LDB_ERR_OPERATIONS_ERROR; 475 } 476 477 if (ltdb_cache_load(module) != 0) { 478 ltdb_unlock_read(module); 479 return LDB_ERR_OPERATIONS_ERROR; 480 } 481 482 if (req->op.search.tree == NULL) { 483 ltdb_unlock_read(module); 484 return LDB_ERR_OPERATIONS_ERROR; 485 } 486 487 req->handle = init_ltdb_handle(ltdb, module, req); 488 if (req->handle == NULL) { 489 ltdb_unlock_read(module); 490 return LDB_ERR_OPERATIONS_ERROR; 491 } 492 ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); 493 494 ltdb_ac->tree = req->op.search.tree; 495 ltdb_ac->scope = req->op.search.scope; 496 ltdb_ac->base = req->op.search.base; 497 ltdb_ac->attrs = req->op.search.attrs; 498 499 ret = ltdb_search_indexed(req->handle); 500 if (ret == -1) { 501 ret = ltdb_search_full(req->handle); 502 } 503 if (ret != LDB_SUCCESS) { 504 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n"); 505 req->handle->state = LDB_ASYNC_DONE; 506 req->handle->status = ret; 507 } 508 509 /* Finally send an LDB_REPLY_DONE packet when searching is finished */ 510 511 ares = talloc_zero(req, struct ldb_reply); 512 if (!ares) { 513 ltdb_unlock_read(module); 514 return LDB_ERR_OPERATIONS_ERROR; 515 } 516 517 req->handle->state = LDB_ASYNC_DONE; 518 ares->type = LDB_REPLY_DONE; 519 520 ret = req->callback(module->ldb, req->context, ares); 521 req->handle->status = ret; 522 523 ltdb_unlock_read(module); 524 525 return LDB_SUCCESS; 526} 527 528