def dc_watcher(self): (r1, w1) = os.pipe() pid = os.fork() if pid != 0: # Parent process return the result socket to the caller. return r1 # Load the lp context for the Domain Controller, rather than the # member server. config_file = os.environ["DC_SERVERCONFFILE"] lp_ctx = LoadParm() lp_ctx.load(config_file) # # Is the message a SamLogon authentication? def is_sam_logon(m): if m is None: return False msg = json.loads(m) return (msg["type"] == "Authentication" and msg["Authentication"]["serviceDescription"] == "SamLogon") # # Handler function for received authentication messages. def message_handler(context, msgType, src, message): # Print the message to help debugging the tests. # as it's a JSON message it does not look like a sub-unit message. print(message) self.dc_msgs.append(message) # Set up a messaging context to listen for authentication events on # the domain controller. msg_ctx = Messaging((1, ), lp_ctx=lp_ctx) msg_ctx.irpc_add_name(AUTH_EVENT_NAME) msg_handler_and_context = (message_handler, None) msg_ctx.register(msg_handler_and_context, msg_type=MSG_AUTH_LOG) # Wait for the SamLogon message. # As there could be other SamLogon's in progress we need to collect # all the SamLogons and let the caller match them to the session. self.dc_msgs = [] start_time = time.time() while (time.time() - start_time < 1): msg_ctx.loop_once(0.1) # Only interested in SamLogon messages, filter out the rest msgs = list(filter(is_sam_logon, self.dc_msgs)) if msgs: for m in msgs: m += "\n" os.write(w1, get_bytes(m)) else: os.write(w1, get_bytes("None\n")) os.close(w1) msg_ctx.deregister(msg_handler_and_context, msg_type=MSG_AUTH_LOG) msg_ctx.irpc_remove_name(AUTH_EVENT_NAME) os._exit(0)
class AuthLogTestBase(samba.tests.TestCase): def setUp(self): super(AuthLogTestBase, self).setUp() lp_ctx = self.get_loadparm() self.msg_ctx = Messaging((1, ), lp_ctx=lp_ctx) self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) def messageHandler(context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print message jsonMsg = json.loads(message) context["messages"].append(jsonMsg) self.context = {"messages": []} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.discardMessages() self.remoteAddress = None self.server = os.environ["SERVER"] self.connection = None def tearDown(self): if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) def waitForMessages(self, isLastExpectedMessage, connection=None): def completed(messages): for message in messages: if isRemote(message) and isLastExpectedMessage(message): return True return False def isRemote(message): remote = None if message["type"] == "Authorization": remote = message["Authorization"]["remoteAddress"] elif message["type"] == "Authentication": remote = message["Authentication"]["remoteAddress"] else: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False self.connection = connection start_time = time.time() while not completed(self.context["messages"]): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None return [] self.connection = None return filter(isRemote, self.context["messages"]) # Discard any previously queued messages. def discardMessages(self): self.msg_ctx.loop_once(0.001) while len(self.context["messages"]): self.msg_ctx.loop_once(0.001) self.context["messages"] = []
class AuthLogTestBase(samba.tests.TestCase): def setUp(self): super(AuthLogTestBase, self).setUp() lp_ctx = self.get_loadparm() self.msg_ctx = Messaging((1,), lp_ctx=lp_ctx); self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) def messageHandler( context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print message jsonMsg = json.loads(message) context["messages"].append( jsonMsg) self.context = { "messages": []} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.discardMessages() self.remoteAddress = None self.server = os.environ["SERVER"] self.connection = None def tearDown(self): if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) def waitForMessages(self, isLastExpectedMessage, connection=None): """Wait for all the expected messages to arrive The connection is passed through to keep the connection alive until all the logging messages have been received. """ def completed( messages): for message in messages: if isRemote( message) and isLastExpectedMessage( message): return True return False def isRemote( message): remote = None if message["type"] == "Authorization": remote = message["Authorization"]["remoteAddress"] elif message["type"] == "Authentication": remote = message["Authentication"]["remoteAddress"] else: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False self.connection = connection start_time = time.time() while not completed( self.context["messages"]): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None return [] self.connection = None return filter( isRemote, self.context["messages"]) # Discard any previously queued messages. def discardMessages(self): self.msg_ctx.loop_once(0.001) while len( self.context["messages"]): self.msg_ctx.loop_once(0.001) self.context["messages"] = [] # Remove any NETLOGON authentication messages # NETLOGON is only performed once per session, so to avoid ordering # dependencies within the tests it's best to strip out NETLOGON messages. # def remove_netlogon_messages(self, messages): def is_not_netlogon(msg): if "Authentication" not in msg: return True sd = msg["Authentication"]["serviceDescription"] return sd != "NETLOGON" return list(filter(is_not_netlogon, messages))
class AuditLogTestBase(samba.tests.TestCase): def setUp(self): super(AuditLogTestBase, self).setUp() lp_ctx = self.get_loadparm() self.msg_ctx = Messaging((1, ), lp_ctx=lp_ctx) self.msg_ctx.irpc_add_name(self.event_type) # # Check the remote address of a message against the one beimg used # for the tests. # def isRemote(message): audit = getAudit(message) if audit is None: return False remote = audit["remoteAddress"] if remote is None: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False def messageHandler(context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print(message) jsonMsg = json.loads(message) if ((jsonMsg["type"] == "passwordChange" or jsonMsg["type"] == "dsdbChange" or jsonMsg["type"] == "groupChange") and isRemote(jsonMsg)): context["messages"].append(jsonMsg) elif jsonMsg["type"] == "dsdbTransaction": context["txnMessage"] = jsonMsg self.context = {"messages": [], "txnMessage": None} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=self.message_type) self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) def authHandler(context, msgType, src, message): jsonMsg = json.loads(message) if jsonMsg["type"] == "Authorization" and isRemote(jsonMsg): # This does not look like sub unit output and it # makes these tests much easier to debug. print(message) context["sessionId"] = jsonMsg["Authorization"]["sessionId"] context["serviceDescription"] =\ jsonMsg["Authorization"]["serviceDescription"] self.auth_context = {"sessionId": "", "serviceDescription": ""} self.auth_handler_and_context = (authHandler, self.auth_context) self.msg_ctx.register(self.auth_handler_and_context, msg_type=MSG_AUTH_LOG) self.discardMessages() self.server = os.environ["SERVER"] self.connection = None def tearDown(self): self.discardMessages() self.msg_ctx.irpc_remove_name(self.event_type) self.msg_ctx.irpc_remove_name(AUTH_EVENT_NAME) if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=self.message_type) if self.auth_handler_and_context: self.msg_ctx.deregister(self.auth_handler_and_context, msg_type=MSG_AUTH_LOG) def haveExpected(self, expected, dn): if dn is None: return len(self.context["messages"]) >= expected else: received = 0 for msg in self.context["messages"]: audit = getAudit(msg) if audit["dn"].lower() == dn.lower(): received += 1 if received >= expected: return True return False def waitForMessages(self, number, connection=None, dn=None): """Wait for all the expected messages to arrive The connection is passed through to keep the connection alive until all the logging messages have been received. """ self.connection = connection start_time = time.time() while not self.haveExpected(number, dn): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None print("Timed out") return [] self.connection = None if dn is None: return self.context["messages"] messages = [] for msg in self.context["messages"]: audit = getAudit(msg) if audit["dn"].lower() == dn.lower(): messages.append(msg) return messages # Discard any previously queued messages. def discardMessages(self): self.msg_ctx.loop_once(0.001) while (len(self.context["messages"]) or self.context["txnMessage"] is not None): self.context["messages"] = [] self.context["txnMessage"] = None self.msg_ctx.loop_once(0.001) GUID_RE = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" # # Is the supplied GUID string correctly formatted # def is_guid(self, guid): return re.match(self.GUID_RE, guid) def get_session(self): return self.auth_context["sessionId"] def get_service_description(self): return self.auth_context["serviceDescription"]
class AuditLogTestBase(samba.tests.TestCase): def setUp(self): super(AuditLogTestBase, self).setUp() # connect to the server's messaging bus (we need to explicitly load a # different smb.conf here, because in all other respects this test # wants to act as a separate remote client) server_conf = os.getenv('SERVERCONFFILE') if server_conf: lp_ctx = LoadParm(filename_for_non_global_lp=server_conf) else: lp_ctx = self.get_loadparm() self.msg_ctx = Messaging((1,), lp_ctx=lp_ctx) self.msg_ctx.irpc_add_name(self.event_type) # Now switch back to using the client-side smb.conf. The tests will # use the first interface in the client.conf (we need to strip off # the subnet mask portion) lp_ctx = self.get_loadparm() client_ip_and_mask = lp_ctx.get('interfaces')[0] client_ip = client_ip_and_mask.split('/')[0] # the messaging ctx is the server's view of the world, so our own # client IP will be the remoteAddress when connections are logged self.remoteAddress = client_ip # # Check the remote address of a message against the one being used # for the tests. # def isRemote(message): audit = getAudit(message) if audit is None: return False remote = audit["remoteAddress"] if remote is None: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False def messageHandler(context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print(message) jsonMsg = json.loads(message) if ((jsonMsg["type"] == "passwordChange" or jsonMsg["type"] == "dsdbChange" or jsonMsg["type"] == "groupChange") and isRemote(jsonMsg)): context["messages"].append(jsonMsg) elif jsonMsg["type"] == "dsdbTransaction": context["txnMessage"] = jsonMsg self.context = {"messages": [], "txnMessage": None} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=self.message_type) self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) def authHandler(context, msgType, src, message): jsonMsg = json.loads(message) if jsonMsg["type"] == "Authorization" and isRemote(jsonMsg): # This does not look like sub unit output and it # makes these tests much easier to debug. print(message) context["sessionId"] = jsonMsg["Authorization"]["sessionId"] context["serviceDescription"] =\ jsonMsg["Authorization"]["serviceDescription"] self.auth_context = {"sessionId": "", "serviceDescription": ""} self.auth_handler_and_context = (authHandler, self.auth_context) self.msg_ctx.register(self.auth_handler_and_context, msg_type=MSG_AUTH_LOG) self.discardMessages() self.server = os.environ["SERVER"] self.connection = None def tearDown(self): self.discardMessages() self.msg_ctx.irpc_remove_name(self.event_type) self.msg_ctx.irpc_remove_name(AUTH_EVENT_NAME) if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=self.message_type) if self.auth_handler_and_context: self.msg_ctx.deregister(self.auth_handler_and_context, msg_type=MSG_AUTH_LOG) def haveExpected(self, expected, dn): if dn is None: return len(self.context["messages"]) >= expected else: received = 0 for msg in self.context["messages"]: audit = getAudit(msg) if audit["dn"].lower() == dn.lower(): received += 1 if received >= expected: return True return False def waitForMessages(self, number, connection=None, dn=None): """Wait for all the expected messages to arrive The connection is passed through to keep the connection alive until all the logging messages have been received. """ self.connection = connection start_time = time.time() while not self.haveExpected(number, dn): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None print("Timed out") return [] self.connection = None if dn is None: return self.context["messages"] messages = [] for msg in self.context["messages"]: audit = getAudit(msg) if audit["dn"].lower() == dn.lower(): messages.append(msg) return messages # Discard any previously queued messages. def discardMessages(self): self.msg_ctx.loop_once(0.001) while (len(self.context["messages"]) or self.context["txnMessage"] is not None): self.context["messages"] = [] self.context["txnMessage"] = None self.msg_ctx.loop_once(0.001) GUID_RE = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" # # Is the supplied GUID string correctly formatted # def is_guid(self, guid): return re.match(self.GUID_RE, guid) def get_session(self): return self.auth_context["sessionId"] def get_service_description(self): return self.auth_context["serviceDescription"]
class AuthLogTestBase(samba.tests.TestCase): @classmethod def setUpClass(self): # connect to the server's messaging bus (we need to explicitly load a # different smb.conf here, because in all other respects this test # wants to act as a separate remote client) server_conf = os.getenv('SERVERCONFFILE') if server_conf: lp_ctx = LoadParm(filename_for_non_global_lp=server_conf) else: samba.tests.env_loadparm() self.msg_ctx = Messaging((1,), lp_ctx=lp_ctx) self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) # Now switch back to using the client-side smb.conf. The tests will # use the first interface in the client.conf (we need to strip off # the subnet mask portion) lp_ctx = samba.tests.env_loadparm() client_ip_and_mask = lp_ctx.get('interfaces')[0] client_ip = client_ip_and_mask.split('/')[0] # the messaging ctx is the server's view of the world, so our own # client IP will be the remoteAddress when connections are logged self.remoteAddress = client_ip def messageHandler(context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print(message) jsonMsg = json.loads(message) context["messages"].append(jsonMsg) self.context = {"messages": []} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.remoteAddress = None self.server = os.environ["SERVER"] self.connection = None @classmethod def tearDownClass(self): if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.msg_ctx.irpc_remove_name(AUTH_EVENT_NAME) def setUp(self): super(AuthLogTestBase, self).setUp() self.discardMessages() def waitForMessages(self, isLastExpectedMessage, connection=None): """Wait for all the expected messages to arrive The connection is passed through to keep the connection alive until all the logging messages have been received. """ def completed(messages): for message in messages: if isRemote(message) and isLastExpectedMessage(message): return True return False def isRemote(message): if self.remoteAddress is None: return True remote = None if message["type"] == "Authorization": remote = message["Authorization"]["remoteAddress"] elif message["type"] == "Authentication": remote = message["Authentication"]["remoteAddress"] else: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False self.connection = connection start_time = time.time() while not completed(self.context["messages"]): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None return [] self.connection = None return list(filter(isRemote, self.context["messages"])) # Discard any previously queued messages. @classmethod def discardMessages(self): self.msg_ctx.loop_once(0.001) while len(self.context["messages"]): self.context["messages"] = [] self.msg_ctx.loop_once(0.001) # Remove any NETLOGON authentication messages # NETLOGON is only performed once per session, so to avoid ordering # dependencies within the tests it's best to strip out NETLOGON messages. # def remove_netlogon_messages(self, messages): def is_not_netlogon(msg): if "Authentication" not in msg: return True sd = msg["Authentication"]["serviceDescription"] return sd != "NETLOGON" return list(filter(is_not_netlogon, messages)) GUID_RE = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" # # Is the supplied GUID string correctly formatted # def is_guid(self, guid): return re.match(self.GUID_RE, guid)
class AuthLogTestBase(samba.tests.TestCase): def setUp(self): super(AuthLogTestBase, self).setUp() lp_ctx = self.get_loadparm() self.msg_ctx = Messaging((1,), lp_ctx=lp_ctx) self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) def messageHandler(context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print(message) jsonMsg = json.loads(message) context["messages"].append(jsonMsg) self.context = {"messages": []} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.discardMessages() self.remoteAddress = None self.server = os.environ["SERVER"] self.connection = None def tearDown(self): if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.msg_ctx.irpc_remove_name(AUTH_EVENT_NAME) def waitForMessages(self, isLastExpectedMessage, connection=None): """Wait for all the expected messages to arrive The connection is passed through to keep the connection alive until all the logging messages have been received. """ def completed(messages): for message in messages: if isRemote(message) and isLastExpectedMessage(message): return True return False def isRemote(message): remote = None if message["type"] == "Authorization": remote = message["Authorization"]["remoteAddress"] elif message["type"] == "Authentication": remote = message["Authentication"]["remoteAddress"] else: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False self.connection = connection start_time = time.time() while not completed(self.context["messages"]): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None return [] self.connection = None return filter(isRemote, self.context["messages"]) # Discard any previously queued messages. def discardMessages(self): self.msg_ctx.loop_once(0.001) while len(self.context["messages"]): self.msg_ctx.loop_once(0.001) self.context["messages"] = [] # Remove any NETLOGON authentication messages # NETLOGON is only performed once per session, so to avoid ordering # dependencies within the tests it's best to strip out NETLOGON messages. # def remove_netlogon_messages(self, messages): def is_not_netlogon(msg): if "Authentication" not in msg: return True sd = msg["Authentication"]["serviceDescription"] return sd != "NETLOGON" return list(filter(is_not_netlogon, messages)) GUID_RE = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" # # Is the supplied GUID string correctly formatted # def is_guid(self, guid): return re.match(self.GUID_RE, guid)
class AuthLogTestBase(samba.tests.TestCase): def setUp(self): super(AuthLogTestBase, self).setUp() lp_ctx = self.get_loadparm() self.msg_ctx = Messaging((1,), lp_ctx=lp_ctx); self.msg_ctx.irpc_add_name(AUTH_EVENT_NAME) def messageHandler( context, msgType, src, message): # This does not look like sub unit output and it # makes these tests much easier to debug. print message jsonMsg = json.loads(message) context["messages"].append( jsonMsg) self.context = { "messages": []} self.msg_handler_and_context = (messageHandler, self.context) self.msg_ctx.register(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) self.discardMessages() self.remoteAddress = None self.server = os.environ["SERVER"] self.connection = None def tearDown(self): if self.msg_handler_and_context: self.msg_ctx.deregister(self.msg_handler_and_context, msg_type=MSG_AUTH_LOG) def waitForMessages(self, isLastExpectedMessage, connection=None): def completed( messages): for message in messages: if isRemote( message) and isLastExpectedMessage( message): return True return False def isRemote( message): remote = None if message["type"] == "Authorization": remote = message["Authorization"]["remoteAddress"] elif message["type"] == "Authentication": remote = message["Authentication"]["remoteAddress"] else: return False try: addr = remote.split(":") return addr[1] == self.remoteAddress except IndexError: return False self.connection = connection start_time = time.time() while not completed( self.context["messages"]): self.msg_ctx.loop_once(0.1) if time.time() - start_time > 1: self.connection = None return [] self.connection = None return filter( isRemote, self.context["messages"]) # Discard any previously queued messages. def discardMessages(self): self.msg_ctx.loop_once(0.001) while len( self.context["messages"]): self.msg_ctx.loop_once(0.001) self.context["messages"] = []