Exemple #1
0
    async def modify(self, entry, changes, controls=None):
        try:
            req = {
                'object': entry.encode(),
                'changes': encode_changes(changes)
            }
            br = {'modifyRequest': ModifyRequest(req)}
            msg = {'protocolOp': protocolOp(br)}
            if controls is not None:
                msg['controls'] = controls

            msg_id = await self.send_message(msg)
            results = await self.recv_message(msg_id)
            if isinstance(results[0], Exception):
                return False, results[0]

            for message in results:
                msg_type = message['protocolOp'].name
                message = message.native
                if msg_type == 'modifyResponse':
                    if message['protocolOp']['resultCode'] != 'success':
                        return False, Exception(
                            'Failed to add DN! LDAP error! Reason: %s Diag: %s'
                            % (message['protocolOp']['resultCode'],
                               message['protocolOp']['diagnosticMessage']))

            return True, None
        except Exception as e:
            return False, e
Exemple #2
0
    async def delete(self, entry):
        """
		Performs the delete operation.
		
		:param entry: The DN of the object to be deleted
		:type entry: str
		:return: A tuple of (True, None) on success or (False, Exception) on error. 
		:rtype: (:class:`bool`, :class:`Exception`)
		"""
        try:
            br = {'delRequest': DelRequest(entry.encode())}
            msg = {'protocolOp': protocolOp(br)}

            msg_id = await self.send_message(msg)
            results = await self.recv_message(msg_id)
            if isinstance(results[0], Exception):
                return False, results[0]

            for message in results:
                msg_type = message['protocolOp'].name
                message = message.native
                if msg_type == 'delResponse':
                    if message['protocolOp']['resultCode'] != 'success':
                        return False, Exception(
                            'Failed to add DN! LDAP error! Reason: %s Diag: %s'
                            % (message['protocolOp']['resultCode'],
                               message['protocolOp']['diagnosticMessage']))

            return True, None
        except Exception as e:
            return False, e
Exemple #3
0
    async def add(self, entry, attributes):
        try:
            req = {
                'entry': entry.encode(),
                'attributes': encode_attributes(attributes)
            }
            br = {'addRequest': AddRequest(req)}
            msg = {'protocolOp': protocolOp(br)}

            msg_id = await self.send_message(msg)
            results = await self.recv_message(msg_id)
            if isinstance(results[0], Exception):
                return False, results[0]

            for message in results:
                msg_type = message['protocolOp'].name
                message = message.native
                if msg_type == 'addResponse':
                    if message['protocolOp']['resultCode'] != 'success':
                        return False, Exception(
                            'Failed to add DN! LDAP error! Reason: %s Diag: %s'
                            % (message['protocolOp']['resultCode'],
                               message['protocolOp']['diagnosticMessage']))

            return True, None
        except Exception as e:
            return False, e
Exemple #4
0
	async def get_serverinfo(self):
		if self.status != MSLDAPClientStatus.RUNNING:
			return None, Exception('Connection not running! Probably encountered an error')

		attributes = [
			b'subschemaSubentry',
    		b'dsServiceName',
    		b'namingContexts',
    		b'defaultNamingContext',
    		b'schemaNamingContext',
    		b'configurationNamingContext',
    		b'rootDomainNamingContext',
    		b'supportedControl',
    		b'supportedLDAPVersion',
    		b'supportedLDAPPolicies',
    		b'supportedSASLMechanisms',
    		b'dnsHostName',
    		b'ldapServiceName',
    		b'serverName',
    		b'supportedCapabilities'
		]

		filt = { 'present' : 'objectClass'.encode() }
		searchreq = {
			'baseObject' : b'',
			'scope': 0,
			'derefAliases': 0, 
			'sizeLimit': 1,
			'timeLimit': self.target.timeout - 1,
			'typesOnly': False,
			'filter': Filter(filt),
			'attributes': attributes,
		}

		br = { 'searchRequest' : SearchRequest( searchreq	)}
		msg = { 'protocolOp' : protocolOp(br)}

		msg_id = await self.send_message(msg)
		res = await self.recv_message(msg_id)
		res = res[0]
		if isinstance(res, Exception):
			return None, res
		
		#print('res')
		#print(res)
		return convert_attributes(res.native['protocolOp']['attributes']), None
