LCOV - code coverage report
Current view: top level - lib/ldb-samba - ldb_matching_rules.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 191 244 78.3 %
Date: 2021-08-25 13:27:56 Functions: 6 6 100.0 %

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

Generated by: LCOV version 1.13