PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/source4/lib/ldb/ldb_tdb/ldb_search.c

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