s4/dsdb/common: clang: Fix access results in null pointer deref.
[amitay/samba.git] / source4 / dsdb / common / util_trusts.c
index 0e41803f7c553de7a929305bb4b5affa13af4225..b4571dca95700f04d5b46cc2e6006a2e6f1ddf58 100644 (file)
@@ -32,7 +32,8 @@
 #include "dsdb/common/util.h"
 #include "libds/common/flag_mapping.h"
 #include "../lib/util/dlinklist.h"
-#include "../lib/crypto/crypto.h"
+#include "lib/crypto/md4.h"
+#include "libcli/ldap/ldap_ndr.h"
 
 NTSTATUS dsdb_trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx,
                                const struct lsa_ForestTrustInformation *lfti,
@@ -73,7 +74,7 @@ NTSTATUS dsdb_trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx,
 
                ftr->flags = lftr->flags;
                ftr->timestamp = lftr->time;
-               ftr->type = lftr->type;
+               ftr->type = (enum ForestTrustInfoRecordType)lftr->type;
 
                switch (lftr->type) {
                case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
@@ -156,7 +157,7 @@ static NTSTATUS dsdb_trust_forest_record_to_lsa(TALLOC_CTX *mem_ctx,
 
        lftr->flags = ftr->flags;
        lftr->time = ftr->timestamp;
-       lftr->type = ftr->type;
+       lftr->type = (enum lsa_ForestTrustRecordType)ftr->type;
 
        switch (lftr->type) {
        case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
@@ -233,7 +234,7 @@ NTSTATUS dsdb_trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx,
        }
 
        lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation);
-       if (fti == NULL) {
+       if (lfti == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -381,7 +382,9 @@ static NTSTATUS dsdb_trust_parse_crossref_info(TALLOC_CTX *mem_ctx,
        const char *dns = NULL;
        const char *netbios = NULL;
        struct ldb_dn *nc_dn = NULL;
-       struct dom_sid sid = {};
+       struct dom_sid sid = {
+               .num_auths = 0,
+       };
        NTSTATUS status;
 
        *_tdo = NULL;
@@ -481,12 +484,6 @@ static NTSTATUS dsdb_trust_crossref_tdo_info(TALLOC_CTX *mem_ctx,
                *_trust_parent_tdo = NULL;
        }
 
-       domain_dn = ldb_get_default_basedn(sam_ctx);
-       if (domain_dn == NULL) {
-               TALLOC_FREE(frame);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
        partitions_dn = samdb_partitions_dn(sam_ctx, frame);
        if (partitions_dn == NULL) {
                TALLOC_FREE(frame);
@@ -626,11 +623,11 @@ static int dns_cmp(const char *s1, const char *s2)
        size_t l1 = 0;
        const char *p1 = NULL;
        size_t num_comp1 = 0;
-       uint16_t comp1[UINT8_MAX] = {};
+       uint16_t comp1[UINT8_MAX] = {0};
        size_t l2 = 0;
        const char *p2 = NULL;
        size_t num_comp2 = 0;
-       uint16_t comp2[UINT8_MAX] = {};
+       uint16_t comp2[UINT8_MAX] = {0};
        size_t i;
 
        if (s1 != NULL) {
@@ -657,7 +654,7 @@ static int dns_cmp(const char *s1, const char *s2)
                if (i == 0) {
                        p1 = s1;
 
-                       if (l1 == 0 && l1 >= UINT16_MAX) {
+                       if (l1 == 0 || l1 >= UINT16_MAX) {
                                /* just use one single component on overflow */
                                break;
                        }
@@ -687,7 +684,7 @@ static int dns_cmp(const char *s1, const char *s2)
                if (i == 0) {
                        p2 = s2;
 
-                       if (l2 == 0 && l2 >= UINT16_MAX) {
+                       if (l2 == 0 || l2 >= UINT16_MAX) {
                                /* just use one single component on overflow */
                                break;
                        }
@@ -833,6 +830,22 @@ static bool dsdb_trust_find_tln_ex_match(const struct lsa_ForestTrustInformation
        return false;
 }
 
+NTSTATUS dsdb_trust_local_tdo_info(TALLOC_CTX *mem_ctx,
+                                  struct ldb_context *sam_ctx,
+                                  struct lsa_TrustDomainInfoInfoEx **_tdo)
+{
+       struct ldb_dn *domain_dn = NULL;
+
+       domain_dn = ldb_get_default_basedn(sam_ctx);
+       if (domain_dn == NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       return dsdb_trust_crossref_tdo_info(mem_ctx, sam_ctx,
+                                           domain_dn, NULL,
+                                           _tdo, NULL, NULL);
+}
+
 NTSTATUS dsdb_trust_xref_tdo_info(TALLOC_CTX *mem_ctx,
                                  struct ldb_context *sam_ctx,
                                  struct lsa_TrustDomainInfoInfoEx **_tdo)
@@ -1000,8 +1013,12 @@ NTSTATUS dsdb_trust_xref_forest_info(TALLOC_CTX *mem_ctx,
                const char *dns = NULL;
                const char *netbios = NULL;
                struct ldb_dn *nc_dn = NULL;
-               struct dom_sid sid = {};
-               struct lsa_ForestTrustRecord e = {};
+               struct dom_sid sid = {
+                       .num_auths = 0,
+               };
+               struct lsa_ForestTrustRecord e = {
+                       .flags = 0,
+               };
                struct lsa_ForestTrustDomainInfo *d = NULL;
                struct lsa_StringLarge *t = NULL;
                bool match = false;
@@ -1075,7 +1092,9 @@ NTSTATUS dsdb_trust_xref_forest_info(TALLOC_CTX *mem_ctx,
        for (i=0; (tln_el != NULL) && i < tln_el->num_values; i++) {
                const struct ldb_val *v = &tln_el->values[i];
                const char *dns = (const char *)v->data;
-               struct lsa_ForestTrustRecord e = {};
+               struct lsa_ForestTrustRecord e = {
+                       .flags = 0,
+               };
                struct lsa_StringLarge *t = NULL;
                bool match = false;
                NTSTATUS status;
@@ -2026,7 +2045,9 @@ NTSTATUS dsdb_trust_merge_forest_info(TALLOC_CTX *mem_ctx,
         */
        for (ni = 0; ni < nfti->count; ni++) {
                const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
-               struct lsa_ForestTrustRecord tftr = {};
+               struct lsa_ForestTrustRecord tftr = {
+                       .flags = 0,
+               };
                const char *ndns = NULL;
                bool ignore_new = false;
                bool found_old = false;
@@ -2141,7 +2162,9 @@ NTSTATUS dsdb_trust_merge_forest_info(TALLOC_CTX *mem_ctx,
         */
        for (ni = 0; ni < nfti->count; ni++) {
                const struct lsa_ForestTrustRecord *nftr = nfti->entries[ni];
-               struct lsa_ForestTrustRecord tftr = {};
+               struct lsa_ForestTrustRecord tftr = {
+                       .flags = 0,
+               };
                const struct lsa_ForestTrustDomainInfo *nd = NULL;
                const char *ndns = NULL;
                const char *nnbt = NULL;
@@ -2567,19 +2590,89 @@ NTSTATUS dsdb_trust_search_tdo_by_type(struct ldb_context *sam_ctx,
        return NT_STATUS_OK;
 }
 
+NTSTATUS dsdb_trust_search_tdo_by_sid(struct ldb_context *sam_ctx,
+                                     const struct dom_sid *sid,
+                                     const char * const *attrs,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ldb_message **msg)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       int ret;
+       struct ldb_dn *system_dn = NULL;
+       char *encoded_sid = NULL;
+       char *filter = NULL;
+
+       *msg = NULL;
+
+       if (sid == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_INVALID_PARAMETER_MIX;
+       }
+
+       encoded_sid = ldap_encode_ndr_dom_sid(frame, sid);
+       if (encoded_sid == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
+       if (system_dn == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       filter = talloc_asprintf(frame,
+                               "(&"
+                                 "(objectClass=trustedDomain)"
+                                 "(securityIdentifier=%s)"
+                               ")",
+                               encoded_sid);
+       if (filter == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = dsdb_search_one(sam_ctx, mem_ctx, msg,
+                             system_dn,
+                             LDB_SCOPE_ONELEVEL, attrs,
+                             DSDB_SEARCH_NO_GLOBAL_CATALOG,
+                             "%s", filter);
+       if (ret != LDB_SUCCESS) {
+               NTSTATUS status = dsdb_ldb_err_to_ntstatus(ret);
+               DEBUG(3, ("Failed to search for %s: %s - %s\n",
+                         filter, nt_errstr(status), ldb_errstring(sam_ctx)));
+               TALLOC_FREE(frame);
+               return status;
+       }
+
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
 NTSTATUS dsdb_trust_get_incoming_passwords(struct ldb_message *msg,
                                           TALLOC_CTX *mem_ctx,
                                           struct samr_Password **_current,
                                           struct samr_Password **_previous)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-       struct samr_Password __current = {};
-       struct samr_Password __previous = {};
+       struct samr_Password __current = {
+               .hash = {0},
+       };
+       struct samr_Password __previous = {
+               .hash = {0},
+       };
        struct samr_Password *current = NULL;
        struct samr_Password *previous = NULL;
        const struct ldb_val *blob = NULL;
        enum ndr_err_code ndr_err;
-       struct trustAuthInOutBlob incoming = {};
+       struct trustAuthInOutBlob incoming = {
+               .count = 0,
+       };
        uint32_t i;
 
        if (_current != NULL) {
@@ -2671,7 +2764,9 @@ NTSTATUS dsdb_trust_get_incoming_passwords(struct ldb_message *msg,
        if (_previous != NULL) {
                *_previous = talloc(mem_ctx, struct samr_Password);
                if (*_previous == NULL) {
-                       TALLOC_FREE(*_current);
+                       if (_current != NULL) {
+                               TALLOC_FREE(*_current);
+                       }
                        TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
@@ -2755,6 +2850,9 @@ struct dsdb_trust_routing_domain {
        struct dsdb_trust_routing_domain *prev, *next;
 
        struct lsa_TrustDomainInfoInfoEx *tdo;
+
+       struct lsa_ForestTrustDomainInfo di;
+
        struct lsa_ForestTrustInformation *fti;
 };
 
@@ -2814,6 +2912,18 @@ NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx,
                return status;
        }
 
+       /*
+        * d->tdo should not be NULL of status above is 'NT_STATUS_OK'
+        * check is needed to satisfy clang static checker
+       */
+       if (d->tdo == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+       d->di.domain_sid = d->tdo->sid;
+       d->di.netbios_domain_name.string = d->tdo->netbios_name.string;
+       d->di.dns_domain_name.string = d->tdo->domain_name.string;
+
        if (root_trust_tdo != NULL) {
                root_direction_tdo = root_trust_tdo;
        } else if (trust_parent_tdo != NULL) {
@@ -2856,7 +2966,11 @@ NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx,
                        return status;
                }
 
-               DLIST_ADD_END(table->domains, d, NULL);
+               d->di.domain_sid = d->tdo->sid;
+               d->di.netbios_domain_name.string = d->tdo->netbios_name.string;
+               d->di.dns_domain_name.string = d->tdo->domain_name.string;
+
+               DLIST_ADD_END(table->domains, d);
 
                if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
                        struct ForestTrustInfo *fti = NULL;
@@ -3130,3 +3244,214 @@ const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_routing_by_name(
 
        return NULL;
 }
+
+const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_sid(
+               const struct dsdb_trust_routing_table *table,
+               const struct dom_sid *sid,
+               const struct lsa_ForestTrustDomainInfo **pdi)
+{
+       const struct dsdb_trust_routing_domain *d = NULL;
+
+       if (pdi != NULL) {
+               *pdi = NULL;
+       }
+
+       if (sid == NULL) {
+               return NULL;
+       }
+
+       for (d = table->domains; d != NULL; d = d->next) {
+               bool transitive = false;
+               uint32_t i;
+
+               if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
+                       transitive = true;
+               }
+
+               if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
+                       transitive = true;
+               }
+
+               if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
+                       transitive = false;
+               }
+
+               if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
+                       transitive = false;
+               }
+
+               if (!transitive || d->fti == NULL) {
+                       bool match = false;
+
+                       match = dom_sid_equal(d->di.domain_sid, sid);
+                       if (match) {
+                               /*
+                                * exact match, it's the domain itself.
+                                */
+                               if (pdi != NULL) {
+                                       *pdi = &d->di;
+                               }
+                               return d->tdo;
+                       }
+                       continue;
+               }
+
+               for (i = 0; i < d->fti->count; i++ ) {
+                       const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
+                       const struct lsa_ForestTrustDomainInfo *di = NULL;
+                       const struct dom_sid *fti_sid = NULL;
+                       bool match = false;
+
+                       if (f == NULL) {
+                               /* broken record */
+                               continue;
+                       }
+
+                       if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
+                               continue;
+                       }
+
+                       if (f->flags & LSA_SID_DISABLED_MASK) {
+                               /*
+                                * any flag disables the entry.
+                                */
+                               continue;
+                       }
+
+                       di = &f->forest_trust_data.domain_info;
+                       fti_sid = di->domain_sid;
+                       if (fti_sid == NULL) {
+                               /* broken record */
+                               continue;
+                       }
+
+                       match = dom_sid_equal(fti_sid, sid);
+                       if (match) {
+                               /*
+                                * exact match, it's a domain in the forest.
+                                */
+                               if (pdi != NULL) {
+                                       *pdi = di;
+                               }
+                               return d->tdo;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_name(
+               const struct dsdb_trust_routing_table *table,
+               const char *name,
+               const struct lsa_ForestTrustDomainInfo **pdi)
+{
+       const struct dsdb_trust_routing_domain *d = NULL;
+
+       if (pdi != NULL) {
+               *pdi = NULL;
+       }
+
+       if (name == NULL) {
+               return NULL;
+       }
+
+       for (d = table->domains; d != NULL; d = d->next) {
+               bool transitive = false;
+               uint32_t i;
+
+               if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
+                       transitive = true;
+               }
+
+               if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
+                       transitive = true;
+               }
+
+               if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
+                       transitive = false;
+               }
+
+               if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
+                       transitive = false;
+               }
+
+               if (!transitive || d->fti == NULL) {
+                       bool match = false;
+
+                       match = strequal_m(d->di.netbios_domain_name.string,
+                                          name);
+                       if (match) {
+                               /*
+                                * exact match for netbios name,
+                                * it's the domain itself.
+                                */
+                               if (pdi != NULL) {
+                                       *pdi = &d->di;
+                               }
+                               return d->tdo;
+                       }
+                       match = strequal_m(d->di.dns_domain_name.string,
+                                          name);
+                       if (match) {
+                               /*
+                                * exact match for dns name,
+                                * it's the domain itself.
+                                */
+                               if (pdi != NULL) {
+                                       *pdi = &d->di;
+                               }
+                               return d->tdo;
+                       }
+                       continue;
+               }
+
+               for (i = 0; i < d->fti->count; i++ ) {
+                       const struct lsa_ForestTrustRecord *f = d->fti->entries[i];
+                       const struct lsa_ForestTrustDomainInfo *di = NULL;
+                       bool match = false;
+
+                       if (f == NULL) {
+                               /* broken record */
+                               continue;
+                       }
+
+                       if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) {
+                               continue;
+                       }
+                       di = &f->forest_trust_data.domain_info;
+
+                       if (!(f->flags & LSA_NB_DISABLED_MASK)) {
+                               match = strequal_m(di->netbios_domain_name.string,
+                                                  name);
+                               if (match) {
+                                       /*
+                                        * exact match for netbios name,
+                                        * it's a domain in the forest.
+                                        */
+                                       if (pdi != NULL) {
+                                               *pdi = di;
+                                       }
+                                       return d->tdo;
+                               }
+                       }
+
+                       if (!(f->flags & LSA_TLN_DISABLED_MASK)) {
+                               match = strequal_m(di->dns_domain_name.string,
+                                                  name);
+                               if (match) {
+                                       /*
+                                        * exact match for dns name,
+                                        * it's a domain in the forest.
+                                        */
+                                       if (pdi != NULL) {
+                                               *pdi = di;
+                                       }
+                                       return d->tdo;
+                               }
+                       }
+               }
+       }
+
+       return NULL;
+}