Exemple #5
0
	async def modify(self, entry, changes, controls = None):
		"""
		Performs the modify operation.
		
		:param entry: The DN of the object whose attributes are to be modified
		:type entry: str
		:param changes: Describes the changes to be made on the object. Must be a dictionary of the following format: {'attribute': [('change_type', [value])]}
		:type changes: dict
		:param controls: additional controls to be passed in the query
		:type controls: List[class:`Control`] 
		:return: A tuple of (True, None) on success or (False, Exception) on error. 
		:rtype: (:class:`bool`, :class:`Exception`)
		"""
		try:
			req = {
				'object' : entry.encode(),
				'changes' : encode_changes(changes)
			}
			br = { 'modifyRequest' : ModifyRequest(req)}
			msg = { 'protocolOp' : protocolOp(br)}
			if controls is not None:
				msg['controls'] = controls
			
			msg_id = await self.send_message(msg)
			results = await self.recv_message(msg_id)
			if isinstance(results[0], Exception):
				return False, results[0]
			
			for message in results:
				msg_type = message['protocolOp'].name
				message = message.native
				if msg_type == 'modifyResponse':
					if message['protocolOp']['resultCode'] != 'success':
						return False, LDAPModifyException(
							entry,
							message['protocolOp']['resultCode'],
							message['protocolOp']['diagnosticMessage']
						)

			return True, None
		except Exception as e:
			return False, e
Exemple #6
0
    async def whoami(self):
        if self.status != MSLDAPClientStatus.RUNNING:
            return None, Exception(
                'Connection not running! Probably encountered an error')

        ext = {
            'requestName': b'1.3.6.1.4.1.4203.1.11.3',
        }
        br = {'extendedReq': ExtendedRequest(ext)}
        msg = {'protocolOp': protocolOp(br)}

        msg_id = await self.send_message(msg)
        res = await self.recv_message(msg_id)
        res = res[0]
        if isinstance(res, Exception):
            return None, res
        if res.native['protocolOp']['resultCode'] != 'success':
            return False, LDAPBindException(
                res['protocolOp']['resultCode'],
                res['protocolOp']['diagnosticMessage'])
        return res.native['protocolOp']['responseValue'].decode(), None
Exemple #7
0
	async def add(self, entry, attributes):
		"""
		Performs the add operation.
		
		:param entry: The DN of the object to be added
		:type entry: str
		:param attributes: Attributes to be used in the operation
		:type attributes: dict
		:return: A tuple of (True, None) on success or (False, Exception) on error. 
		:rtype: (:class:`bool`, :class:`Exception`)
		"""
		try:
			req = {
				'entry' : entry.encode(),
				'attributes' : encode_attributes(attributes)
			}
			br = { 'addRequest' : AddRequest(req)}
			msg = { 'protocolOp' : protocolOp(br)}
			
			msg_id = await self.send_message(msg)
			results = await self.recv_message(msg_id)
			if isinstance(results[0], Exception):
				return False, results[0]
			
			for message in results:
				msg_type = message['protocolOp'].name
				message = message.native
				if msg_type == 'addResponse':
					if message['protocolOp']['resultCode'] != 'success':
						return False, LDAPAddException(
							entry,
							message['protocolOp']['resultCode'],
							message['protocolOp']['diagnosticMessage']
						)

			return True, None
		except Exception as e:
			return False, e
