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