LCOV - code coverage report
Current view: top level - source4/dsdb/common - util_links.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 56 83 67.5 %
Date: 2024-02-28 12:06:22 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Helpers to search for links in the DB
       5             : 
       6             :    Copyright (C) Catalyst.Net Ltd 2017
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "dsdb/samdb/samdb.h"
      24             : #include "lib/util/binsearch.h"
      25             : #include "librpc/gen_ndr/ndr_misc.h"
      26             : 
      27             : /*
      28             :  * We choose, as the sort order, the same order as is used in DRS replication,
      29             :  * which is the memcmp() order of the NDR GUID, not that obtained from
      30             :  * GUID_compare().
      31             :  *
      32             :  * This means that sorted links will be in the same order as a new DC would
      33             :  * see them.
      34             :  */
      35     8488185 : int ndr_guid_compare(const struct GUID *guid1, const struct GUID *guid2)
      36             : {
      37     8488185 :         uint8_t v1_data[16] = { 0 };
      38     8488185 :         struct ldb_val v1 = data_blob_const(v1_data, sizeof(v1_data));
      39        3437 :         uint8_t v2_data[16];
      40     8488185 :         struct ldb_val v2 = data_blob_const(v2_data, sizeof(v2_data));
      41             : 
      42             :         /* This can't fail */
      43     8488185 :         ndr_push_struct_into_fixed_blob(&v1, guid1,
      44             :                                         (ndr_push_flags_fn_t)ndr_push_GUID);
      45             :         /* This can't fail */
      46     8488185 :         ndr_push_struct_into_fixed_blob(&v2, guid2,
      47             :                                         (ndr_push_flags_fn_t)ndr_push_GUID);
      48     8488185 :         return data_blob_cmp(&v1, &v2);
      49             : }
      50             : 
      51             : 
      52      475462 : static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
      53             :                                            struct parsed_dn *p)
      54             : {
      55      475462 :         int cmp = 0;
      56             :         /*
      57             :          * This works like a standard compare function in its return values,
      58             :          * but has an extra trick to deal with errors: zero is returned and
      59             :          * ctx->err is set to the ldb error code.
      60             :          *
      61             :          * That is, if (as is expected in most cases) you get a non-zero
      62             :          * result, you don't need to check for errors.
      63             :          *
      64             :          * We assume the second argument refers to a DN is from the database
      65             :          * and has a GUID -- but this GUID might not have been parsed out yet.
      66             :          */
      67      475462 :         if (p->dsdb_dn == NULL) {
      68      337200 :                 int ret = really_parse_trusted_dn(ctx->mem_ctx, ctx->ldb, p,
      69             :                                                   ctx->ldap_oid);
      70      337200 :                 if (ret != LDB_SUCCESS) {
      71           0 :                         ctx->err = ret;
      72           0 :                         return 0;
      73             :                 }
      74             :         }
      75      475462 :         cmp = ndr_guid_compare(ctx->guid, &p->guid);
      76      475462 :         if (cmp == 0 && ctx->compare_extra_part) {
      77       63539 :                 if (ctx->partial_extra_part_length != 0) {
      78             :                         /* Allow a prefix match on the blob. */
      79        1252 :                         return memcmp(ctx->extra_part.data,
      80        1252 :                                       p->dsdb_dn->extra_part.data,
      81        1252 :                                       MIN(ctx->partial_extra_part_length,
      82             :                                           p->dsdb_dn->extra_part.length));
      83             :                 } else {
      84       62287 :                         return data_blob_cmp(&ctx->extra_part,
      85       62287 :                                              &p->dsdb_dn->extra_part);
      86             :                 }
      87             :         }
      88             : 
      89      411649 :         return cmp;
      90             : }
      91             : 
      92             : /* When a parsed_dn comes from the database, sometimes it is not really parsed. */
      93             : 
      94     2570922 : int really_parse_trusted_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
      95             :                                    struct parsed_dn *pdn, const char *ldap_oid)
      96             : {
      97         381 :         NTSTATUS status;
      98     2570922 :         struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb, pdn->v,
      99             :                                                         ldap_oid);
     100     2570922 :         if (dsdb_dn == NULL) {
     101           0 :                 return LDB_ERR_INVALID_DN_SYNTAX;
     102             :         }
     103             : 
     104     2570922 :         status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &pdn->guid, "GUID");
     105     2570922 :         if (!NT_STATUS_IS_OK(status)) {
     106           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     107             :         }
     108     2570922 :         pdn->dsdb_dn = dsdb_dn;
     109     2570922 :         return LDB_SUCCESS;
     110             : }
     111             : 
     112             : 
     113      115011 : int get_parsed_dns_trusted(TALLOC_CTX *mem_ctx, struct ldb_message_element *el,
     114             :                                   struct parsed_dn **pdn)
     115             : {
     116             :         /* Here we get a list of 'struct parsed_dns' without the parsing */
     117         204 :         unsigned int i;
     118      115011 :         *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
     119             :                                  el->num_values);
     120      115011 :         if (!*pdn) {
     121           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     122             :         }
     123             : 
     124     9481486 :         for (i = 0; i < el->num_values; i++) {
     125     9366475 :                 (*pdn)[i].v = &el->values[i];
     126             :         }
     127             : 
     128      114807 :         return LDB_SUCCESS;
     129             : }
     130             : 
     131             : 
     132      103939 : int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
     133             :                    unsigned int count,
     134             :                    const struct GUID *guid,
     135             :                    struct ldb_dn *target_dn,
     136             :                    DATA_BLOB extra_part,
     137             :                    size_t partial_extra_part_length,
     138             :                    struct parsed_dn **exact,
     139             :                    struct parsed_dn **next,
     140             :                    const char *ldap_oid,
     141             :                    bool compare_extra_part)
     142             : {
     143         259 :         unsigned int i;
     144         259 :         struct compare_ctx ctx;
     145      103939 :         if (pdn == NULL) {
     146        3373 :                 *exact = NULL;
     147        3373 :                 *next = NULL;
     148        3373 :                 return LDB_SUCCESS;
     149             :         }
     150             : 
     151      100566 :         if (unlikely(GUID_all_zero(guid))) {
     152             :                 /*
     153             :                  * When updating a link using DRS, we sometimes get a NULL
     154             :                  * GUID when a forward link has been deleted and its GUID has
     155             :                  * for some reason been forgotten. The best we can do is try
     156             :                  * and match by DN via a linear search. Note that this
     157             :                  * probably only happens in the ADD case, in which we only
     158             :                  * allow modification of link if it is already deleted, so
     159             :                  * this seems very close to an elaborate NO-OP, but we are not
     160             :                  * quite prepared to declare it so.
     161             :                  *
     162             :                  * If the DN is not in our list, we have to add it to the
     163             :                  * beginning of the list, where it would naturally sort.
     164             :                  */
     165           0 :                 struct parsed_dn *p;
     166           0 :                 if (target_dn == NULL) {
     167             :                         /* We don't know the target DN, so we can't search for DN */
     168           0 :                         DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
     169             :                                   "attribute but we don't have a DN to compare "
     170             :                                   "it with\n"));
     171           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     172             :                 }
     173           0 :                 *exact = NULL;
     174           0 :                 *next = NULL;
     175             : 
     176           0 :                 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
     177             :                           "%s; searching through links for it\n",
     178             :                           ldb_dn_get_linearized(target_dn)));
     179             : 
     180           0 :                 for (i = 0; i < count; i++) {
     181           0 :                         int cmp;
     182           0 :                         p = &pdn[i];
     183           0 :                         if (p->dsdb_dn == NULL) {
     184           0 :                                 int ret = really_parse_trusted_dn(pdn, ldb, p, ldap_oid);
     185           0 :                                 if (ret != LDB_SUCCESS) {
     186           0 :                                         return LDB_ERR_OPERATIONS_ERROR;
     187             :                                 }
     188             :                         }
     189             : 
     190           0 :                         cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
     191           0 :                         if (cmp == 0) {
     192           0 :                                 *exact = p;
     193           0 :                                 return LDB_SUCCESS;
     194             :                         }
     195             :                 }
     196             :                 /*
     197             :                  * Here we have a null guid which doesn't match any existing
     198             :                  * link. This is a bit unexpected because null guids occur
     199             :                  * when a forward link has been deleted and we are replicating
     200             :                  * that deletion.
     201             :                  *
     202             :                  * The best thing to do is weep into the logs and add the
     203             :                  * offending link to the beginning of the list which is
     204             :                  * at least the correct sort position.
     205             :                  */
     206           0 :                 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
     207             :                           "link to unknown DN %s\n",
     208             :                           ldb_dn_get_linearized(target_dn)));
     209           0 :                 *next = pdn;
     210           0 :                 return LDB_SUCCESS;
     211             :         }
     212             : 
     213      100566 :         ctx.guid = guid;
     214      100566 :         ctx.ldb = ldb;
     215      100566 :         ctx.mem_ctx = pdn;
     216      100566 :         ctx.ldap_oid = ldap_oid;
     217      100566 :         ctx.extra_part = extra_part;
     218      100566 :         ctx.partial_extra_part_length = partial_extra_part_length;
     219      100566 :         ctx.compare_extra_part = compare_extra_part;
     220      100566 :         ctx.err = 0;
     221             : 
     222      576028 :         BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
     223             :                                 *exact, *next);
     224             : 
     225      100566 :         if (ctx.err != 0) {
     226           0 :                 return ctx.err;
     227             :         }
     228      100354 :         return LDB_SUCCESS;
     229             : }

Generated by: LCOV version 1.14