diff --git a/Source/santad/Logs/EndpointSecurity/Serializers/BasicString.mm b/Source/santad/Logs/EndpointSecurity/Serializers/BasicString.mm index 7fea65b34..8f7fc495a 100644 --- a/Source/santad/Logs/EndpointSecurity/Serializers/BasicString.mm +++ b/Source/santad/Logs/EndpointSecurity/Serializers/BasicString.mm @@ -185,6 +185,62 @@ static inline void AppendInstigator(std::string &str, const EnrichedEventType &e event.instigator().real_group()); } +#if HAVE_MACOS_13 + +static inline void AppendEventUser(std::string &str, const es_string_token_t &user, + std::optional uid) { + if (user.length > 0) { + str.append("|event_user="); + str.append(user.data); + } + + if (uid.has_value()) { + str.append("|event_uid="); + str.append(std::to_string(uid.value())); + } +} + +static inline void AppendGraphicalSession(std::string &str, es_graphical_session_id_t session_id) { + str.append("|graphical_session_id="); + str.append(std::to_string(session_id)); +} + +static inline void AppendSocketAddress(std::string &str, es_address_type_t type, + es_string_token_t addr) { + str.append("|address_type="); + switch (type) { + case ES_ADDRESS_TYPE_NONE: str.append("none"); break; + case ES_ADDRESS_TYPE_IPV4: str.append("ipv4"); break; + case ES_ADDRESS_TYPE_IPV6: str.append("ipv6"); break; + case ES_ADDRESS_TYPE_NAMED_SOCKET: str.append("named_socket"); break; + default: str.append("unknown"); break; + } + + if (addr.length > 0) { + str.append("|address="); + str.append(SanitizableString(addr).Sanitized()); + } +} + +static inline std::string GetOpenSSHLoginResult(std::string &str, + es_openssh_login_result_type_t result) { + switch (result) { + case ES_OPENSSH_LOGIN_EXCEED_MAXTRIES: return "LOGIN_EXCEED_MAXTRIES"; + case ES_OPENSSH_LOGIN_ROOT_DENIED: return "LOGIN_ROOT_DENIED"; + case ES_OPENSSH_AUTH_SUCCESS: return "AUTH_SUCCESS"; + case ES_OPENSSH_AUTH_FAIL_NONE: return "AUTH_FAIL_NONE"; + case ES_OPENSSH_AUTH_FAIL_PASSWD: return "AUTH_FAIL_PASSWD"; + case ES_OPENSSH_AUTH_FAIL_KBDINT: return "AUTH_FAIL_KBDINT"; + case ES_OPENSSH_AUTH_FAIL_PUBKEY: return "AUTH_FAIL_PUBKEY"; + case ES_OPENSSH_AUTH_FAIL_HOSTBASED: return "AUTH_FAIL_HOSTBASED"; + case ES_OPENSSH_AUTH_FAIL_GSSAPI: return "AUTH_FAIL_GSSAPI"; + case ES_OPENSSH_INVALID_USER: return "INVALID_USER"; + default: return "UNKNOWN"; + } +} + +#endif // HAVE_MACOS_13 + static char *FormattedDateString(char *buf, size_t len) { struct timeval tv; struct tm tm; @@ -434,46 +490,174 @@ static inline void AppendInstigator(std::string &str, const EnrichedEventType &e } #if HAVE_MACOS_13 + std::vector BasicString::SerializeMessage(const EnrichedLoginWindowSessionLogin &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=LOGIN_WINDOW_SESSION_LOGIN"); + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.lw_session_login->username, msg.UID()); + AppendGraphicalSession(str, msg->event.lw_session_login->graphical_session_id); + + return FinalizeString(str); }; std::vector BasicString::SerializeMessage(const EnrichedLoginWindowSessionLogout &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=LOGIN_WINDOW_SESSION_LOGOUT"); + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.lw_session_logout->username, msg.UID()); + AppendGraphicalSession(str, msg->event.lw_session_logout->graphical_session_id); + + return FinalizeString(str); }; std::vector BasicString::SerializeMessage(const EnrichedLoginWindowSessionLock &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=LOGIN_WINDOW_SESSION_LOCK"); + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.lw_session_lock->username, msg.UID()); + AppendGraphicalSession(str, msg->event.lw_session_lock->graphical_session_id); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedLoginWindowSessionUnlock &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=LOGIN_WINDOW_SESSION_UNLOCK"); + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.lw_session_unlock->username, msg.UID()); + AppendGraphicalSession(str, msg->event.lw_session_unlock->graphical_session_id); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedScreenSharingAttach &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=SCREEN_SHARING_ATTACH|success="); + str.append(msg->event.screensharing_attach->success ? "true" : "false"); + + AppendSocketAddress(str, msg->event.screensharing_attach->source_address_type, + msg->event.screensharing_attach->source_address); + + if (msg->event.screensharing_attach->viewer_appleid.length > 0) { + str.append("|viewer="); + str.append(SanitizableString(msg->event.screensharing_attach->viewer_appleid).Sanitized()); + } + + if (msg->event.screensharing_attach->authentication_type.length > 0) { + str.append("|auth_type="); + str.append(SanitizableString(msg->event.screensharing_attach->authentication_type).Sanitized()); + } + + if (msg->event.screensharing_attach->authentication_username.length > 0) { + str.append("|auth_user="); + str.append( + SanitizableString(msg->event.screensharing_attach->authentication_username).Sanitized()); + } + + if (msg->event.screensharing_attach->session_username.length > 0) { + str.append("|session_user="); + str.append(SanitizableString(msg->event.screensharing_attach->session_username).Sanitized()); + } + + str.append("|existing_session="); + str.append(msg->event.screensharing_attach->existing_session ? "true" : "false"); + + AppendInstigator(str, msg); + AppendGraphicalSession(str, msg->event.screensharing_attach->graphical_session_id); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedScreenSharingDetach &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=SCREEN_SHARING_DETACH"); + + AppendSocketAddress(str, msg->event.screensharing_detach->source_address_type, + msg->event.screensharing_detach->source_address); + + if (msg->event.screensharing_detach->viewer_appleid.length > 0) { + str.append("|viewer="); + str.append(SanitizableString(msg->event.screensharing_detach->viewer_appleid).Sanitized()); + } + + AppendInstigator(str, msg); + AppendGraphicalSession(str, msg->event.screensharing_detach->graphical_session_id); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedOpenSSHLogin &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=OPENSSH_LOGIN|success="); + str.append(msg->event.openssh_login->success ? "true" : "false"); + str.append("|result_type="); + str.append(GetOpenSSHLoginResult(str, msg->event.openssh_login->result_type)); + + AppendSocketAddress(str, msg->event.openssh_login->source_address_type, + msg->event.openssh_login->source_address); + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.openssh_login->username, + msg->event.openssh_login->has_uid + ? std::make_optional(msg->event.openssh_login->uid.uid) + : std::nullopt); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedOpenSSHLogout &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=OPENSSH_LOGOUT"); + + AppendSocketAddress(str, msg->event.openssh_logout->source_address_type, + msg->event.openssh_logout->source_address); + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.openssh_logout->username, + std::make_optional(msg->event.openssh_logout->uid)); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedLoginLogin &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=LOGIN|success="); + str.append(msg->event.login_login->success ? "true" : "false"); + if (!msg->event.login_login->success) { + str.append("|failure="); + str.append(SanitizableString(msg->event.login_login->failure_message).Sanitized()); + } + + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.login_login->username, + msg->event.login_login->has_uid + ? std::make_optional(msg->event.login_login->uid.uid) + : std::nullopt); + + return FinalizeString(str); } std::vector BasicString::SerializeMessage(const EnrichedLoginLogout &msg) { - return {}; + std::string str = CreateDefaultString(); + + str.append("action=LOGOUT"); + + AppendInstigator(str, msg); + AppendEventUser(str, msg->event.login_logout->username, + std::make_optional(msg->event.login_logout->uid)); + + return FinalizeString(str); } -#endif + +#endif // HAVE_MACOS_13 std::vector BasicString::SerializeFileAccess(const std::string &policy_version, const std::string &policy_name, diff --git a/Source/santad/Logs/EndpointSecurity/Serializers/BasicStringTest.mm b/Source/santad/Logs/EndpointSecurity/Serializers/BasicStringTest.mm index c54f521c8..9dce80edf 100644 --- a/Source/santad/Logs/EndpointSecurity/Serializers/BasicStringTest.mm +++ b/Source/santad/Logs/EndpointSecurity/Serializers/BasicStringTest.mm @@ -266,6 +266,248 @@ - (void)testSerializeMessageCSInvalidated { XCTAssertCppStringEqual(got, want); } +#if HAVE_MACOS_13 + +- (void)testSerializeMessageLoginWindowSessionLogin { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN, &proc); + es_event_lw_session_login_t lwLogin = { + .username = MakeESStringToken("daemon"), + .graphical_session_id = 123, + }; + + esMsg.event.lw_session_login = &lwLogin; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=LOGIN_WINDOW_SESSION_LOGIN|pid=12|ppid=56|process=foo|processpath=foo|" + "uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|" + "graphical_session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageLoginWindowSessionLogout { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT, &proc); + es_event_lw_session_logout_t lwLogout = { + .username = MakeESStringToken("daemon"), + .graphical_session_id = 123, + }; + + esMsg.event.lw_session_logout = &lwLogout; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=LOGIN_WINDOW_SESSION_LOGOUT|pid=12|ppid=56|process=foo|processpath=" + "foo|uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|" + "graphical_session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageLoginWindowSessionLock { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK, &proc); + es_event_lw_session_lock_t lwLock = { + .username = MakeESStringToken("daemon"), + .graphical_session_id = 123, + }; + + esMsg.event.lw_session_lock = &lwLock; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=LOGIN_WINDOW_SESSION_LOCK|pid=12|ppid=56|process=foo|processpath=foo|" + "uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|" + "graphical_session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageLoginWindowSessionUnlock { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK, &proc); + es_event_lw_session_unlock_t lwUnlock = { + .username = MakeESStringToken("daemon"), + .graphical_session_id = 123, + }; + + esMsg.event.lw_session_unlock = &lwUnlock; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=LOGIN_WINDOW_SESSION_UNLOCK|pid=12|ppid=56|process=foo|processpath=" + "foo|uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|" + "graphical_session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageLoginLogin { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN, &proc); + es_event_login_login_t login = { + .success = false, + .failure_message = MakeESStringToken("my|failure"), + .username = MakeESStringToken("asdf"), + .has_uid = false, + }; + esMsg.event.login_login = &login; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = + "action=LOGIN|success=false|failure=myfailure|pid=12|ppid=56|process=foo|processpath=foo|" + "uid=-2|user=nobody|gid=-1|group=nogroup|event_user=asdf|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); + + login.success = true; + login.has_uid = true; + login.uid.uid = 123; + + got = BasicStringSerializeMessage(&esMsg); + want = "action=LOGIN|success=true|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|" + "gid=-1|group=nogroup|event_user=asdf|event_uid=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageLoginLogout { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT, &proc); + es_event_login_logout_t logout{ + .username = MakeESStringToken("asdf"), + .uid = 123, + }; + esMsg.event.login_logout = &logout; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=LOGOUT|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|" + "gid=-1|group=nogroup|event_user=asdf|event_uid=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageScreenSharingAttach { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH, &proc); + es_event_screensharing_attach_t attach{ + .success = true, + .source_address_type = ES_ADDRESS_TYPE_IPV6, + .source_address = MakeESStringToken("::1"), + .viewer_appleid = MakeESStringToken("foo@example.com"), + .authentication_type = MakeESStringToken("idk"), + .authentication_username = MakeESStringToken("my_auth_user"), + .session_username = MakeESStringToken("my_session_user"), + .existing_session = true, + .graphical_session_id = 123, + }; + esMsg.event.screensharing_attach = &attach; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = + "action=SCREEN_SHARING_ATTACH|success=true|address_type=ipv6|address=::1|viewer=foo@example." + "com|auth_type=idk|auth_user=my_auth_user|session_user=my_session_user|existing_session=true|" + "pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=nogroup|graphical_" + "session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); + + attach.source_address_type = (es_address_type_t)1234; // Intentionally bad + attach.source_address = MakeESStringToken(NULL); + attach.viewer_appleid = MakeESStringToken(NULL); + attach.authentication_type = MakeESStringToken(NULL); + attach.authentication_username = MakeESStringToken(NULL); + attach.session_username = MakeESStringToken(NULL); + + got = BasicStringSerializeMessage(&esMsg); + want = "action=SCREEN_SHARING_ATTACH|success=true|address_type=unknown|existing_session=true|pid=" + "12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=nogroup|graphical_" + "session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageScreenSharingDetach { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH, &proc); + es_event_screensharing_detach_t detach{ + .source_address_type = ES_ADDRESS_TYPE_IPV4, + .source_address = MakeESStringToken("1.2.3.4"), + .viewer_appleid = MakeESStringToken("foo@example.com"), + .graphical_session_id = 123, + }; + esMsg.event.screensharing_detach = &detach; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=SCREEN_SHARING_DETACH|address_type=ipv4|address=1.2.3.4|viewer=foo@" + "example.com|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|" + "gid=-1|group=nogroup|graphical_session_id=123|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageOpenSSHLogin { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN, &proc); + es_event_openssh_login_t login{ + .success = false, + .result_type = ES_OPENSSH_AUTH_FAIL_PASSWD, + .source_address_type = ES_ADDRESS_TYPE_NAMED_SOCKET, + .source_address = MakeESStringToken("foo"), + .username = MakeESStringToken("my_user"), + .has_uid = false, + }; + esMsg.event.openssh_login = &login; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=OPENSSH_LOGIN|success=false|result_type=AUTH_FAIL_PASSWD|address_type=" + "named_socket|address=foo|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|" + "user=nobody|gid=-1|group=nogroup|event_user=my_user|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); + + login.success = true; + login.result_type = ES_OPENSSH_AUTH_SUCCESS; + login.has_uid = true; + login.uid.uid = 456; + + got = BasicStringSerializeMessage(&esMsg); + want = "action=OPENSSH_LOGIN|success=true|result_type=AUTH_SUCCESS|address_type=named_socket|" + "address=foo|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=" + "nogroup|event_user=my_user|event_uid=456|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +- (void)testSerializeMessageOpenSSHLogout { + es_file_t procFile = MakeESFile("foo"); + es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78)); + es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT, &proc); + es_event_openssh_logout_t logout{ + .source_address_type = ES_ADDRESS_TYPE_IPV4, + .source_address = MakeESStringToken("5.6.7.8"), + .username = MakeESStringToken("my_user"), + .uid = 321, + }; + esMsg.event.openssh_logout = &logout; + + std::string got = BasicStringSerializeMessage(&esMsg); + std::string want = "action=OPENSSH_LOGOUT|address_type=ipv4|address=5.6.7.8|pid=12|ppid=56|" + "process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=nogroup|event_" + "user=my_user|event_uid=321|machineid=my_id\n"; + + XCTAssertCppStringEqual(got, want); +} + +#endif // HAVE_MACOS_13 + - (void)testGetAccessTypeString { std::map accessTypeToString = { {ES_EVENT_TYPE_AUTH_OPEN, "OPEN"}, {ES_EVENT_TYPE_AUTH_LINK, "LINK"},