Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : ldb database library - Extended match rules
5 :
6 : Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
7 : Copyright (C) Andrew Bartlett <abartlet@samba.org>
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include <ldb_module.h>
25 : #include "dsdb/samdb/samdb.h"
26 : #include "ldb_matching_rules.h"
27 : #include "libcli/security/security.h"
28 : #include "dsdb/common/util.h"
29 : #include "librpc/gen_ndr/ndr_dnsp.h"
30 : #include "lib/util/smb_strtox.h"
31 :
32 : #undef strcasecmp
33 :
34 5614 : static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx,
35 : struct ldb_context *ldb,
36 : const char *attr,
37 : const struct dsdb_dn *dn_to_match,
38 : const char *dn_oid,
39 : struct dsdb_dn *to_visit,
40 : struct dsdb_dn ***visited,
41 : unsigned int *visited_count,
42 : bool *matched)
43 : {
44 0 : TALLOC_CTX *tmp_ctx;
45 0 : int ret, i, j;
46 0 : struct ldb_result *res;
47 0 : struct ldb_message *msg;
48 0 : struct ldb_message_element *el;
49 5614 : const char *attrs[] = { attr, NULL };
50 :
51 5614 : tmp_ctx = talloc_new(mem_ctx);
52 5614 : if (tmp_ctx == NULL) {
53 0 : return LDB_ERR_OPERATIONS_ERROR;
54 : }
55 :
56 : /*
57 : * Fetch the entry to_visit
58 : *
59 : * NOTE: This is a new LDB search from the TOP of the module
60 : * stack. This means that this search runs the whole stack
61 : * from top to bottom.
62 : *
63 : * This may seem to be in-efficient, but it is also the only
64 : * way to ensure that the ACLs for this search are applied
65 : * correctly.
66 : *
67 : * Note also that we don't have the original request
68 : * here, so we can not apply controls or timeouts here.
69 : */
70 5614 : ret = dsdb_search_dn(ldb,
71 : tmp_ctx,
72 : &res,
73 : to_visit->dn,
74 : attrs,
75 : DSDB_MARK_REQ_UNTRUSTED);
76 5614 : if (ret != LDB_SUCCESS) {
77 0 : talloc_free(tmp_ctx);
78 0 : return ret;
79 : }
80 5614 : if (res->count != 1) {
81 0 : talloc_free(tmp_ctx);
82 0 : return LDB_ERR_OPERATIONS_ERROR;
83 : }
84 5614 : msg = res->msgs[0];
85 :
86 : /* Fetch the attribute to match from the entry being visited */
87 5614 : el = ldb_msg_find_element(msg, attr);
88 5614 : if (el == NULL) {
89 : /* This entry does not have the attribute to match */
90 4371 : talloc_free(tmp_ctx);
91 4371 : *matched = false;
92 4371 : return LDB_SUCCESS;
93 : }
94 :
95 : /*
96 : * If the value to match is present in the attribute values of the
97 : * current entry being visited, set matched to true and return OK
98 : */
99 2906 : for (i=0; i<el->num_values; i++) {
100 0 : struct dsdb_dn *dn;
101 1928 : dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
102 1928 : if (dn == NULL) {
103 0 : talloc_free(tmp_ctx);
104 0 : *matched = false;
105 0 : return LDB_ERR_INVALID_DN_SYNTAX;
106 : }
107 :
108 1928 : if (ldb_dn_compare(dn_to_match->dn, dn->dn) == 0) {
109 265 : talloc_free(tmp_ctx);
110 265 : *matched = true;
111 265 : return LDB_SUCCESS;
112 : }
113 : }
114 :
115 : /*
116 : * If arrived here, the value to match is not in the values of the
117 : * entry being visited. Add the entry being visited (to_visit)
118 : * to the visited array. The array is (re)allocated in the parent
119 : * memory context.
120 : */
121 978 : if (visited == NULL) {
122 0 : return LDB_ERR_OPERATIONS_ERROR;
123 978 : } else if (*visited == NULL) {
124 543 : *visited = talloc_array(mem_ctx, struct dsdb_dn *, 1);
125 543 : if (*visited == NULL) {
126 0 : talloc_free(tmp_ctx);
127 0 : return LDB_ERR_OPERATIONS_ERROR;
128 : }
129 543 : (*visited)[0] = to_visit;
130 543 : (*visited_count) = 1;
131 : } else {
132 435 : *visited = talloc_realloc(mem_ctx, *visited, struct dsdb_dn *,
133 : (*visited_count) + 1);
134 435 : if (*visited == NULL) {
135 0 : talloc_free(tmp_ctx);
136 0 : return LDB_ERR_OPERATIONS_ERROR;
137 : }
138 435 : (*visited)[(*visited_count)] = to_visit;
139 435 : (*visited_count)++;
140 : }
141 :
142 : /*
143 : * steal to_visit into visited array context, as it has to live until
144 : * the array is freed.
145 : */
146 978 : talloc_steal(*visited, to_visit);
147 :
148 : /*
149 : * Iterate over the values of the attribute of the entry being
150 : * visited (to_visit) and follow them, calling this function
151 : * recursively.
152 : * If the value is in the visited array, skip it.
153 : * Otherwise, follow the link and visit it.
154 : */
155 2223 : for (i=0; i<el->num_values; i++) {
156 0 : struct dsdb_dn *next_to_visit;
157 1430 : bool skip = false;
158 :
159 1430 : next_to_visit = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
160 1430 : if (next_to_visit == NULL) {
161 0 : talloc_free(tmp_ctx);
162 0 : *matched = false;
163 0 : return LDB_ERR_INVALID_DN_SYNTAX;
164 : }
165 :
166 : /*
167 : * If the value is already in the visited array, skip it.
168 : * Note the last element of the array is ignored because it is
169 : * the current entry DN.
170 : */
171 2710 : for (j=0; j < (*visited_count) - 1; j++) {
172 1310 : struct dsdb_dn *visited_dn = (*visited)[j];
173 1310 : if (ldb_dn_compare(visited_dn->dn,
174 : next_to_visit->dn) == 0) {
175 30 : skip = true;
176 30 : break;
177 : }
178 : }
179 1430 : if (skip) {
180 30 : talloc_free(next_to_visit);
181 30 : continue;
182 : }
183 :
184 : /* If the value is not in the visited array, evaluate it */
185 1400 : ret = ldb_eval_transitive_filter_helper(tmp_ctx, ldb, attr,
186 : dn_to_match, dn_oid,
187 : next_to_visit,
188 : visited, visited_count,
189 : matched);
190 1400 : if (ret != LDB_SUCCESS) {
191 0 : talloc_free(tmp_ctx);
192 0 : return ret;
193 : }
194 1400 : if (*matched) {
195 185 : talloc_free(tmp_ctx);
196 185 : return LDB_SUCCESS;
197 : }
198 : }
199 :
200 793 : talloc_free(tmp_ctx);
201 793 : *matched = false;
202 793 : return LDB_SUCCESS;
203 : }
204 :
205 : /*
206 : * This function parses the linked attribute value to match, whose syntax
207 : * will be one of the different DN syntaxes, into a ldb_dn struct.
208 : */
209 4216 : static int ldb_eval_transitive_filter(TALLOC_CTX *mem_ctx,
210 : struct ldb_context *ldb,
211 : const char *attr,
212 : const struct ldb_val *value_to_match,
213 : struct dsdb_dn *current_object_dn,
214 : bool *matched)
215 : {
216 0 : const struct dsdb_schema *schema;
217 0 : const struct dsdb_attribute *schema_attr;
218 0 : struct dsdb_dn *dn_to_match;
219 0 : const char *dn_oid;
220 0 : unsigned int count;
221 4216 : struct dsdb_dn **visited = NULL;
222 :
223 4216 : schema = dsdb_get_schema(ldb, mem_ctx);
224 4216 : if (schema == NULL) {
225 0 : return LDB_ERR_OPERATIONS_ERROR;
226 : }
227 :
228 4216 : schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attr);
229 4216 : if (schema_attr == NULL) {
230 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
231 : }
232 :
233 : /* This is the DN syntax of the attribute being matched */
234 4216 : dn_oid = schema_attr->syntax->ldap_oid;
235 :
236 : /*
237 : * Build a ldb_dn struct holding the value to match, which is the
238 : * value entered in the search filter
239 : */
240 4216 : dn_to_match = dsdb_dn_parse(mem_ctx, ldb, value_to_match, dn_oid);
241 4216 : if (dn_to_match == NULL) {
242 2 : *matched = false;
243 2 : return LDB_SUCCESS;
244 : }
245 :
246 4214 : return ldb_eval_transitive_filter_helper(mem_ctx, ldb, attr,
247 : dn_to_match, dn_oid,
248 : current_object_dn,
249 : &visited, &count, matched);
250 : }
251 :
252 : /*
253 : * This rule provides recursive search of a link attribute
254 : *
255 : * Documented in [MS-ADTS] section 3.1.1.3.4.4.3 LDAP_MATCHING_RULE_TRANSITIVE_EVAL
256 : * This allows a search filter such as:
257 : *
258 : * member:1.2.840.113556.1.4.1941:=cn=user,cn=users,dc=samba,dc=example,dc=com
259 : *
260 : * This searches not only the member attribute, but also any member
261 : * attributes that point at an object with this member in them. All the
262 : * various DN syntax types are supported, not just plain DNs.
263 : *
264 : */
265 4243 : static int ldb_comparator_trans(struct ldb_context *ldb,
266 : const char *oid,
267 : const struct ldb_message *msg,
268 : const char *attribute_to_match,
269 : const struct ldb_val *value_to_match,
270 : bool *matched)
271 : {
272 0 : const struct dsdb_schema *schema;
273 0 : const struct dsdb_attribute *schema_attr;
274 0 : struct ldb_dn *msg_dn;
275 0 : struct dsdb_dn *dsdb_msg_dn;
276 0 : TALLOC_CTX *tmp_ctx;
277 0 : int ret;
278 :
279 4243 : tmp_ctx = talloc_new(ldb);
280 4243 : if (tmp_ctx == NULL) {
281 0 : return LDB_ERR_OPERATIONS_ERROR;
282 : }
283 :
284 : /*
285 : * If the target attribute to match is not a linked attribute, then
286 : * the filter evaluates to undefined
287 : */
288 4243 : schema = dsdb_get_schema(ldb, tmp_ctx);
289 4243 : if (schema == NULL) {
290 0 : talloc_free(tmp_ctx);
291 0 : return LDB_ERR_OPERATIONS_ERROR;
292 : }
293 :
294 4243 : schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
295 4243 : if (schema_attr == NULL) {
296 0 : talloc_free(tmp_ctx);
297 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
298 : }
299 :
300 : /*
301 : * This extended match filter is only valid for linked attributes,
302 : * following the MS definition (the schema attribute has a linkID
303 : * defined). See dochelp request 114111212024789 on cifs-protocols
304 : * mailing list.
305 : */
306 4243 : if (schema_attr->linkID == 0) {
307 27 : *matched = false;
308 27 : talloc_free(tmp_ctx);
309 27 : return LDB_SUCCESS;
310 : }
311 :
312 : /* Duplicate original msg dn as the msg must not be modified */
313 4216 : msg_dn = ldb_dn_copy(tmp_ctx, msg->dn);
314 4216 : if (msg_dn == NULL) {
315 0 : talloc_free(tmp_ctx);
316 0 : return LDB_ERR_OPERATIONS_ERROR;
317 : }
318 :
319 : /*
320 : * Build a dsdb dn from the message copied DN, which should be a plain
321 : * DN syntax.
322 : */
323 4216 : dsdb_msg_dn = dsdb_dn_construct(tmp_ctx, msg_dn, data_blob_null,
324 : LDB_SYNTAX_DN);
325 4216 : if (dsdb_msg_dn == NULL) {
326 0 : *matched = false;
327 0 : return LDB_ERR_INVALID_DN_SYNTAX;
328 : }
329 :
330 4216 : ret = ldb_eval_transitive_filter(tmp_ctx, ldb,
331 : attribute_to_match,
332 : value_to_match,
333 : dsdb_msg_dn, matched);
334 4216 : talloc_free(tmp_ctx);
335 4216 : return ret;
336 : }
337 :
338 :
339 : /*
340 : * This rule provides match of a dns object with expired records.
341 : *
342 : * This allows a search filter such as:
343 : *
344 : * dnsRecord:1.3.6.1.4.1.7165.4.5.3:=3694869
345 : *
346 : * where the value is a number of hours since the start of 1601.
347 : *
348 : * This allows the caller to find records that should become a DNS
349 : * tomestone, despite that information being deep within an NDR packed
350 : * object
351 : */
352 337 : static int dsdb_match_for_dns_to_tombstone_time(struct ldb_context *ldb,
353 : const char *oid,
354 : const struct ldb_message *msg,
355 : const char *attribute_to_match,
356 : const struct ldb_val *value_to_match,
357 : bool *matched)
358 : {
359 0 : TALLOC_CTX *tmp_ctx;
360 0 : unsigned int i;
361 337 : struct ldb_message_element *el = NULL;
362 337 : struct auth_session_info *session_info = NULL;
363 0 : uint64_t tombstone_time;
364 337 : struct dnsp_DnssrvRpcRecord *rec = NULL;
365 0 : enum ndr_err_code err;
366 337 : *matched = false;
367 :
368 : /* Needs to be dnsRecord, no match otherwise */
369 337 : if (ldb_attr_cmp(attribute_to_match, "dnsRecord") != 0) {
370 6 : return LDB_SUCCESS;
371 : }
372 :
373 331 : el = ldb_msg_find_element(msg, attribute_to_match);
374 331 : if (el == NULL) {
375 15 : return LDB_SUCCESS;
376 : }
377 :
378 316 : if (ldb_msg_element_is_inaccessible(el)) {
379 0 : *matched = false;
380 0 : return LDB_SUCCESS;
381 : }
382 :
383 316 : session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"),
384 : struct auth_session_info);
385 316 : if (session_info == NULL) {
386 0 : return ldb_oom(ldb);
387 : }
388 316 : if (security_session_user_level(session_info, NULL)
389 : != SECURITY_SYSTEM) {
390 :
391 3 : DBG_ERR("unauthorised access\n");
392 3 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
393 : }
394 :
395 : /* We only expect uint32_t <= 10 digits */
396 313 : if (value_to_match->length >= 12) {
397 3 : DBG_ERR("Invalid timestamp passed\n");
398 3 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
399 : } else {
400 310 : int error = 0;
401 0 : char s[12];
402 :
403 310 : memcpy(s, value_to_match->data, value_to_match->length);
404 310 : s[value_to_match->length] = 0;
405 310 : if (s[0] == '\0') {
406 3 : DBG_ERR("Empty timestamp passed\n");
407 9 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
408 : }
409 307 : tombstone_time = smb_strtoull(s,
410 : NULL,
411 : 10,
412 : &error,
413 : SMB_STR_FULL_STR_CONV);
414 307 : if (error != 0) {
415 6 : DBG_ERR("Invalid timestamp string passed\n");
416 6 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
417 : }
418 : }
419 :
420 301 : tmp_ctx = talloc_new(ldb);
421 301 : if (tmp_ctx == NULL) {
422 0 : return ldb_oom(ldb);
423 : }
424 :
425 1209 : for (i = 0; i < el->num_values; i++) {
426 924 : rec = talloc_zero(tmp_ctx, struct dnsp_DnssrvRpcRecord);
427 924 : if (rec == NULL) {
428 0 : TALLOC_FREE(tmp_ctx);
429 0 : return ldb_oom(ldb);
430 : }
431 924 : err = ndr_pull_struct_blob(
432 924 : &(el->values[i]),
433 : tmp_ctx,
434 : rec,
435 : (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
436 924 : if (!NDR_ERR_CODE_IS_SUCCESS(err)){
437 0 : DBG_ERR("Failed to pull dns rec blob.\n");
438 0 : TALLOC_FREE(tmp_ctx);
439 0 : return LDB_ERR_OPERATIONS_ERROR;
440 : }
441 :
442 924 : if (rec->wType == DNS_TYPE_SOA || rec->wType == DNS_TYPE_NS) {
443 40 : TALLOC_FREE(rec);
444 40 : continue;
445 : }
446 :
447 884 : if (rec->wType == DNS_TYPE_TOMBSTONE) {
448 2 : TALLOC_FREE(rec);
449 2 : continue;
450 : }
451 882 : if (rec->dwTimeStamp == 0) {
452 134 : TALLOC_FREE(rec);
453 134 : continue;
454 : }
455 748 : if (rec->dwTimeStamp > tombstone_time) {
456 732 : TALLOC_FREE(rec);
457 732 : continue;
458 : }
459 :
460 16 : *matched = true;
461 16 : break;
462 : }
463 :
464 301 : TALLOC_FREE(tmp_ctx);
465 301 : return LDB_SUCCESS;
466 : }
467 :
468 :
469 : /*
470 : * This rule provides match of a link attribute against a 'should be expunged' criteria
471 : *
472 : * This allows a search filter such as:
473 : *
474 : * member:1.3.6.1.4.1.7165.4.5.2:=131139216000000000
475 : *
476 : * This searches the member attribute, but also any member attributes
477 : * that are deleted and should be expunged after the specified NTTIME
478 : * time.
479 : *
480 : */
481 8039834 : static int dsdb_match_for_expunge(struct ldb_context *ldb,
482 : const char *oid,
483 : const struct ldb_message *msg,
484 : const char *attribute_to_match,
485 : const struct ldb_val *value_to_match,
486 : bool *matched)
487 : {
488 407846 : const struct dsdb_schema *schema;
489 407846 : const struct dsdb_attribute *schema_attr;
490 407846 : TALLOC_CTX *tmp_ctx;
491 407846 : unsigned int i;
492 407846 : struct ldb_message_element *el;
493 407846 : struct auth_session_info *session_info;
494 407846 : uint64_t tombstone_time;
495 8039834 : *matched = false;
496 :
497 8039834 : el = ldb_msg_find_element(msg, attribute_to_match);
498 8039834 : if (el == NULL) {
499 7630106 : return LDB_SUCCESS;
500 : }
501 :
502 2019 : if (ldb_msg_element_is_inaccessible(el)) {
503 0 : *matched = false;
504 0 : return LDB_SUCCESS;
505 : }
506 :
507 137 : session_info
508 2019 : = talloc_get_type(ldb_get_opaque(ldb, DSDB_SESSION_INFO),
509 : struct auth_session_info);
510 2019 : if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
511 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
512 : }
513 :
514 : /*
515 : * If the target attribute to match is not a linked attribute, then
516 : * the filter evaluates to undefined
517 : */
518 2019 : schema = dsdb_get_schema(ldb, NULL);
519 2019 : if (schema == NULL) {
520 0 : return LDB_ERR_OPERATIONS_ERROR;
521 : }
522 :
523 : /* TODO this is O(log n) per attribute */
524 2019 : schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
525 2019 : if (schema_attr == NULL) {
526 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
527 : }
528 :
529 : /*
530 : * This extended match filter is only valid for forward linked attributes.
531 : */
532 2019 : if (schema_attr->linkID == 0 || (schema_attr->linkID & 1) == 1) {
533 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
534 : }
535 :
536 : /* Just check we don't allow the caller to fill our stack */
537 2017 : if (value_to_match->length >=64) {
538 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
539 2017 : } else {
540 2017 : int error = 0;
541 2017 : char s[value_to_match->length+1];
542 :
543 2017 : memcpy(s, value_to_match->data, value_to_match->length);
544 2017 : s[value_to_match->length] = 0;
545 2017 : if (s[0] == '\0' || s[0] == '-') {
546 6 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
547 : }
548 2016 : tombstone_time = smb_strtoull(s,
549 : NULL,
550 : 10,
551 : &error,
552 : SMB_STR_FULL_STR_CONV);
553 2016 : if (error != 0) {
554 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
555 : }
556 : }
557 :
558 2011 : tmp_ctx = talloc_new(ldb);
559 2011 : if (tmp_ctx == NULL) {
560 0 : return LDB_ERR_OPERATIONS_ERROR;
561 : }
562 :
563 6041 : for (i = 0; i < el->num_values; i++) {
564 247 : NTSTATUS status;
565 247 : struct dsdb_dn *dn;
566 247 : uint64_t rmd_changetime;
567 4049 : if (dsdb_dn_is_deleted_val(&el->values[i]) == false) {
568 4030 : continue;
569 : }
570 :
571 90 : dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i],
572 69 : schema_attr->syntax->ldap_oid);
573 69 : if (dn == NULL) {
574 0 : DEBUG(1, ("Error: Failed to parse linked attribute blob of %s.\n", el->name));
575 0 : continue;
576 : }
577 :
578 69 : status = dsdb_get_extended_dn_uint64(dn->dn, &rmd_changetime,
579 : "RMD_CHANGETIME");
580 69 : if (!NT_STATUS_IS_OK(status)) {
581 0 : DEBUG(1, ("Error: RMD_CHANGETIME is missing on a forward link.\n"));
582 0 : continue;
583 : }
584 :
585 69 : if (rmd_changetime > tombstone_time) {
586 50 : continue;
587 : }
588 :
589 19 : *matched = true;
590 19 : break;
591 : }
592 2011 : talloc_free(tmp_ctx);
593 2011 : return LDB_SUCCESS;
594 : }
595 :
596 :
597 339476 : int ldb_register_samba_matching_rules(struct ldb_context *ldb)
598 : {
599 339476 : struct ldb_extended_match_rule *transitive_eval = NULL,
600 339476 : *match_for_expunge = NULL,
601 339476 : *match_for_dns_to_tombstone_time = NULL;
602 11313 : int ret;
603 :
604 339476 : transitive_eval = talloc_zero(ldb, struct ldb_extended_match_rule);
605 339476 : transitive_eval->oid = SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL;
606 339476 : transitive_eval->callback = ldb_comparator_trans;
607 339476 : ret = ldb_register_extended_match_rule(ldb, transitive_eval);
608 339476 : if (ret != LDB_SUCCESS) {
609 0 : talloc_free(transitive_eval);
610 0 : return ret;
611 : }
612 :
613 339476 : match_for_expunge = talloc_zero(ldb, struct ldb_extended_match_rule);
614 339476 : match_for_expunge->oid = DSDB_MATCH_FOR_EXPUNGE;
615 339476 : match_for_expunge->callback = dsdb_match_for_expunge;
616 339476 : ret = ldb_register_extended_match_rule(ldb, match_for_expunge);
617 339476 : if (ret != LDB_SUCCESS) {
618 0 : talloc_free(match_for_expunge);
619 0 : return ret;
620 : }
621 :
622 339476 : match_for_dns_to_tombstone_time = talloc_zero(
623 : ldb,
624 : struct ldb_extended_match_rule);
625 339476 : match_for_dns_to_tombstone_time->oid = DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME;
626 11313 : match_for_dns_to_tombstone_time->callback
627 339476 : = dsdb_match_for_dns_to_tombstone_time;
628 339476 : ret = ldb_register_extended_match_rule(ldb,
629 : match_for_dns_to_tombstone_time);
630 339476 : if (ret != LDB_SUCCESS) {
631 0 : TALLOC_FREE(match_for_dns_to_tombstone_time);
632 0 : return ret;
633 : }
634 :
635 328163 : return LDB_SUCCESS;
636 : }
|