173 lines
7.6 KiB
Diff
173 lines
7.6 KiB
Diff
From 1be46b322f1fe469cf3cc5e5a77a96b29f8beb7f Mon Sep 17 00:00:00 2001
|
|
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
Date: Wed, 1 Aug 2012 10:14:09 +0300
|
|
Subject: [PATCH 76/79] Handle exceptions when establishing trusts
|
|
|
|
Translate exceptions produced by DCERPC bindings when establishing trusts.
|
|
There are two types of errors that may be produced by DCERPC bindings:
|
|
- RuntimeError with a text (RuntimeError('NT_STATUS_OBJECT_NAME_NOT_FOUND')
|
|
- RuntimeError with a numeric code and 'friendly' message
|
|
|
|
Error codes could have two prefixes:
|
|
- NT error codes, start with NT_STATUS_ prefix
|
|
- Windows error codes, start with WERR_ prefix
|
|
|
|
Full list of errors is available in Samba source code:
|
|
libcli/util/ntstatus.h: NT_STATUS error codes
|
|
libcli/util/werror.h: Windows error codes
|
|
|
|
Majority of errors returned when dealing with trusts are of NT_STATUS type,
|
|
these also include all typical POSIX errors mapped to corresponding NT errors.
|
|
|
|
Unfortunately, in the textual RuntimeError case very little can be done to
|
|
get better clarification of the error. More error paths will need to be added
|
|
as they will be discovered -- DCERPC error messaging is complex.
|
|
|
|
https://fedorahosted.org/freeipa/ticket/2868
|
|
---
|
|
ipaserver/dcerpc.py | 75 ++++++++++++++++++++++++++++++++++++++++++-----------
|
|
1 file changed, 60 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
|
index 6b830f65b854b74fcf080b071212e7658f334adf..982e12b31a9525a35c5d921e6559471a7633e025 100644
|
|
--- a/ipaserver/dcerpc.py
|
|
+++ b/ipaserver/dcerpc.py
|
|
@@ -28,6 +28,7 @@ from ipalib.parameters import Enum
|
|
from ipalib import Command
|
|
from ipalib import errors
|
|
from ipapython import ipautil
|
|
+from ipapython.ipa_log_manager import *
|
|
from ipaserver.install import installutils
|
|
|
|
import os, string, struct, copy
|
|
@@ -49,6 +50,31 @@ The code in this module relies heavily on samba4-python package
|
|
and Samba4 python bindings.
|
|
""")
|
|
|
|
+access_denied_error = errors.ACIError(info='CIFS server denied your credentials')
|
|
+dcerpc_error_codes = {
|
|
+ -1073741823: errors.RemoteRetrieveError(reason='communication with CIFS server was unsuccessful'),
|
|
+ -1073741790: access_denied_error,
|
|
+ -1073741715: access_denied_error,
|
|
+ -1073741614: access_denied_error,
|
|
+ -1073741603: errors.ValidationError(name='AD domain controller', error='unsupported functional level'),
|
|
+}
|
|
+
|
|
+dcerpc_error_messages = {
|
|
+ "NT_STATUS_OBJECT_NAME_NOT_FOUND": errors.NotFound(reason='Cannot find specified domain or server name'),
|
|
+ "NT_STATUS_INVALID_PARAMETER_MIX": errors.RequirementError(name='At least the domain or IP address should be specified'),
|
|
+}
|
|
+
|
|
+def assess_dcerpc_exception(num=None,message=None):
|
|
+ """
|
|
+ Takes error returned by Samba bindings and converts it into
|
|
+ an IPA error class.
|
|
+ """
|
|
+ if num and num in dcerpc_error_codes:
|
|
+ return dcerpc_error_codes[num]
|
|
+ if message and message in dcerpc_error_messages:
|
|
+ return dcerpc_error_messages[message]
|
|
+ return errors.RemoteRetrieveError(reason='CIFS server communication error: code "%s", message "%s" (both may be "None")' % (num, message))
|
|
+
|
|
class ExtendedDNControl(_ldap.controls.RequestControl):
|
|
def __init__(self):
|
|
self.controlType = "1.2.840.113556.1.4.529"
|
|
@@ -151,8 +177,8 @@ class TrustDomainInstance(object):
|
|
try:
|
|
result = lsa.lsarpc(binding, self.parm, self.creds)
|
|
return result
|
|
- except:
|
|
- return None
|
|
+ except RuntimeError, (num, message):
|
|
+ raise assess_dcerpc_exception(num=num, message=message)
|
|
|
|
def __init_lsa_pipe(self, remote_host):
|
|
"""
|
|
@@ -168,13 +194,21 @@ class TrustDomainInstance(object):
|
|
if self._pipe:
|
|
return
|
|
|
|
+ attempts = 0
|
|
bindings = self.__gen_lsa_bindings(remote_host)
|
|
for binding in bindings:
|
|
- self._pipe = self.__gen_lsa_connection(binding)
|
|
- if self._pipe:
|
|
- break
|
|
+ try:
|
|
+ self._pipe = self.__gen_lsa_connection(binding)
|
|
+ if self._pipe:
|
|
+ break
|
|
+ except errors.ACIError, e:
|
|
+ attempts = attempts + 1
|
|
+
|
|
+ if self._pipe is None and attempts == len(bindings):
|
|
+ raise errors.ACIError(info='CIFS server %s denied your credentials' % (remote_host))
|
|
+
|
|
if self._pipe is None:
|
|
- raise errors.RequirementError(name='Working LSA pipe')
|
|
+ raise errors.RemoteRetrieveError(reason='Cannot establish LSA connection to %s. Is CIFS server running?' % (remote_host))
|
|
|
|
def __gen_lsa_bindings(self, remote_host):
|
|
"""
|
|
@@ -195,10 +229,14 @@ class TrustDomainInstance(object):
|
|
When retrieving DC information anonymously, we can't get SID of the domain
|
|
"""
|
|
netrc = net.Net(creds=self.creds, lp=self.parm)
|
|
- if discover_srv:
|
|
- result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
|
- else:
|
|
- result = netrc.finddc(address=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
|
+ try:
|
|
+ if discover_srv:
|
|
+ result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
|
+ else:
|
|
+ result = netrc.finddc(address=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
|
+ except RuntimeError, e:
|
|
+ raise assess_dcerpc_exception(message=str(e))
|
|
+
|
|
if not result:
|
|
return False
|
|
self.info['name'] = unicode(result.domain_name)
|
|
@@ -217,7 +255,7 @@ class TrustDomainInstance(object):
|
|
result = res['defaultNamingContext'][0]
|
|
self.info['dns_hostname'] = res['dnsHostName'][0]
|
|
except _ldap.LDAPError, e:
|
|
- print "LDAP error when connecting to %s: %s" % (unicode(result.pdc_name), str(e))
|
|
+ root_logger.error("LDAP error when connecting to %s: %s" % (unicode(result.pdc_name), str(e)))
|
|
|
|
if result:
|
|
self.info['sid'] = self.parse_naming_context(result)
|
|
@@ -232,8 +270,12 @@ class TrustDomainInstance(object):
|
|
|
|
objectAttribute = lsa.ObjectAttribute()
|
|
objectAttribute.sec_qos = lsa.QosInfo()
|
|
- self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED)
|
|
- result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_DNS)
|
|
+ try:
|
|
+ self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED)
|
|
+ result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_DNS)
|
|
+ except RuntimeError, (num, message):
|
|
+ raise assess_dcerpc_exception(num=num, message=message)
|
|
+
|
|
self.info['name'] = unicode(result.name.string)
|
|
self.info['dns_domain'] = unicode(result.dns_domain.string)
|
|
self.info['dns_forest'] = unicode(result.dns_forest.string)
|
|
@@ -315,9 +357,12 @@ class TrustDomainInstance(object):
|
|
dname.string = another_domain.info['dns_domain']
|
|
res = self._pipe.QueryTrustedDomainInfoByName(self._policy_handle, dname, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
|
|
self._pipe.DeleteTrustedDomain(self._policy_handle, res.info_ex.sid)
|
|
- except:
|
|
+ except RuntimeError, e:
|
|
pass
|
|
- self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE)
|
|
+ try:
|
|
+ self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE)
|
|
+ except RuntimeError, (num, message):
|
|
+ raise assess_dcerpc_exception(num=num, message=message)
|
|
|
|
class TrustDomainJoins(object):
|
|
def __init__(self, api):
|
|
--
|
|
1.7.11.2
|
|
|