|
|
b01884 |
From e5471e66c6a718ffa28433813b8a8d7896b16d9e Mon Sep 17 00:00:00 2001
|
|
|
b01884 |
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
|
b01884 |
Date: Mon, 7 Jan 2019 15:28:29 +0200
|
|
|
b01884 |
Subject: [PATCH] ipaserver/dcerpc: fix exclusion entry with a forest trust
|
|
|
b01884 |
domain info returned
|
|
|
b01884 |
|
|
|
b01884 |
When looking through the topology of a trusted forest, we should support
|
|
|
b01884 |
all types of forest trust records. Since Samba Python bindings parse the
|
|
|
b01884 |
data into a typed structure, a type of the record has to be taken into
|
|
|
b01884 |
account or there will be type mismatch when accessing elements of the
|
|
|
b01884 |
union:
|
|
|
b01884 |
|
|
|
b01884 |
typedef [switch_type(lsa_ForestTrustRecordType)] union {
|
|
|
b01884 |
[case(LSA_FOREST_TRUST_TOP_LEVEL_NAME)] lsa_StringLarge top_level_name;
|
|
|
b01884 |
[case(LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX)] lsa_StringLarge top_level_name_ex;
|
|
|
b01884 |
[case(LSA_FOREST_TRUST_DOMAIN_INFO)] lsa_ForestTrustDomainInfo domain_info;
|
|
|
b01884 |
[default] lsa_ForestTrustBinaryData data;
|
|
|
b01884 |
} lsa_ForestTrustData;
|
|
|
b01884 |
|
|
|
b01884 |
typedef struct {
|
|
|
b01884 |
lsa_ForestTrustRecordFlags flags;
|
|
|
b01884 |
lsa_ForestTrustRecordType type;
|
|
|
b01884 |
NTTIME_hyper time;
|
|
|
b01884 |
[switch_is(type)] lsa_ForestTrustData forest_trust_data;
|
|
|
b01884 |
} lsa_ForestTrustRecord;
|
|
|
b01884 |
|
|
|
b01884 |
typedef [public] struct {
|
|
|
b01884 |
[range(0,4000)] uint32 count;
|
|
|
b01884 |
[size_is(count)] lsa_ForestTrustRecord **entries;
|
|
|
b01884 |
} lsa_ForestTrustInformation;
|
|
|
b01884 |
|
|
|
b01884 |
Each entry in the lsa_ForestTrustInformation has forest_trust_data
|
|
|
b01884 |
member but its content depends on the value of a type member
|
|
|
b01884 |
(forest_trust_data is a union of all possible structures).
|
|
|
b01884 |
|
|
|
b01884 |
Previously we assumed only TLN or TLN exclusion record which were
|
|
|
b01884 |
of the same type (lsa_StringLarge). Access to forest_trust_data.string
|
|
|
b01884 |
fails when forest_trust_data's type is lsa_ForestTrustDomainInfo as it
|
|
|
b01884 |
has no string member.
|
|
|
b01884 |
|
|
|
b01884 |
Fix the code by properly accessing the dns_domain_name from the
|
|
|
b01884 |
lsa_ForestTrustDomainInfo structure.
|
|
|
b01884 |
|
|
|
b01884 |
Fixes: https://pagure.io/freeipa/issue/7828
|
|
|
b01884 |
Reviewed-By: Christian Heimes <cheimes@redhat.com>
|
|
|
b01884 |
---
|
|
|
b01884 |
ipaserver/dcerpc.py | 64 ++++++++++++++++++++++++++++++++++++++-------
|
|
|
b01884 |
1 file changed, 55 insertions(+), 9 deletions(-)
|
|
|
b01884 |
|
|
|
b01884 |
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
|
|
b01884 |
index 125493657..51a8e82e7 100644
|
|
|
b01884 |
--- a/ipaserver/dcerpc.py
|
|
|
b01884 |
+++ b/ipaserver/dcerpc.py
|
|
|
b01884 |
@@ -51,6 +51,7 @@ from samba.dcerpc import security, lsa, drsblobs, nbt, netlogon
|
|
|
b01884 |
from samba.ndr import ndr_pack, ndr_print
|
|
|
b01884 |
from samba import net
|
|
|
b01884 |
from samba import arcfour_encrypt
|
|
|
b01884 |
+from samba import ntstatus
|
|
|
b01884 |
import samba
|
|
|
b01884 |
|
|
|
b01884 |
import ldap as _ldap
|
|
|
b01884 |
@@ -1105,6 +1106,25 @@ class TrustDomainInstance(object):
|
|
|
b01884 |
original forest.
|
|
|
b01884 |
"""
|
|
|
b01884 |
|
|
|
b01884 |
+ def domain_name_from_ftinfo(ftinfo):
|
|
|
b01884 |
+ """
|
|
|
b01884 |
+ Returns a domain name string from a ForestTrustRecord
|
|
|
b01884 |
+
|
|
|
b01884 |
+ :param ftinfo: LSA ForestTrustRecord to parse
|
|
|
b01884 |
+ """
|
|
|
b01884 |
+ if ftinfo.type == lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
|
|
|
b01884 |
+ return ftinfo.forest_trust_data.dns_domain_name.string
|
|
|
b01884 |
+ elif ftinfo.type == lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
|
|
|
b01884 |
+ return ftinfo.forest_trust_data.string
|
|
|
b01884 |
+ elif ftinfo.type == lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
|
|
|
b01884 |
+ # We should ignore TLN exclusion record because it
|
|
|
b01884 |
+ # is already an exclusion so we aren't going to
|
|
|
b01884 |
+ # change anything here
|
|
|
b01884 |
+ return None
|
|
|
b01884 |
+ else:
|
|
|
b01884 |
+ # Ignore binary blobs we don't know about
|
|
|
b01884 |
+ return None
|
|
|
b01884 |
+
|
|
|
b01884 |
# List of entries for unsolved conflicts
|
|
|
b01884 |
result = []
|
|
|
b01884 |
|
|
|
b01884 |
@@ -1145,18 +1165,26 @@ class TrustDomainInstance(object):
|
|
|
b01884 |
e1.time = e.time
|
|
|
b01884 |
e1.forest_trust_data = e.forest_trust_data
|
|
|
b01884 |
|
|
|
b01884 |
+ # We either have a domain struct, a TLN name,
|
|
|
b01884 |
+ # or a TLN exclusion name in the list.
|
|
|
b01884 |
+ # The rest we should skip, those are binary blobs
|
|
|
b01884 |
+ dns_domain_name = domain_name_from_ftinfo(e)
|
|
|
b01884 |
+
|
|
|
b01884 |
# Search for a match in the topology of another domain
|
|
|
b01884 |
# if there is a match, we have to convert a record
|
|
|
b01884 |
# into a TLN exclusion to allow its routing to the
|
|
|
b01884 |
# another domain
|
|
|
b01884 |
for r in another_domain.ftinfo_records:
|
|
|
b01884 |
- if r['rec_name'] == e.forest_trust_data.string:
|
|
|
b01884 |
+ # r['rec_name'] cannot be None, thus we can ignore
|
|
|
b01884 |
+ # the case when dns_domain_name is None
|
|
|
b01884 |
+ if r['rec_name'] == dns_domain_name:
|
|
|
b01884 |
is_our_record = True
|
|
|
b01884 |
|
|
|
b01884 |
# Convert e1 into an exclusion record
|
|
|
b01884 |
e1.type = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
|
|
|
b01884 |
e1.flags = 0
|
|
|
b01884 |
e1.time = trust_timestamp
|
|
|
b01884 |
+ e1.forest_trust_data.string = dns_domain_name
|
|
|
b01884 |
break
|
|
|
b01884 |
entries.append(e1)
|
|
|
b01884 |
|
|
|
b01884 |
@@ -1180,11 +1208,29 @@ class TrustDomainInstance(object):
|
|
|
b01884 |
# Update the forest trust information now
|
|
|
b01884 |
ldname = lsa.StringLarge()
|
|
|
b01884 |
ldname.string = rec.name.string
|
|
|
b01884 |
- cninfo = self._pipe.lsaRSetForestTrustInformation(
|
|
|
b01884 |
- self._policy_handle,
|
|
|
b01884 |
- ldname,
|
|
|
b01884 |
- lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
|
|
|
b01884 |
- fti, 0)
|
|
|
b01884 |
+ cninfo = None
|
|
|
b01884 |
+ try:
|
|
|
b01884 |
+ cninfo = self._pipe.lsaRSetForestTrustInformation(
|
|
|
b01884 |
+ self._policy_handle,
|
|
|
b01884 |
+ ldname,
|
|
|
b01884 |
+ lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
|
|
|
b01884 |
+ fti, 0)
|
|
|
b01884 |
+ except samba.NTSTATUSError as error:
|
|
|
b01884 |
+ # Handle NT_STATUS_INVALID_PARAMETER separately
|
|
|
b01884 |
+ if ntstatus.NT_STATUS_INVALID_PARAMETER == error.args[0]:
|
|
|
b01884 |
+ result.append(rec)
|
|
|
b01884 |
+ logger.error("Unable to resolve conflict for "
|
|
|
b01884 |
+ "DNS domain %s in the forest %s "
|
|
|
b01884 |
+ "for in-forest domain %s. Trust cannot "
|
|
|
b01884 |
+ "be established unless this conflict "
|
|
|
b01884 |
+ "is fixed manually.",
|
|
|
b01884 |
+ another_domain.info['dns_domain'],
|
|
|
b01884 |
+ self.info['dns_domain'],
|
|
|
b01884 |
+ rec.name.string)
|
|
|
b01884 |
+ else:
|
|
|
b01884 |
+ raise assess_dcerpc_error(error)
|
|
|
b01884 |
+
|
|
|
b01884 |
+
|
|
|
b01884 |
if cninfo:
|
|
|
b01884 |
result.append(rec)
|
|
|
b01884 |
logger.error("When defining exception for DNS "
|
|
|
b01884 |
@@ -1213,9 +1259,9 @@ class TrustDomainInstance(object):
|
|
|
b01884 |
# Otherwise, raise TrustTopologyConflictError() exception
|
|
|
b01884 |
domains = [x.name.string for x in result]
|
|
|
b01884 |
raise errors.TrustTopologyConflictError(
|
|
|
b01884 |
- target=self.info['dns_domain'],
|
|
|
b01884 |
- conflict=another_domain.info['dns_domain'],
|
|
|
b01884 |
- domains=domains)
|
|
|
b01884 |
+ forest=self.info['dns_domain'],
|
|
|
b01884 |
+ conflict=another_domain.info['dns_domain'],
|
|
|
b01884 |
+ domains=domains)
|
|
|
b01884 |
|
|
|
b01884 |
|
|
|
b01884 |
|
|
|
b01884 |
--
|
|
|
b01884 |
2.20.1
|
|
|
b01884 |
|