From daf266a28ec3720d054aafddad3274ad8740cd46 Mon Sep 17 00:00:00 2001 From: Florian Best Date: Fri, 10 May 2019 13:48:51 +0200 Subject: [PATCH] Ensure self._l is not left in an only partially initialized state If the timeout is reached and a reconnection was not successfull in that time, a ldap.SERVER_DOWN exception is raised. If later on, when it's assured that the ldap server is running again, the connection is used again, the reconnection is not performed and the ldap connection in an incosistent unbind state. Traceback (most recent call last): File "reproduce.py", line 23, in _ = lo.search_s('l=school,l=dev', ldap.SCOPE_SUBTREE, '(uid=Administrator)') File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 597, in search_s return self.search_ext_s(base,scope,filterstr,attrlist,attrsonly,None,None,timeout=self.timeout) File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 997, in search_ext_s return self._apply_method_s(SimpleLDAPObject.search_ext_s,*args,**kwargs) File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 935, in _apply_method_s return func(self,*args,**kwargs) File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 591, in search_ext_s return self.result(msgid,all=1,timeout=timeout)[1] File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 503, in result resp_type, resp_data, resp_msgid = self.result2(msgid,all,timeout) File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 507, in result2 resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all,timeout) File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 514, in result3 resp_ctrl_classes=resp_ctrl_classes File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 521, in result4 ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop) File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 106, in _ldap_call result = func(*args,**kwargs) ldap.INSUFFICIENT_ACCESS: {'desc': 'Insufficient access'} --- Lib/ldap/ldapobject.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index f7443fa..a92b088 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -1166,14 +1166,18 @@ def reconnect(self,uri,retry_max=1,retry_delay=60.0): counter_text,uri )) try: - # Do the connect - self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri) - self._restore_options() - # StartTLS extended operation in case this was called before - if self._start_tls: - SimpleLDAPObject.start_tls_s(self) - # Repeat last simple or SASL bind - self._apply_last_bind() + try: + # Do the connect + self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri) + self._restore_options() + # StartTLS extended operation in case this was called before + if self._start_tls: + SimpleLDAPObject.start_tls_s(self) + # Repeat last simple or SASL bind + self._apply_last_bind() + except ldap.LDAPError: + SimpleLDAPObject.unbind_s(self) + raise except (ldap.SERVER_DOWN,ldap.TIMEOUT): if __debug__ and self._trace_level>=1: self._trace_file.write('*** %s reconnect to %s failed\n' % ( @@ -1185,7 +1189,6 @@ def reconnect(self,uri,retry_max=1,retry_delay=60.0): if __debug__ and self._trace_level>=1: self._trace_file.write('=> delay %s...\n' % (retry_delay)) time.sleep(retry_delay) - SimpleLDAPObject.unbind_s(self) else: if __debug__ and self._trace_level>=1: self._trace_file.write('*** %s reconnect to %s successful => repeat last operation\n' % (