Exemple #8
0
    async def search(self,
                     base,
                     query,
                     attributes,
                     search_scope=2,
                     size_limit=1000,
                     types_only=False,
                     derefAliases=0,
                     timeLimit=None,
                     controls=None,
                     return_done=False):
        """
		Performs the search operation.
		
		:param base: base tree on which the search should be performed
		:type base: str
		:param query: filter query that defines what should be searched for
		:type query: str
		:param attributes: a list of attributes to be included in the response
		:type attributes: List[str]
		:param search_scope: Specifies the search operation's scope. Default: 2 (Subtree)
		:type search_scope: int
		:param types_only: indicates whether the entries returned should include attribute types only or both types and values. Default: False (both)
		:type types_only: bool
		:param size_limit: Size limit of result elements per query. Default: 1000
		:type size_limit: int
		:param derefAliases: Specifies the behavior on how aliases are dereferenced. Default: 0 (never)
		:type derefAliases: int
		:param timeLimit: Maximum time the search should take. If time limit reached the server SHOULD return an error
		:type timeLimit: int
		:param controls: additional controls to be passed in the query
		:type controls: dict
		:param return_done: Controls wether the final 'done' LDAP message should be returned, or just the actual results
		:type return_done: bool

		:return: Async generator which yields (`LDAPMessage`, None) tuple on success or (None, `Exception`) on error
		:rtype: Iterator[(:class:`LDAPMessage`, :class:`Exception`)]
		"""
        if self.status != MSLDAPClientStatus.RUNNING:
            yield None, Exception(
                'Connection not running! Probably encountered an error')
            return
        try:
            if timeLimit is None:
                timeLimit = 600  #not sure

            flt = query_syntax_converter(query)

            searchreq = {
                'baseObject': base.encode(),
                'scope': search_scope,
                'derefAliases': derefAliases,
                'sizeLimit': size_limit,
                'timeLimit': timeLimit,
                'typesOnly': types_only,
                'filter': flt,
                'attributes': attributes,
            }

            br = {'searchRequest': SearchRequest(searchreq)}
            msg = {'protocolOp': protocolOp(br)}
            if controls is not None:
                msg['controls'] = controls

            msg_id = await self.send_message(msg)

            while True:
                results = await self.recv_message(msg_id)
                for message in results:
                    msg_type = message['protocolOp'].name
                    message = message.native
                    if msg_type == 'searchResDone':
                        #print(message)
                        #print('BREAKING!')
                        if return_done is True:
                            yield (message, None)
                        break

                    elif msg_type == 'searchResRef':
                        #TODO: Check if we need to deal with this further
                        continue

                    if return_done is True:
                        yield (message, None)
                    else:
                        yield (convert_result(message['protocolOp']), None)
                else:
                    continue

                break

        except Exception as e:
            yield (None, e)
Exemple #9
0
    async def bind(self):
        """
		Performs the bind operation.
		This is where the authentication happens. Remember to call `connect` before this function!

		:return: A tuple of (True, None) on success or (False, Exception) on error. 
		:rtype: (:class:`bool`, :class:`Exception`)
		"""
        logger.debug('BIND in progress...')
        try:
            if self.creds.auth_method == LDAPAuthProtocol.SICILY:

                data, to_continue, err = await self.auth.authenticate(None)
                if err is not None:
                    return None, err

                auth = {'sicily_disco': b''}

                bindreq = {
                    'version': 3,
                    'name': 'NTLM'.encode(),
                    'authentication': AuthenticationChoice(auth),
                }

                br = {'bindRequest': BindRequest(bindreq)}
                msg = {'protocolOp': protocolOp(br)}

                msg_id = await self.send_message(msg)
                res = await self.recv_message(msg_id)
                res = res[0]
                if isinstance(res, Exception):
                    return False, res
                res = res.native
                if res['protocolOp']['resultCode'] != 'success':
                    return False, Exception(
                        'BIND failed! Result code: "%s" Reason: "%s"' %
                        (res['protocolOp']['resultCode'],
                         res['protocolOp']['diagnosticMessage']))

                auth = {'sicily_nego': data}

                bindreq = {
                    'version': 3,
                    'name': 'NTLM'.encode(),
                    'authentication': AuthenticationChoice(auth),
                }

                br = {'bindRequest': BindRequest(bindreq)}
                msg = {'protocolOp': protocolOp(br)}

                msg_id = await self.send_message(msg)
                res = await self.recv_message(msg_id)
                res = res[0]
                if isinstance(res, Exception):
                    return False, res
                res = res.native
                if res['protocolOp']['resultCode'] != 'success':
                    return False, Exception(
                        'BIND failed! Result code: "%s" Reason: "%s"' %
                        (res['protocolOp']['resultCode'],
                         res['protocolOp']['diagnosticMessage']))

                data, to_continue, err = await self.auth.authenticate(
                    res['protocolOp']['matchedDN'])
                if err is not None:
                    return None, err

                auth = {'sicily_resp': data}

                bindreq = {
                    'version': 3,
                    'name': 'NTLM'.encode(),
                    'authentication': AuthenticationChoice(auth),
                }

                br = {'bindRequest': BindRequest(bindreq)}
                msg = {'protocolOp': protocolOp(br)}

                msg_id = await self.send_message(msg)
                res = await self.recv_message(msg_id)
                res = res[0]
                if isinstance(res, Exception):
                    return False, res
                res = res.native
                if res['protocolOp']['resultCode'] != 'success':
                    return False, Exception(
                        'BIND failed! Result code: "%s" Reason: "%s"' %
                        (res['protocolOp']['resultCode'],
                         res['protocolOp']['diagnosticMessage']))

                self.__bind_success()
                return True, None

            elif self.creds.auth_method == LDAPAuthProtocol.SIMPLE:
                pw = b''
                if self.auth.password != None:
                    pw = self.auth.password.encode()

                user = b''
                if self.auth.username != None:
                    user = self.auth.username.encode()

                auth = {'simple': pw}

                bindreq = {
                    'version': 3,
                    'name': user,
                    'authentication': AuthenticationChoice(auth),
                }

                br = {'bindRequest': BindRequest(bindreq)}
                msg = {'protocolOp': protocolOp(br)}

                msg_id = await self.send_message(msg)
                res = await self.recv_message(msg_id)
                res = res[0]
                if isinstance(res, Exception):
                    return False, res
                res = res.native
                if res['protocolOp']['resultCode'] == 'success':
                    self.__bind_success()
                    return True, None

                else:
                    return False, Exception(
                        'BIND failed! Result code: "%s" Reason: "%s"' %
                        (res['protocolOp']['resultCode'],
                         res['protocolOp']['diagnosticMessage']))

            elif self.creds.auth_method in MSLDAP_GSS_METHODS:
                challenge = None
                while True:
                    try:
                        data, to_continue, err = await self.auth.authenticate(
                            challenge, cb_data=self.cb_data)
                        if err is not None:
                            raise err
                    except Exception as e:
                        return False, e

                    sasl = {
                        'mechanism': 'GSS-SPNEGO'.encode(),
                        'credentials': data,
                    }
                    auth = {'sasl': SaslCredentials(sasl)}

                    bindreq = {
                        'version': 3,
                        'name': b'',
                        'authentication': AuthenticationChoice(auth),
                    }

                    br = {'bindRequest': BindRequest(bindreq)}
                    msg = {'protocolOp': protocolOp(br)}

                    msg_id = await self.send_message(msg)
                    res = await self.recv_message(msg_id)
                    res = res[0]
                    if isinstance(res, Exception):
                        return False, res
                    res = res.native
                    if res['protocolOp']['resultCode'] == 'success':
                        if 'serverSaslCreds' in res['protocolOp']:
                            data, _, err = await self.auth.authenticate(
                                res['protocolOp']['serverSaslCreds'],
                                cb_data=self.cb_data)
                            if err is not None:
                                return False, err

                        self.encryption_sequence_counter = self.auth.get_seq_number(
                        )
                        self.__bind_success()

                        return True, None

                    elif res['protocolOp'][
                            'resultCode'] == 'saslBindInProgress':
                        challenge = res['protocolOp']['serverSaslCreds']
                        continue

                    else:
                        return False, Exception(
                            'BIND failed! Result code: "%s" Reason: "%s"' %
                            (res['protocolOp']['resultCode'],
                             res['protocolOp']['diagnosticMessage']))

            else:
                raise Exception('Not implemented authentication method: %s' %
                                self.creds.auth_method.name)
        except Exception as e:
            return False, e
