|
|
c58629 |
From a4e9e8f368c8a61d539e9da26e4a16a6234c138f Mon Sep 17 00:00:00 2001
|
|
|
c58629 |
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
|
c58629 |
Date: Fri, 17 Nov 2017 17:19:25 +0200
|
|
|
c58629 |
Subject: [PATCH] trust: detect and error out when non-AD trust with IPA domain
|
|
|
c58629 |
name exists
|
|
|
c58629 |
|
|
|
c58629 |
Quite often users choose wrong type of trust on Active Directory side
|
|
|
c58629 |
when setting up a trust to freeIPA. The trust type supported by freeIPA
|
|
|
c58629 |
is just a normal forest trust to another Active Directory. However,
|
|
|
c58629 |
some people follow old internet recipes that force using a trust to MIT
|
|
|
c58629 |
Kerberos realm.
|
|
|
c58629 |
|
|
|
c58629 |
This is a wrong type of trust. Unfortunately, when someone used MIT
|
|
|
c58629 |
Kerberos realm trust, there is no way to programmatically remote the
|
|
|
c58629 |
trust from freeIPA side. As result, we have to detect such situation and
|
|
|
c58629 |
report an error.
|
|
|
c58629 |
|
|
|
c58629 |
To do proper reporting, we need reuse some constants and trust type
|
|
|
c58629 |
names we use in IPA CLI/Web UI. These common components were moved to
|
|
|
c58629 |
a separate ipaserver/dcerpc_common.py module that is imported by both
|
|
|
c58629 |
ipaserver/plugins/trust.py and ipaserver/dcerpc.py.
|
|
|
c58629 |
|
|
|
c58629 |
Fixes https://pagure.io/freeipa/issue/7264
|
|
|
c58629 |
|
|
|
c58629 |
Reviewed-By: Christian Heimes <cheimes@redhat.com>
|
|
|
c58629 |
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
|
|
|
c58629 |
---
|
|
|
c58629 |
ipaserver/dcerpc.py | 37 +++++++++++++++--------
|
|
|
c58629 |
ipaserver/dcerpc_common.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
c58629 |
ipaserver/plugins/trust.py | 65 ++++++++++-------------------------------
|
|
|
c58629 |
3 files changed, 113 insertions(+), 62 deletions(-)
|
|
|
c58629 |
create mode 100644 ipaserver/dcerpc_common.py
|
|
|
c58629 |
|
|
|
c58629 |
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
|
|
c58629 |
index aa63cd9db0a1d47b5309cc6bed2ff7584760a39d..ac1b2a34784df491a3851aa21bbadbec2297241c 100644
|
|
|
c58629 |
--- a/ipaserver/dcerpc.py
|
|
|
c58629 |
+++ b/ipaserver/dcerpc.py
|
|
|
c58629 |
@@ -31,6 +31,10 @@ from ipapython import ipautil
|
|
|
c58629 |
from ipapython.ipa_log_manager import root_logger
|
|
|
c58629 |
from ipapython.dn import DN
|
|
|
c58629 |
from ipaserver.install import installutils
|
|
|
c58629 |
+from ipaserver.dcerpc_common import (TRUST_BIDIRECTIONAL,
|
|
|
c58629 |
+ TRUST_JOIN_EXTERNAL,
|
|
|
c58629 |
+ trust_type_string)
|
|
|
c58629 |
+
|
|
|
c58629 |
from ipalib.util import normalize_name
|
|
|
c58629 |
|
|
|
c58629 |
import os
|
|
|
c58629 |
@@ -77,15 +81,6 @@ The code in this module relies heavily on samba4-python package
|
|
|
c58629 |
and Samba4 python bindings.
|
|
|
c58629 |
""")
|
|
|
c58629 |
|
|
|
c58629 |
-# Both constants can be used as masks against trust direction
|
|
|
c58629 |
-# because bi-directional has two lower bits set.
|
|
|
c58629 |
-TRUST_ONEWAY = 1
|
|
|
c58629 |
-TRUST_BIDIRECTIONAL = 3
|
|
|
c58629 |
-
|
|
|
c58629 |
-# Trust join behavior
|
|
|
c58629 |
-# External trust -- allow creating trust to a non-root domain in the forest
|
|
|
c58629 |
-TRUST_JOIN_EXTERNAL = 1
|
|
|
c58629 |
-
|
|
|
c58629 |
|
|
|
c58629 |
def is_sid_valid(sid):
|
|
|
c58629 |
try:
|
|
|
c58629 |
@@ -151,6 +146,7 @@ pysss_type_key_translation_dict = {
|
|
|
c58629 |
pysss_nss_idmap.ID_BOTH: 'both',
|
|
|
c58629 |
}
|
|
|
c58629 |
|
|
|
c58629 |
+
|
|
|
c58629 |
class TrustTopologyConflictSolved(Exception):
|
|
|
c58629 |
"""
|
|
|
c58629 |
Internal trust error: raised when previously detected
|
|
|
c58629 |
@@ -1254,9 +1250,26 @@ class TrustDomainInstance(object):
|
|
|
c58629 |
dname = lsa.String()
|
|
|
c58629 |
dname.string = another_domain.info['dns_domain']
|
|
|
c58629 |
res = self._pipe.QueryTrustedDomainInfoByName(
|
|
|
c58629 |
- self._policy_handle,
|
|
|
c58629 |
- dname,
|
|
|
c58629 |
- lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
|
|
|
c58629 |
+ self._policy_handle,
|
|
|
c58629 |
+ dname,
|
|
|
c58629 |
+ lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO
|
|
|
c58629 |
+ )
|
|
|
c58629 |
+ if res.info_ex.trust_type != lsa.LSA_TRUST_TYPE_UPLEVEL:
|
|
|
c58629 |
+ msg = _('There is already a trust to {ipa_domain} with '
|
|
|
c58629 |
+ 'unsupported type {trust_type}. Please remove '
|
|
|
c58629 |
+ 'it manually on AD DC side.')
|
|
|
c58629 |
+ ttype = trust_type_string(
|
|
|
c58629 |
+ res.info_ex.trust_type, res.info_ex.trust_attributes
|
|
|
c58629 |
+ )
|
|
|
c58629 |
+ err = unicode(msg).format(
|
|
|
c58629 |
+ ipa_domain=another_domain.info['dns_domain'],
|
|
|
c58629 |
+ trust_type=ttype)
|
|
|
c58629 |
+
|
|
|
c58629 |
+ raise errors.ValidationError(
|
|
|
c58629 |
+ name=_('AD domain controller'),
|
|
|
c58629 |
+ error=err
|
|
|
c58629 |
+ )
|
|
|
c58629 |
+
|
|
|
c58629 |
self._pipe.DeleteTrustedDomain(self._policy_handle,
|
|
|
c58629 |
res.info_ex.sid)
|
|
|
c58629 |
except RuntimeError as e:
|
|
|
c58629 |
diff --git a/ipaserver/dcerpc_common.py b/ipaserver/dcerpc_common.py
|
|
|
c58629 |
new file mode 100644
|
|
|
c58629 |
index 0000000000000000000000000000000000000000..526b025e3282c8a556088eb2ed1ba467b889b86c
|
|
|
c58629 |
--- /dev/null
|
|
|
c58629 |
+++ b/ipaserver/dcerpc_common.py
|
|
|
c58629 |
@@ -0,0 +1,73 @@
|
|
|
c58629 |
+import six
|
|
|
c58629 |
+from ipalib import _
|
|
|
c58629 |
+if six.PY3:
|
|
|
c58629 |
+ unicode = six.text_type
|
|
|
c58629 |
+
|
|
|
c58629 |
+# Both constants can be used as masks against trust direction
|
|
|
c58629 |
+# because bi-directional has two lower bits set.
|
|
|
c58629 |
+TRUST_ONEWAY = 1
|
|
|
c58629 |
+TRUST_BIDIRECTIONAL = 3
|
|
|
c58629 |
+
|
|
|
c58629 |
+# Trust join behavior
|
|
|
c58629 |
+# External trust -- allow creating trust to a non-root domain in the forest
|
|
|
c58629 |
+TRUST_JOIN_EXTERNAL = 1
|
|
|
c58629 |
+
|
|
|
c58629 |
+# We don't want to import any of Samba Python code here just for constants
|
|
|
c58629 |
+# Since these constants set in MS-ADTS, we can rely on their stability
|
|
|
c58629 |
+LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001
|
|
|
c58629 |
+
|
|
|
c58629 |
+_trust_direction_dict = {
|
|
|
c58629 |
+ 1: _('Trusting forest'),
|
|
|
c58629 |
+ 2: _('Trusted forest'),
|
|
|
c58629 |
+ 3: _('Two-way trust')
|
|
|
c58629 |
+}
|
|
|
c58629 |
+
|
|
|
c58629 |
+_trust_status_dict = {
|
|
|
c58629 |
+ True: _('Established and verified'),
|
|
|
c58629 |
+ False: _('Waiting for confirmation by remote side')
|
|
|
c58629 |
+}
|
|
|
c58629 |
+
|
|
|
c58629 |
+_trust_type_dict_unknown = _('Unknown')
|
|
|
c58629 |
+
|
|
|
c58629 |
+# Trust type is a combination of ipanttrusttype and ipanttrustattributes
|
|
|
c58629 |
+# We shift trust attributes by 3 bits to left so bit 0 becomes bit 3 and
|
|
|
c58629 |
+# 2+(1 << 3) becomes 10.
|
|
|
c58629 |
+_trust_type_dict = {
|
|
|
c58629 |
+ 1: _('Non-Active Directory domain'),
|
|
|
c58629 |
+ 2: _('Active Directory domain'),
|
|
|
c58629 |
+ 3: _('RFC4120-compliant Kerberos realm'),
|
|
|
c58629 |
+ 10: _('Non-transitive external trust to a domain in '
|
|
|
c58629 |
+ 'another Active Directory forest'),
|
|
|
c58629 |
+ 11: _('Non-transitive external trust to an RFC4120-'
|
|
|
c58629 |
+ 'compliant Kerberos realm')
|
|
|
c58629 |
+}
|
|
|
c58629 |
+
|
|
|
c58629 |
+
|
|
|
c58629 |
+def trust_type_string(level, attrs):
|
|
|
c58629 |
+ """
|
|
|
c58629 |
+ Returns a string representing a type of the trust.
|
|
|
c58629 |
+ The original field is an enum:
|
|
|
c58629 |
+ LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001,
|
|
|
c58629 |
+ LSA_TRUST_TYPE_UPLEVEL = 0x00000002,
|
|
|
c58629 |
+ LSA_TRUST_TYPE_MIT = 0x00000003
|
|
|
c58629 |
+ """
|
|
|
c58629 |
+ transitive = int(attrs) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
|
|
|
c58629 |
+ string = _trust_type_dict.get(int(level) | (transitive << 3),
|
|
|
c58629 |
+ _trust_type_dict_unknown)
|
|
|
c58629 |
+ return unicode(string)
|
|
|
c58629 |
+
|
|
|
c58629 |
+
|
|
|
c58629 |
+def trust_direction_string(level):
|
|
|
c58629 |
+ """
|
|
|
c58629 |
+ Returns a string representing a direction of the trust.
|
|
|
c58629 |
+ The original field is a bitmask taking two bits in use
|
|
|
c58629 |
+ LSA_TRUST_DIRECTION_INBOUND = 0x00000001,
|
|
|
c58629 |
+ LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002
|
|
|
c58629 |
+ """
|
|
|
c58629 |
+ string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
|
|
|
c58629 |
+ return unicode(string)
|
|
|
c58629 |
+
|
|
|
c58629 |
+
|
|
|
c58629 |
+def trust_status_string(level):
|
|
|
c58629 |
+ string = _trust_status_dict.get(level, _trust_type_dict_unknown)
|
|
|
c58629 |
+ return unicode(string)
|
|
|
c58629 |
diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
|
|
|
c58629 |
index d0bbfbc47ca65c9c5229685fc9d202c293fe41cd..ecc5fa0b22f94de05cc5282758be093f0cfca13f 100644
|
|
|
c58629 |
--- a/ipaserver/plugins/trust.py
|
|
|
c58629 |
+++ b/ipaserver/plugins/trust.py
|
|
|
c58629 |
@@ -44,6 +44,13 @@ from ipalib import errors
|
|
|
c58629 |
from ipalib import output
|
|
|
c58629 |
from ldap import SCOPE_SUBTREE
|
|
|
c58629 |
from time import sleep
|
|
|
c58629 |
+from ipaserver.dcerpc_common import (TRUST_ONEWAY,
|
|
|
c58629 |
+ TRUST_BIDIRECTIONAL,
|
|
|
c58629 |
+ TRUST_JOIN_EXTERNAL,
|
|
|
c58629 |
+ LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE,
|
|
|
c58629 |
+ trust_type_string,
|
|
|
c58629 |
+ trust_direction_string,
|
|
|
c58629 |
+ trust_status_string)
|
|
|
c58629 |
|
|
|
c58629 |
if six.PY3:
|
|
|
c58629 |
unicode = str
|
|
|
c58629 |
@@ -63,9 +70,6 @@ except Exception as e:
|
|
|
c58629 |
if api.env.in_server and api.env.context in ['lite', 'server']:
|
|
|
c58629 |
try:
|
|
|
c58629 |
import ipaserver.dcerpc
|
|
|
c58629 |
- from ipaserver.dcerpc import (TRUST_ONEWAY,
|
|
|
c58629 |
- TRUST_BIDIRECTIONAL,
|
|
|
c58629 |
- TRUST_JOIN_EXTERNAL)
|
|
|
c58629 |
import dbus
|
|
|
c58629 |
import dbus.mainloop.glib
|
|
|
c58629 |
_bindings_installed = True
|
|
|
c58629 |
@@ -157,28 +161,14 @@ particular type.
|
|
|
c58629 |
|
|
|
c58629 |
register = Registry()
|
|
|
c58629 |
|
|
|
c58629 |
-# Trust type is a combination of ipanttrusttype and ipanttrustattributes
|
|
|
c58629 |
-# We shift trust attributes by 3 bits to left so bit 0 becomes bit 3 and
|
|
|
c58629 |
-# 2+(1 << 3) becomes 10.
|
|
|
c58629 |
-_trust_type_dict = {1 : _('Non-Active Directory domain'),
|
|
|
c58629 |
- 2 : _('Active Directory domain'),
|
|
|
c58629 |
- 3 : _('RFC4120-compliant Kerberos realm'),
|
|
|
c58629 |
- 10: _('Non-transitive external trust to a domain in another Active Directory forest')}
|
|
|
c58629 |
-
|
|
|
c58629 |
-_trust_direction_dict = {1 : _('Trusting forest'),
|
|
|
c58629 |
- 2 : _('Trusted forest'),
|
|
|
c58629 |
- 3 : _('Two-way trust')}
|
|
|
c58629 |
-_trust_status_dict = {True : _('Established and verified'),
|
|
|
c58629 |
- False : _('Waiting for confirmation by remote side')}
|
|
|
c58629 |
-_trust_type_dict_unknown = _('Unknown')
|
|
|
c58629 |
-
|
|
|
c58629 |
-_trust_type_option = StrEnum('trust_type',
|
|
|
c58629 |
- cli_name='type',
|
|
|
c58629 |
- label=_('Trust type (ad for Active Directory, default)'),
|
|
|
c58629 |
- values=(u'ad',),
|
|
|
c58629 |
- default=u'ad',
|
|
|
c58629 |
- autofill=True,
|
|
|
c58629 |
- )
|
|
|
c58629 |
+_trust_type_option = StrEnum(
|
|
|
c58629 |
+ 'trust_type',
|
|
|
c58629 |
+ cli_name='type',
|
|
|
c58629 |
+ label=_('Trust type (ad for Active Directory, default)'),
|
|
|
c58629 |
+ values=(u'ad',),
|
|
|
c58629 |
+ default=u'ad',
|
|
|
c58629 |
+ autofill=True,
|
|
|
c58629 |
+ )
|
|
|
c58629 |
|
|
|
c58629 |
DEFAULT_RANGE_SIZE = 200000
|
|
|
c58629 |
|
|
|
c58629 |
@@ -187,31 +177,6 @@ DBUS_IFACE_TRUST = 'com.redhat.idm.trust'
|
|
|
c58629 |
CRED_STYLE_SAMBA = 1
|
|
|
c58629 |
CRED_STYLE_KERBEROS = 2
|
|
|
c58629 |
|
|
|
c58629 |
-LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001
|
|
|
c58629 |
-
|
|
|
c58629 |
-def trust_type_string(level, attrs):
|
|
|
c58629 |
- """
|
|
|
c58629 |
- Returns a string representing a type of the trust. The original field is an enum:
|
|
|
c58629 |
- LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001,
|
|
|
c58629 |
- LSA_TRUST_TYPE_UPLEVEL = 0x00000002,
|
|
|
c58629 |
- LSA_TRUST_TYPE_MIT = 0x00000003
|
|
|
c58629 |
- """
|
|
|
c58629 |
- transitive = int(attrs) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
|
|
|
c58629 |
- string = _trust_type_dict.get(int(level) | (transitive << 3), _trust_type_dict_unknown)
|
|
|
c58629 |
- return unicode(string)
|
|
|
c58629 |
-
|
|
|
c58629 |
-def trust_direction_string(level):
|
|
|
c58629 |
- """
|
|
|
c58629 |
- Returns a string representing a direction of the trust. The original field is a bitmask taking two bits in use
|
|
|
c58629 |
- LSA_TRUST_DIRECTION_INBOUND = 0x00000001,
|
|
|
c58629 |
- LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002
|
|
|
c58629 |
- """
|
|
|
c58629 |
- string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
|
|
|
c58629 |
- return unicode(string)
|
|
|
c58629 |
-
|
|
|
c58629 |
-def trust_status_string(level):
|
|
|
c58629 |
- string = _trust_status_dict.get(level, _trust_type_dict_unknown)
|
|
|
c58629 |
- return unicode(string)
|
|
|
c58629 |
|
|
|
c58629 |
def make_trust_dn(env, trust_type, dn):
|
|
|
c58629 |
assert isinstance(dn, DN)
|
|
|
c58629 |
--
|
|
|
c58629 |
2.13.6
|
|
|
c58629 |
|