largs.append(args['value']) if SeleniumCommandPrototypes.has_key(cmd): proto = SeleniumCommandPrototypes[cmd] method = getattr(self._selenium, proto['method']) self.logSentPayload( "%s(target = %s, value = %s)" % (cmd, args.get('target', None), args.get('value', None)), payload='', sutAddress='%s:%s' % (self['rc_host'], self['rc_port'])) ret = method(cmd, largs) if proto['treturnType']: self.logReceivedPayload("%s returned" % cmd, payload=ret, sutAddress='%s:%s' % (self['rc_host'], self['rc_port'])) self.triEnqueueMsg(ret) else: # We assume that no return value is expected method = getattr(self._selenium, "do_command") self.logSentPayload( "%s(target = %s, value = %s)" % (cmd, args.get('target', None), args.get('value', None)), payload='', sutAddress='%s:%s' % (self['rc_host'], self['rc_port'])) ret = method(cmd, largs) ProbeImplementationManager.registerProbeImplementationClass( 'selenium', SeleniumProbe)
if not inspect.ismethod(attr): return True if self.retValuePattern.search(attr.__name__): return True return False def _isElementPresent(self, target): try: self._getWebelement(target) except NoSuchElementException, e: return False return True def _isAlertPresent(self): try: self.driver.switch_to_alert() except NoAlertPresentException, e: return False return True def _getDriverObj(self): return self.driver def _reset(self): if self.driver: if self['auto_shutdown']: self.driver.quit() self.driver = None ProbeImplementationManager.registerProbeImplementationClass('selenium.webdriver', SeleniumWebdriverProbe)
self._probe.getLogger().debug( "New data to read from %s" % str(addr)) data = s.recv(65535) if not data: self._probe.getLogger().debug( "%s disconnected by peer" % str(addr)) self._probe._feedData( addr, '' ) # notify the feeder that we won't have more data self._probe._disconnect( addr, reason="disconnected by peer") else: # New received message. self._probe._feedData(addr, data) except Exception as e: self._probe.getLogger().warning( "exception while polling active/listening sockets: %s" % str(e) + ProbeImplementationManager.getBacktrace()) except Exception as e: self._probe.getLogger().warning( "exception while polling active/listening sockets: %s" % str(e)) # Avoid 100% CPU usage when select() raises an error time.sleep(0.01) ProbeImplementationManager.registerProbeImplementationClass('tcp', TcpProbe)
cursor = conn.cursor() self.logSentPayload(query.split(' ')[0].upper(), query) try: cursor.execute(str(query)) conn.commit() except Exception, e: self.getLogger().warning( "Exception while executing query: %s" % getBacktrace()) conn.rollback() cursor.close() conn.close() raise e res = [] if cursor.description: # equivalent to "the previous execution() provided a set ?" columnNames = map(lambda x: x[0], cursor.description) for row in cursor.fetchall(): res.append(dict(zip(columnNames, row))) self.triEnqueueMsg(('result', res)) cursor.close() conn.close() except Exception, e: self.getLogger().warning("Exception while handling a query: %s" % getBacktrace()) self.triEnqueueMsg(('error', str(e))) ProbeImplementationManager.registerProbeImplementationClass( 'sql.oracle', OracleProbe)
if self.retValuePattern.search(attr.__name__): return True return False def _isElementPresent(self, target): try: self._getWebelement(target) except NoSuchElementException, e: return False return True def _isAlertPresent(self): try: self.driver.switch_to_alert() except NoAlertPresentException, e: return False return True def _getDriverObj(self): return self.driver def _reset(self): if self.driver: if self['auto_shutdown']: self.driver.quit() self.driver = None ProbeImplementationManager.registerProbeImplementationClass( 'selenium.webdriver', SeleniumWebdriverProbe)
import os def scanPlugins(paths, label): for path in paths: if not path in sys.path: sys.path.append(path) try: for m in os.listdir(path): if m.startswith('__init__') or not (os.path.isdir(path + '/' + m) or m.endswith('.py')) or m.startswith('.'): continue if m.endswith('.py'): m = m[:-3] try: plugin = __import__(m) registerPlugin(plugin.SUPPORTED_CONF_FILE_FORMATS, plugin) except Exception, e: ProbeImplementationManager.getLogger().warning("Unable to import %s %s: %s" % (m, label, str(e))) except Exception, e: ProbeImplementationManager.getLogger().warning("Unable to scan %s path for %ss: %s" % (path, label, str(e))) # On import, scan plugins import os.path currentDir = os.path.normpath(os.path.realpath(os.path.dirname(sys.modules[globals()['__name__']].__file__))) scanPlugins([ "%s/plugins" % currentDir ], 'configuration file accessor') ## # ConfigFile probe class registration ## ProbeImplementationManager.registerProbeImplementationClass('configurationfile', ConfigFileProbe)
while not self._stopEvent.isSet(): listening = self._probe._getListeningSockets() active = self._probe._getActiveSockets() rset = listening + active try: r, w, e = select.select(rset, [], [], 0.001) for s in r: try: localaddr = s.getsockname() (data, addr) = s.recvfrom(65535) self._probe.getLogger().debug( "New data to read from %s" % str(addr)) # New received message. self._probe._feedData(localaddr, addr, data) except Exception as e: self._probe.getLogger().warning( "exception while polling active/listening sockets: %s" % str(e)) except Exception as e: self._probe.getLogger().warning( "exception while polling active/listening sockets: %s" % str(e)) # Avoid 100% CPU usage when select() raised an error time.sleep(0.01) ProbeImplementationManager.registerProbeImplementationClass('udp', UdpProbe)
conn = dbapi.connect(str(self['user']), str(self['password']), dsn) cursor = conn.cursor() self.logSentPayload(query.split(' ')[0].upper(), query) try: cursor.execute(str(query)) conn.commit() except Exception, e: self.getLogger().warning("Exception while executing query: %s" % getBacktrace()) conn.rollback() cursor.close() conn.close() raise e res = [] if cursor.description: # equivalent to "the previous execution() provided a set ?" columnNames = map(lambda x: x[0], cursor.description) for row in cursor.fetchall(): res.append(dict(zip(columnNames, row))) self.triEnqueueMsg(('result', res)) cursor.close() conn.close() except Exception, e: self.getLogger().warning("Exception while handling a query: %s" % getBacktrace()) self.triEnqueueMsg(('error', str(e))) ProbeImplementationManager.registerProbeImplementationClass('sql.oracle', OracleProbe)
try: conn = dbapi.connect(user = self['user'], passwd = self['password'], db = self['database'], host = self['host']) # '%s:%s' % (self['host'], self['port'])) cursor = conn.cursor() self.logSentPayload(query.split(' ')[0].upper(), query) try: cursor.execute(query) conn.commit() except Exception, e: conn.rollback() cursor.close() conn.close() raise e res = [] if cursor.description: # equivalent to "the previous execution() provided a set ?" columnNames = map(lambda x: x[0], cursor.description) for row in cursor.fetchall(): res.append(dict(zip(columnNames, row))) self.triEnqueueMsg(('result', res)) cursor.close() conn.close() except Exception, e: self.getLogger().warning("Exception while handling a query: %s" % str(e)) self.triEnqueueMsg(('error', str(e))) ProbeImplementationManager.registerProbeImplementationClass('sql.mysql', MySqlProbe)
def onTriSAReset(self): pass def onTriSend(self, message, sutAddress): try: (operation, args) = message except: raise Exception("Invalid message format") proxy = ServerProxy(self, self['server_url']) # The following code should be executed in a dedicated thread try: f = getattr(proxy, operation) if isinstance(args, list): ret = f(*args) elif isinstance(args, dict): ret = f(**args) else: ret = f(args) event = ('response', ret) except xmlrpclib.Fault, e: event = ('fault', { 'code': e.faultCode, 'string': e.faultString }) # Raise other exceptions if needed self.triEnqueueMsg(event) ProbeImplementationManager.registerProbeImplementationClass('xmlrpc.client', XmlRpcClientProbe)
# Just wait self._probe.getLogger().info( 'Waiting for additional data...') elif status == CodecManager.IncrementalCodec.DECODING_ERROR: raise Exception( 'Unable to decode response: decoding error') else: # DECODING_OK fromAddr = "%s:%s" % (self._probe['host'], self._probe['port']) self._probe.getLogger().debug( 'message decoded, enqueuing...') self._probe.logReceivedPayload(summary, buf, fromAddr) self._probe.triEnqueueMsg(decodedMessage, fromAddr) self._stopEvent.set() except Exception as e: self._probe.getLogger().error( 'Error while waiting for http response: %s' % str(e)) self._stopEvent.set() if not self._probe['maintain_connection']: # Well, actually this should depends on the HTTP protocol version... self._probe.disconnect() def stop(self): self._stopEvent.set() self.join() ProbeImplementationManager.registerProbeImplementationClass( 'http.client', HttpClientProbe)
def _addBaseDn(self, dn): """ Append the base_dn property, if any """ baseDn = self['base_dn'] if baseDn: return ','.join( filter(lambda x: x.strip(), dn.split(',') + baseDn.split(','))) else: return dn def _stripBaseDn(self, dn): """ If the dn ends with the base_dn property, strips it. """ baseDn = self['base_dn'] if baseDn: baseDn = ','.join( filter(lambda x: x.strip(), self['base_dn'].split(','))) if dn.lower().endswith(baseDn.lower()): dn = dn[:-len(baseDn)] if dn.endswith(','): dn = dn[:-1] return dn ProbeImplementationManager.registerProbeImplementationClass( 'ldap.client', LdapClientProbe)
self._stopEvent.set() else: self._probe.getLogger().warning( 'Invalid CSeq received. Not enqueuing, ignoring message' ) buf = '' decodedMessage = None # Wait for a possible next message... elif not read: # Message not decoded, nothing to read anymore. raise Exception( 'Incomplete message received, stream interrupted') # .. and we should disconnect, too... except Exception as e: self._probe.getLogger().error( 'Error while waiting for rtsp response: %s' % str(e)) self._stopEvent.set() if not self._probe['maintain_connection']: # Well, maintain connection in RTSP ? self._probe.disconnect() def stop(self): self._stopEvent.set() self.join() ProbeImplementationManager.registerProbeImplementationClass( 'rtsp.client', RtspClientProbe)
# TODO: use a bitmap of updated properties if (pt, src[0], src[1], ssrc) != ( lastPt, lastSourceIp, lastSourcePort, lastSsrc): # PT or emitter updated: raise a stop then a start event. self._probe.triEnqueueMsg(('stoppedReceivingRtp', { 'reason': 'updated' }), "%s:%s" % src) self._probe.logReceivedPayload("Receiving RTP...", data, "%s:%s" % src) self._probe.triEnqueueMsg(('startedReceivingRtp', { 'payloadType': pt, 'ssrc': ssrc, 'fromIp': lastSourceIp, 'fromPort': lastSourcePort }), "%s:%s" % src) # Update stream properties with the current values lastPt = pt lastSourceIp, lastSourcePort = src lastSsrc = ssrc lastTime = time.time() except Exception as e: self._probe.getLogger().error( "Exception while listening RTP: %s" % str(e)) self._probe._conditionallyCloseSocket(fromSocket) ProbeImplementationManager.registerProbeImplementationClass('rtp', RtpProbe)
assert _compareLists([1, 2, 3, 4, 5, 6], [1, 2, 5, 6]) == ([3, 4], []) assert _compareLists([1, 2, 3, 4, 5, 6], [2, 3, 5, 6]) == ([1, 4], []) assert _compareLists([4, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [1, 2, 3]) assert _compareLists([1, 3, 4, 5, 6], [1, 2, 3, 4, 7]) == ([5, 6], [2, 7]) assert _compareLists2([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], []) assert _compareLists2([1, 2, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [3, 4]) assert _compareLists2([1, 2, 3, 4, 5, 6], [1, 2, 5, 6]) == ([3, 4], []) assert _compareLists2([1, 2, 3, 4, 5, 6], [2, 3, 5, 6]) == ([1, 4], []) assert _compareLists2([4, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [1, 2, 3]) assert _compareLists2([1, 3, 4, 5, 6], [1, 2, 3, 4, 7]) == ([5, 6], [2, 7]) import random import time l = 10000 l1 = [random.randrange(0, l * 10) for x in range(0, l)] l2 = [random.randrange(0, l * 10) for x in range(0, l)] l1.sort() l2.sort() for f in (_compareLists, _compareLists2, _compareLists3): start = time.time() f(l1, l2) stop = time.time() print "%s: %s" % (f, stop - start) else: ProbeImplementationManager.registerProbeImplementationClass("watcher.dir", DirWatcherProbe)
# OK, scan the file to get matching new lines self._probe.getLogger().debug( "File %s changed since the last tick, starting at %d" % (filename, offset)) f = open(filename, 'r') f.seek(offset) newlines = f.readlines() f.close() # Technically, the file may have grown since we took the ref size # We should lock the file until we complete our analysis and reading # but the current implementation should be enough for typical probe usages for line in newlines: for pattern in self._patterns: m = pattern.match(line) if m: event = { 'filename': filename, 'line': line.strip() } # Should we strip the line ? for k, v in m.groupdict().items(): event['matched_%s' % k] = v self._probe.triEnqueueMsg(event) # A line can be matched only once. break # else no match ProbeImplementationManager.registerProbeImplementationClass( "watcher.file", FileWatcherProbe)
self._reportStatus = r self._mutex.release() def stop(self): # When explicitely stopped, we should not send a status/output back. if self._process: self.setReportStatus(False) pid = self._process.pid pids = getChildrenPids(pid) self._probe.getLogger().info( "Killing process %s (%s) on user demand..." % (pid, pids)) s = signal.SIGKILL if sys.platform in ['win32', 'win64']: s = signal.SIGTERM for p in pids: try: os.kill(p, s) except Exception as e: self._probe.getLogger().warning( "Unable to kill process %s: %s" % (pid, str(e))) # And we should wait for a notification indicating that the process # has died... # We wait at most 1s. Maybe the process was not killed # (in case of blocking IO for instance), but this should be rare cases # and this will lead to an error later in next command execution. # So the user wil figure it out soon. self._stoppedEvent.wait(1.0) ProbeImplementationManager.registerProbeImplementationClass("exec", ExecProbe)
assert (_compareLists([1, 2, 3, 4, 5, 6], [2, 3, 5, 6]) == ([1, 4], [])) assert (_compareLists([4, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [1, 2, 3])) assert (_compareLists([1, 3, 4, 5, 6], [1, 2, 3, 4, 7]) == ([5, 6], [2, 7])) assert (_compareLists2([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [])) assert (_compareLists2([1, 2, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [3, 4])) assert (_compareLists2([1, 2, 3, 4, 5, 6], [1, 2, 5, 6]) == ([3, 4], [])) assert (_compareLists2([1, 2, 3, 4, 5, 6], [2, 3, 5, 6]) == ([1, 4], [])) assert (_compareLists2([4, 5, 6], [1, 2, 3, 4, 5, 6]) == ([], [1, 2, 3])) assert (_compareLists2([1, 3, 4, 5, 6], [1, 2, 3, 4, 7]) == ([5, 6], [2, 7])) import random import time l = 10000 l1 = [random.randrange(0, l * 10) for x in range(0, l)] l2 = [random.randrange(0, l * 10) for x in range(0, l)] l1.sort() l2.sort() for f in (_compareLists, _compareLists2, _compareLists3): start = time.time() f(l1, l2) stop = time.time() print "%s: %s" % (f, stop - start) else: ProbeImplementationManager.registerProbeImplementationClass( "watcher.dir", DirWatcherProbe)
db=self['database'], host=self['host']) # '%s:%s' % (self['host'], self['port'])) cursor = conn.cursor() self.logSentPayload(query.split(' ')[0].upper(), query) try: cursor.execute(query) conn.commit() except Exception, e: conn.rollback() cursor.close() conn.close() raise e res = [] if cursor.description: # equivalent to "the previous execution() provided a set ?" columnNames = map(lambda x: x[0], cursor.description) for row in cursor.fetchall(): res.append(dict(zip(columnNames, row))) self.triEnqueueMsg(('result', res)) cursor.close() conn.close() except Exception, e: self.getLogger().warning("Exception while handling a query: %s" % str(e)) self.triEnqueueMsg(('error', str(e))) ProbeImplementationManager.registerProbeImplementationClass( 'sql.mysql', MySqlProbe)
self._probe.getLogger().debug('Got some input on %s: (%s)' % (stream, repr(data))) buf = self._buffer[stream] buf += data if self._separator: msgs = buf.split(self._separator) for msg in msgs[:-1]: for pattern in self._patterns: m = pattern.match(msg) if m: event = {'stream': stream, 'output': msg} for k, v in m.groupdict().items(): event['matched_%s' % k] = v self._probe.triEnqueueMsg(event) buf = msgs[-1] else: # No separator management. Notifies things as is. for pattern in self._patterns: m = pattern.match(buf) if m: event = {'stream': stream, 'output': buf} for k, v in m.groupdict().items(): event['matched_%s' % k] = v self._probe.triEnqueueMsg(event) buf = '' ProbeImplementationManager.registerProbeImplementationClass( "exec.interactive", InteractiveExecProbe)
self.getLogger().debug( "Restoring modified/deleted file %s..." % path) # ... except Exception, e: self.getLogger().warning( "Unable to restore modified/deleted file %s: %s" % (path, str(e))) self._addedFiles = [] self._modifiedFiles = [] def _backupFileToDelete(self, path): if not path in self._addedFiles + self._modifiedFiles: pass # targetDir = "%s/ # os.makedirs # target = "%s/ # self.getLogger().info("Backup up file to delete %s -> %s" % (path, target) # shutil.move(path, target) # self._deletedFiles.append(path) def _backupFile(self, path): if not path in self._addedFiles + self._modifiedFiles: # if fileExists(path): pass ProbeImplementationManager.registerProbeImplementationClass( 'file.manager', FileManagerProbe)
(cmd, args) = message # Loose command implementation only for now largs = [] if args.has_key('target'): largs = [ args['target'] ] if args.has_key('value'): largs.append(args['value']) if SeleniumCommandPrototypes.has_key(cmd): proto = SeleniumCommandPrototypes[cmd] method = getattr(self._selenium, proto['method']) self.logSentPayload("%s(target = %s, value = %s)" % (cmd, args.get('target', None), args.get('value', None)), payload = '', sutAddress = '%s:%s' % (self['rc_host'], self['rc_port'])) ret = method(cmd, largs) if proto['treturnType']: self.logReceivedPayload("%s returned" % cmd, payload = ret, sutAddress = '%s:%s' % (self['rc_host'], self['rc_port'])) self.triEnqueueMsg(ret) else: # We assume that no return value is expected method = getattr(self._selenium, "do_command") self.logSentPayload("%s(target = %s, value = %s)" % (cmd, args.get('target', None), args.get('value', None)), payload = '', sutAddress = '%s:%s' % (self['rc_host'], self['rc_port'])) ret = method(cmd, largs) ProbeImplementationManager.registerProbeImplementationClass('selenium', SeleniumProbe)
self._ssh.sendline(actualCommandLine) # Wait for a command completion while not self._stopEvent.isSet(): if self._ssh.prompt(0.1): # We got a completion - skip the command line (that could be multiline) that have been # echoed. output = '\n'.join( self._ssh.before.split('\n')[len(splitcmd):]) self._ssh.sendline('echo $?') self._ssh.prompt() # 'before' contains: line 0: echo $? , line 1: the echo output status = int(self._ssh.before.split('\n')[1].strip()) self._ssh.logout() break except Exception as e: self._probe.triEnqueueMsg('Internal SSH error: %s' % str(e)) # Kill the ssh session, if still active for wathever reason try: self._ssh.terminate() except: pass self._probe.onSshThreadTerminated(status, output) def stop(self): self._stopEvent.set() ProbeImplementationManager.registerProbeImplementationClass("ssh", SshProbe)
def onTriSAReset(self): pass def onTriSend(self, message, sutAddress): try: (operation, args) = message except: raise Exception("Invalid message format") proxy = ServerProxy(self, self['server_url']) # The following code should be executed in a dedicated thread try: f = getattr(proxy, operation) if isinstance(args, list): ret = f(*args) elif isinstance(args, dict): ret = f(**args) else: ret = f(args) event = ('response', ret) except xmlrpclib.Fault as e: event = ('fault', {'code': e.faultCode, 'string': e.faultString}) # Raise other exceptions if needed self.triEnqueueMsg(event) ProbeImplementationManager.registerProbeImplementationClass( 'xmlrpc.client', XmlRpcClientProbe)
except Exception, e: self.getLogger().warning("Unable to remove added file %s: %s" % (path, str(e))) for path in self._modifiedFiles: try: self.getLogger().debug("Restoring modified/deleted file %s..." % path) # ... except Exception, e: self.getLogger().warning("Unable to restore modified/deleted file %s: %s" % (path, str(e))) self._addedFiles = [] self._modifiedFiles = [] def _backupFileToDelete(self, path): if not path in self._addedFiles + self._modifiedFiles: pass # targetDir = "%s/ # os.makedirs # target = "%s/ # self.getLogger().info("Backup up file to delete %s -> %s" % (path, target) # shutil.move(path, target) # self._deletedFiles.append(path) def _backupFile(self, path): if not path in self._addedFiles + self._modifiedFiles: # if fileExists(path): pass ProbeImplementationManager.registerProbeImplementationClass('file.manager', FileManagerProbe)
for m in os.listdir(path): if m.startswith('__init__') or not ( os.path.isdir(path + '/' + m) or m.endswith('.py')) or m.startswith('.'): continue if m.endswith('.py'): m = m[:-3] try: plugin = __import__(m) registerPlugin(plugin.SUPPORTED_CONF_FILE_FORMATS, plugin) except Exception, e: ProbeImplementationManager.getLogger().warning( "Unable to import %s %s: %s" % (m, label, str(e))) except Exception, e: ProbeImplementationManager.getLogger().warning( "Unable to scan %s path for %ss: %s" % (path, label, str(e))) # On import, scan plugins import os.path currentDir = os.path.normpath( os.path.realpath( os.path.dirname(sys.modules[globals()['__name__']].__file__))) scanPlugins(["%s/plugins" % currentDir], 'configuration file accessor') ## # ConfigFile probe class registration ## ProbeImplementationManager.registerProbeImplementationClass( 'configurationfile', ConfigFileProbe)
self._probe._onIncomingConnection(sock, addr) # Raise a new connection notification event - soon else: addr = s.getpeername() self._probe.getLogger().debug( "New data to read from %s" % str(addr)) data = s.recv(65535) if not data: self._probe.getLogger().debug( "%s disconnected by peer" % str(addr)) self._probe._disconnect( addr, reason="disconnected by peer") else: # New received message. self._probe._feedData(addr, data) except Exception as e: self._probe.getLogger().warning( "exception while polling active/listening sockets: %s" % str(e)) except Exception as e: self._probe.getLogger().warning( "exception while polling active/listening sockets: %s" % str(e)) # Avoid 100% CPU usage when select() raised an error time.sleep(0.01) ProbeImplementationManager.registerProbeImplementationClass('sctp', SctpProbe)
offset = 0 if offset is None: # Nothing to do for the file return # OK, scan the file to get matching new lines self._probe.getLogger().debug("File %s changed since the last tick, starting at %d" % (filename, offset)) f = open(filename, 'r') f.seek(offset) newlines = f.readlines() f.close() # Technically, the file may have grown since we took the ref size # We should lock the file until we complete our analysis and reading # but the current implementation should be enough for typical probe usages for line in newlines: for pattern in self._patterns: m = pattern.match(line) if m: event = { 'filename': filename, 'line': line.strip() } # Should we strip the line ? for k, v in m.groupdict().items(): event['matched_%s' % k] = v self._probe.triEnqueueMsg(event) # A line can be matched only once. break # else no match ProbeImplementationManager.registerProbeImplementationClass("watcher.file", FileWatcherProbe)
else: ret = True return ret def _addBaseDn(self, dn): """ Append the base_dn property, if any """ baseDn = self['base_dn'] if baseDn: return ','.join(filter(lambda x: x.strip(), dn.split(',') + baseDn.split(','))) else: return dn def _stripBaseDn(self, dn): """ If the dn ends with the base_dn property, strips it. """ baseDn = self['base_dn'] if baseDn: baseDn = ','.join(filter(lambda x: x.strip(), self['base_dn'].split(','))) if dn.lower().endswith(baseDn.lower()): dn = dn[:-len(baseDn)] if dn.endswith(','): dn = dn[:-1] return dn ProbeImplementationManager.registerProbeImplementationClass('ldap.client', LdapClientProbe)