mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 16:10:02 -06:00
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
This commit is contained in:
parent
9bfa905e72
commit
1be46b322f
@ -28,6 +28,7 @@ from ipalib.parameters import Enum
|
|||||||
from ipalib import Command
|
from ipalib import Command
|
||||||
from ipalib import errors
|
from ipalib import errors
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
|
from ipapython.ipa_log_manager import *
|
||||||
from ipaserver.install import installutils
|
from ipaserver.install import installutils
|
||||||
|
|
||||||
import os, string, struct, copy
|
import os, string, struct, copy
|
||||||
@ -49,6 +50,31 @@ The code in this module relies heavily on samba4-python package
|
|||||||
and Samba4 python bindings.
|
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):
|
class ExtendedDNControl(_ldap.controls.RequestControl):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.controlType = "1.2.840.113556.1.4.529"
|
self.controlType = "1.2.840.113556.1.4.529"
|
||||||
@ -151,8 +177,8 @@ class TrustDomainInstance(object):
|
|||||||
try:
|
try:
|
||||||
result = lsa.lsarpc(binding, self.parm, self.creds)
|
result = lsa.lsarpc(binding, self.parm, self.creds)
|
||||||
return result
|
return result
|
||||||
except:
|
except RuntimeError, (num, message):
|
||||||
return None
|
raise assess_dcerpc_exception(num=num, message=message)
|
||||||
|
|
||||||
def __init_lsa_pipe(self, remote_host):
|
def __init_lsa_pipe(self, remote_host):
|
||||||
"""
|
"""
|
||||||
@ -168,13 +194,21 @@ class TrustDomainInstance(object):
|
|||||||
if self._pipe:
|
if self._pipe:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
attempts = 0
|
||||||
bindings = self.__gen_lsa_bindings(remote_host)
|
bindings = self.__gen_lsa_bindings(remote_host)
|
||||||
for binding in bindings:
|
for binding in bindings:
|
||||||
|
try:
|
||||||
self._pipe = self.__gen_lsa_connection(binding)
|
self._pipe = self.__gen_lsa_connection(binding)
|
||||||
if self._pipe:
|
if self._pipe:
|
||||||
break
|
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:
|
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):
|
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
|
When retrieving DC information anonymously, we can't get SID of the domain
|
||||||
"""
|
"""
|
||||||
netrc = net.Net(creds=self.creds, lp=self.parm)
|
netrc = net.Net(creds=self.creds, lp=self.parm)
|
||||||
|
try:
|
||||||
if discover_srv:
|
if discover_srv:
|
||||||
result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
||||||
else:
|
else:
|
||||||
result = netrc.finddc(address=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
|
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:
|
if not result:
|
||||||
return False
|
return False
|
||||||
self.info['name'] = unicode(result.domain_name)
|
self.info['name'] = unicode(result.domain_name)
|
||||||
@ -217,7 +255,7 @@ class TrustDomainInstance(object):
|
|||||||
result = res['defaultNamingContext'][0]
|
result = res['defaultNamingContext'][0]
|
||||||
self.info['dns_hostname'] = res['dnsHostName'][0]
|
self.info['dns_hostname'] = res['dnsHostName'][0]
|
||||||
except _ldap.LDAPError, e:
|
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:
|
if result:
|
||||||
self.info['sid'] = self.parse_naming_context(result)
|
self.info['sid'] = self.parse_naming_context(result)
|
||||||
@ -232,8 +270,12 @@ class TrustDomainInstance(object):
|
|||||||
|
|
||||||
objectAttribute = lsa.ObjectAttribute()
|
objectAttribute = lsa.ObjectAttribute()
|
||||||
objectAttribute.sec_qos = lsa.QosInfo()
|
objectAttribute.sec_qos = lsa.QosInfo()
|
||||||
|
try:
|
||||||
self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED)
|
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)
|
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['name'] = unicode(result.name.string)
|
||||||
self.info['dns_domain'] = unicode(result.dns_domain.string)
|
self.info['dns_domain'] = unicode(result.dns_domain.string)
|
||||||
self.info['dns_forest'] = unicode(result.dns_forest.string)
|
self.info['dns_forest'] = unicode(result.dns_forest.string)
|
||||||
@ -315,9 +357,12 @@ class TrustDomainInstance(object):
|
|||||||
dname.string = another_domain.info['dns_domain']
|
dname.string = another_domain.info['dns_domain']
|
||||||
res = self._pipe.QueryTrustedDomainInfoByName(self._policy_handle, dname, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
|
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)
|
self._pipe.DeleteTrustedDomain(self._policy_handle, res.info_ex.sid)
|
||||||
except:
|
except RuntimeError, e:
|
||||||
pass
|
pass
|
||||||
|
try:
|
||||||
self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE)
|
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):
|
class TrustDomainJoins(object):
|
||||||
def __init__(self, api):
|
def __init__(self, api):
|
||||||
|
Loading…
Reference in New Issue
Block a user