LCOV - code coverage report
Current view: top level - lib/ldb-samba - ldb_matching_rules.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 206 286 72.0 %
Date: 2024-02-29 22:57:05 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        5630 : 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        5630 :         const char *attrs[] = { attr, NULL };
      50             : 
      51        5630 :         tmp_ctx = talloc_new(mem_ctx);
      52        5630 :         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        5630 :         ret = dsdb_search_dn(ldb,
      71             :                              tmp_ctx,
      72             :                              &res,
      73             :                              to_visit->dn,
      74             :                              attrs,
      75             :                              DSDB_MARK_REQ_UNTRUSTED);
      76        5630 :         if (ret != LDB_SUCCESS) {
      77           0 :                 talloc_free(tmp_ctx);
      78           0 :                 return ret;
      79             :         }
      80        5630 :         if (res->count != 1) {
      81           0 :                 talloc_free(tmp_ctx);
      82           0 :                 return LDB_ERR_OPERATIONS_ERROR;
      83             :         }
      84        5630 :         msg = res->msgs[0];
      85             : 
      86             :         /* Fetch the attribute to match from the entry being visited */
      87        5630 :         el = ldb_msg_find_element(msg, attr);
      88        5630 :         if (el == NULL) {
      89             :                 /* This entry does not have the attribute to match */
      90        4395 :                 talloc_free(tmp_ctx);
      91        4395 :                 *matched = false;
      92        4395 :                 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        2884 :         for (i=0; i<el->num_values; i++) {
     100           0 :                 struct dsdb_dn *dn;
     101        1914 :                 dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
     102        1914 :                 if (dn == NULL) {
     103           0 :                         talloc_free(tmp_ctx);
     104           0 :                         *matched = false;
     105           0 :                         return LDB_ERR_INVALID_DN_SYNTAX;
     106             :                 }
     107             : 
     108        1914 :                 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         970 :         if (visited == NULL) {
     122           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     123         970 :         } 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         427 :                 *visited = talloc_realloc(mem_ctx, *visited, struct dsdb_dn *,
     133             :                                          (*visited_count) + 1);
     134         427 :                 if (*visited == NULL) {
     135           0 :                         talloc_free(tmp_ctx);
     136           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     137             :                 }
     138         427 :                 (*visited)[(*visited_count)] = to_visit;
     139         427 :                 (*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         970 :         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        2236 :         for (i=0; i<el->num_values; i++) {
     156           0 :                 struct dsdb_dn *next_to_visit;
     157        1444 :                 bool skip = false;
     158             : 
     159        1444 :                 next_to_visit = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
     160        1444 :                 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        2714 :                 for (j=0; j < (*visited_count) - 1; j++) {
     172        1298 :                         struct dsdb_dn *visited_dn = (*visited)[j];
     173        1298 :                         if (ldb_dn_compare(visited_dn->dn,
     174             :                                            next_to_visit->dn) == 0) {
     175          28 :                                 skip = true;
     176          28 :                                 break;
     177             :                         }
     178             :                 }
     179        1444 :                 if (skip) {
     180          28 :                         talloc_free(next_to_visit);
     181          28 :                         continue;
     182             :                 }
     183             : 
     184             :                 /* If the value is not in the visited array, evaluate it */
     185        1416 :                 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        1416 :                 if (ret != LDB_SUCCESS) {
     191           0 :                         talloc_free(tmp_ctx);
     192           0 :                         return ret;
     193             :                 }
     194        1416 :                 if (*matched) {
     195         178 :                         talloc_free(tmp_ctx);
     196         178 :                         return LDB_SUCCESS;
     197             :                 }
     198             :         }
     199             : 
     200         792 :         talloc_free(tmp_ctx);
     201         792 :         *matched = false;
     202         792 :         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         342 : 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         342 :         struct ldb_message_element *el = NULL;
     362         342 :         struct auth_session_info *session_info = NULL;
     363           0 :         uint64_t tombstone_time;
     364         342 :         struct dnsp_DnssrvRpcRecord *rec = NULL;
     365           0 :         enum ndr_err_code err;
     366         342 :         *matched = false;
     367             : 
     368             :         /* Needs to be dnsRecord, no match otherwise */
     369         342 :         if (ldb_attr_cmp(attribute_to_match, "dnsRecord") != 0) {
     370           6 :                 return LDB_SUCCESS;
     371             :         }
     372             : 
     373         336 :         el = ldb_msg_find_element(msg, attribute_to_match);
     374         336 :         if (el == NULL) {
     375          20 :                 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     8039940 : 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      407851 :         const struct dsdb_schema *schema;
     489      407851 :         const struct dsdb_attribute *schema_attr;
     490      407851 :         TALLOC_CTX *tmp_ctx;
     491      407851 :         unsigned int i;
     492      407851 :         struct ldb_message_element *el;
     493      407851 :         struct auth_session_info *session_info;
     494      407851 :         uint64_t tombstone_time;
     495     8039940 :         *matched = false;
     496             : 
     497     8039940 :         el = ldb_msg_find_element(msg, attribute_to_match);
     498     8039940 :         if (el == NULL) {
     499     7630209 :                 return LDB_SUCCESS;
     500             :         }
     501             : 
     502        2017 :         if (ldb_msg_element_is_inaccessible(el)) {
     503           0 :                 *matched = false;
     504           0 :                 return LDB_SUCCESS;
     505             :         }
     506             : 
     507         137 :         session_info
     508        2017 :                 = talloc_get_type(ldb_get_opaque(ldb, DSDB_SESSION_INFO),
     509             :                                   struct auth_session_info);
     510        2017 :         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        2017 :         schema = dsdb_get_schema(ldb, NULL);
     519        2017 :         if (schema == NULL) {
     520           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     521             :         }
     522             : 
     523             :         /* TODO this is O(log n) per attribute */
     524        2017 :         schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
     525        2017 :         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        2017 :         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        2015 :         if (value_to_match->length >=64) {
     538           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     539        2015 :         } else {
     540        2015 :                 int error = 0;
     541        2015 :                 char s[value_to_match->length+1];
     542             : 
     543        2015 :                 memcpy(s, value_to_match->data, value_to_match->length);
     544        2015 :                 s[value_to_match->length] = 0;
     545        2015 :                 if (s[0] == '\0' || s[0] == '-') {
     546           6 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     547             :                 }
     548        2014 :                 tombstone_time = smb_strtoull(s,
     549             :                                               NULL,
     550             :                                               10,
     551             :                                               &error,
     552             :                                               SMB_STR_FULL_STR_CONV);
     553        2014 :                 if (error != 0) {
     554           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     555             :                 }
     556             :         }
     557             : 
     558        2009 :         tmp_ctx = talloc_new(ldb);
     559        2009 :         if (tmp_ctx == NULL) {
     560           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     561             :         }
     562             : 
     563        6039 :         for (i = 0; i < el->num_values; i++) {
     564         249 :                 NTSTATUS status;
     565         249 :                 struct dsdb_dn *dn;
     566         249 :                 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        2009 :         talloc_free(tmp_ctx);
     593        2009 :         return LDB_SUCCESS;
     594             : }
     595             : 
     596             : 
     597      337734 : int ldb_register_samba_matching_rules(struct ldb_context *ldb)
     598             : {
     599      337734 :         struct ldb_extended_match_rule *transitive_eval = NULL,
     600      337734 :                 *match_for_expunge = NULL,
     601      337734 :                 *match_for_dns_to_tombstone_time = NULL;
     602       11276 :         int ret;
     603             : 
     604      337734 :         transitive_eval = talloc_zero(ldb, struct ldb_extended_match_rule);
     605      337734 :         transitive_eval->oid = SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL;
     606      337734 :         transitive_eval->callback = ldb_comparator_trans;
     607      337734 :         ret = ldb_register_extended_match_rule(ldb, transitive_eval);
     608      337734 :         if (ret != LDB_SUCCESS) {
     609           0 :                 talloc_free(transitive_eval);
     610           0 :                 return ret;
     611             :         }
     612             : 
     613      337734 :         match_for_expunge = talloc_zero(ldb, struct ldb_extended_match_rule);
     614      337734 :         match_for_expunge->oid = DSDB_MATCH_FOR_EXPUNGE;
     615      337734 :         match_for_expunge->callback = dsdb_match_for_expunge;
     616      337734 :         ret = ldb_register_extended_match_rule(ldb, match_for_expunge);
     617      337734 :         if (ret != LDB_SUCCESS) {
     618           0 :                 talloc_free(match_for_expunge);
     619           0 :                 return ret;
     620             :         }
     621             : 
     622      337734 :         match_for_dns_to_tombstone_time = talloc_zero(
     623             :                 ldb,
     624             :                 struct ldb_extended_match_rule);
     625      337734 :         match_for_dns_to_tombstone_time->oid = DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME;
     626       11276 :         match_for_dns_to_tombstone_time->callback
     627      337734 :                 = dsdb_match_for_dns_to_tombstone_time;
     628      337734 :         ret = ldb_register_extended_match_rule(ldb,
     629             :                                                match_for_dns_to_tombstone_time);
     630      337734 :         if (ret != LDB_SUCCESS) {
     631           0 :                 TALLOC_FREE(match_for_dns_to_tombstone_time);
     632           0 :                 return ret;
     633             :         }
     634             : 
     635      326458 :         return LDB_SUCCESS;
     636             : }

Generated by: LCOV version 1.14