Exemple #10
0
    async def search(self,
                     base,
                     filter,
                     attributes,
                     search_scope=2,
                     paged_size=1000,
                     typesOnly=False,
                     derefAliases=0,
                     timeLimit=None,
                     controls=None,
                     return_done=False):
        """
		This function is a generator!!!!! Dont just call it but use it with "async for"
		"""
        if self.status != MSLDAPClientStatus.RUNNING:
            yield None, Exception(
                'Connection not running! Probably encountered an error')
            return
        try:
            if timeLimit is None:
                timeLimit = 600  #not sure

            searchreq = {
                'baseObject': base,
                'scope': search_scope,
                'derefAliases': derefAliases,
                'sizeLimit': paged_size,
                'timeLimit': timeLimit,
                'typesOnly': typesOnly,
                'filter': filter,
                'attributes': attributes,
            }

            br = {'searchRequest': SearchRequest(searchreq)}
            msg = {'protocolOp': protocolOp(br)}
            if controls is not None:
                msg['controls'] = controls

            msg_id = await self.send_message(msg)

            while True:
                results = await self.recv_message(msg_id)
                for message in results:
                    msg_type = message['protocolOp'].name
                    message = message.native
                    if msg_type == 'searchResDone':
                        #print(message)
                        #print('BREAKING!')
                        if return_done is True:
                            yield (message, None)
                        break

                    elif msg_type == 'searchResRef':
                        #TODO: Check if we need to deal with this further
                        continue

                    if return_done is True:
                        yield (message, None)
                    else:
                        yield (convert_result(message['protocolOp']), None)
                else:
                    continue

                break

        except Exception as e:
            yield (None, e)