+static void log_authentication_event_json(
+ struct imessaging_context *msg_ctx,
+ struct loadparm_context *lp_ctx,
+ const struct timeval *start_time,
+ const struct auth_usersupplied_info *ui,
+ NTSTATUS status,
+ const char *domain_name,
+ const char *account_name,
+ const char *unix_username,
+ struct dom_sid *sid,
+ enum event_id_type event_id,
+ int debug_level)
+{
+ struct json_object wrapper = json_empty_object;
+ struct json_object authentication = json_empty_object;
+ char negotiate_flags[11];
+ int rc = 0;
+
+ authentication = json_new_object();
+ if (json_is_invalid(&authentication)) {
+ goto failure;
+ }
+ rc = json_add_version(&authentication, AUTH_MAJOR, AUTH_MINOR);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_int(&authentication,
+ "eventId",
+ event_id);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_int(&authentication, "logonType", get_logon_type(ui));
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&authentication, "status", nt_errstr(status));
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_address(&authentication, "localAddress", ui->local_host);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc =
+ json_add_address(&authentication, "remoteAddress", ui->remote_host);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "serviceDescription", ui->service_description);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "authDescription", ui->auth_description);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "clientDomain", ui->client.domain_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "clientAccount", ui->client.account_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "workstation", ui->workstation_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&authentication, "becameAccount", account_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&authentication, "becameDomain", domain_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_sid(&authentication, "becameSid", sid);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "mappedAccount", ui->mapped.account_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "mappedDomain", ui->mapped.domain_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&authentication,
+ "netlogonComputer",
+ ui->netlogon_trust_account.computer_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&authentication,
+ "netlogonTrustAccount",
+ ui->netlogon_trust_account.account_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ snprintf(negotiate_flags,
+ sizeof( negotiate_flags),
+ "0x%08X",
+ ui->netlogon_trust_account.negotiate_flags);
+ rc = json_add_string(
+ &authentication, "netlogonNegotiateFlags", negotiate_flags);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_int(&authentication,
+ "netlogonSecureChannelType",
+ ui->netlogon_trust_account.secure_channel_type);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_sid(&authentication,
+ "netlogonTrustAccountSid",
+ ui->netlogon_trust_account.sid);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authentication, "passwordType", get_password_type(ui));
+ if (rc != 0) {
+ goto failure;
+ }
+
+ wrapper = json_new_object();
+ if (json_is_invalid(&wrapper)) {
+ goto failure;
+ }
+ rc = json_add_timestamp(&wrapper);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&wrapper, "type", AUTH_JSON_TYPE);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_object(&wrapper, AUTH_JSON_TYPE, &authentication);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ /*
+ * While not a general-purpose profiling solution this will
+ * assist some to determine how long NTLM and KDC
+ * authentication takes once this process can handle it. This
+ * covers transactions elsewhere but not (eg) the delay while
+ * this is waiting unread on the input socket.
+ */
+ if (start_time != NULL) {
+ struct timeval current_time = timeval_current();
+ uint64_t duration = usec_time_diff(¤t_time,
+ start_time);
+ rc = json_add_int(&authentication, "duration", duration);
+ if (rc != 0) {
+ goto failure;
+ }
+ }
+
+ log_json(msg_ctx,
+ lp_ctx,
+ &wrapper,
+ DBGC_AUTH_AUDIT_JSON,
+ debug_level);
+ json_free(&wrapper);
+ return;
+failure:
+ /*
+ * On a failure authentication will not have been added to wrapper so it
+ * needs to be freed to avoid a leak.
+ *
+ */
+ json_free(&authentication);
+ json_free(&wrapper);
+ DBG_ERR("Failed to write authentication event JSON log message\n");
+}
+
+/*
+ * Log details of a successful authorization to a service,
+ * in a machine parsable json format
+ *
+ * IF removing or changing the format/meaning of a field please update the
+ * major version number AUTHZ_MAJOR
+ *
+ * IF adding a new field please update the minor version number AUTHZ_MINOR
+ *
+ * To process the resulting log lines from the commend line use jq to
+ * parse the json.
+ *
+ * grep "^ {" log_file |\
+ * jq -rc '"\(.timestamp)\t
+ * \(.Authorization.domain)\t
+ * \(.Authorization.account)\t
+ * \(.Authorization.remoteAddress)"'
+ *
+ */
+static void log_successful_authz_event_json(
+ struct imessaging_context *msg_ctx,
+ struct loadparm_context *lp_ctx,
+ const struct tsocket_address *remote,
+ const struct tsocket_address *local,
+ const char *service_description,
+ const char *auth_type,
+ const char *transport_protection,
+ struct auth_session_info *session_info,
+ int debug_level)
+{
+ struct json_object wrapper = json_empty_object;
+ struct json_object authorization = json_empty_object;
+ char account_flags[11];
+ int rc = 0;
+
+ authorization = json_new_object();
+ if (json_is_invalid(&authorization)) {
+ goto failure;
+ }
+ rc = json_add_version(&authorization, AUTHZ_MAJOR, AUTHZ_MINOR);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_address(&authorization, "localAddress", local);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_address(&authorization, "remoteAddress", remote);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authorization, "serviceDescription", service_description);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&authorization, "authType", auth_type);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authorization, "domain", session_info->info->domain_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authorization, "account", session_info->info->account_name);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_sid(
+ &authorization, "sid", &session_info->security_token->sids[0]);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_guid(
+ &authorization, "sessionId", &session_info->unique_session_token);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authorization, "logonServer", session_info->info->logon_server);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(
+ &authorization, "transportProtection", transport_protection);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ snprintf(account_flags,
+ sizeof(account_flags),
+ "0x%08X",
+ session_info->info->acct_flags);
+ rc = json_add_string(&authorization, "accountFlags", account_flags);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ wrapper = json_new_object();
+ if (json_is_invalid(&wrapper)) {
+ goto failure;
+ }
+ rc = json_add_timestamp(&wrapper);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_string(&wrapper, "type", AUTHZ_JSON_TYPE);
+ if (rc != 0) {
+ goto failure;
+ }
+ rc = json_add_object(&wrapper, AUTHZ_JSON_TYPE, &authorization);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ log_json(msg_ctx,
+ lp_ctx,
+ &wrapper,
+ DBGC_AUTH_AUDIT_JSON,
+ debug_level);
+ json_free(&wrapper);
+ return;
+failure:
+ /*
+ * On a failure authorization will not have been added to wrapper so it
+ * needs to be freed to avoid a leak.
+ *
+ */
+ json_free(&authorization);
+ json_free(&wrapper);
+ DBG_ERR("Unable to log Authentication event JSON audit message\n");
+}
+
+#else
+
+static void log_no_json(struct imessaging_context *msg_ctx,
+ struct loadparm_context *lp_ctx)
+{
+ if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
+ static bool auth_event_logged = false;
+ if (auth_event_logged == false) {
+ auth_event_logged = true;
+ DBG_ERR("auth event notification = true but Samba was "
+ "not compiled with jansson\n");
+ }
+ } else {
+ static bool json_logged = false;
+ if (json_logged == false) {
+ json_logged = true;
+ DBG_NOTICE("JSON auth logs not available unless "
+ "compiled with jansson\n");
+ }
+ }
+
+ return;
+}
+
+static void log_authentication_event_json(
+ struct imessaging_context *msg_ctx,
+ struct loadparm_context *lp_ctx,
+ const struct timeval *start_time,
+ const struct auth_usersupplied_info *ui,
+ NTSTATUS status,
+ const char *domain_name,
+ const char *account_name,
+ const char *unix_username,
+ struct dom_sid *sid,
+ enum event_id_type event_id,
+ int debug_level)
+{
+ log_no_json(msg_ctx, lp_ctx);
+ return;
+}
+
+static void log_successful_authz_event_json(
+ struct imessaging_context *msg_ctx,
+ struct loadparm_context *lp_ctx,
+ const struct tsocket_address *remote,
+ const struct tsocket_address *local,
+ const char *service_description,
+ const char *auth_type,
+ const char *transport_protection,
+ struct auth_session_info *session_info,
+ int debug_level)
+{
+ log_no_json(msg_ctx, lp_ctx);
+ return;
+}
+
+#endif
+
+/*
+ * Determine the type of the password supplied for the
+ * authorisation attempt.
+ *
+ */
+static const char* get_password_type(const struct auth_usersupplied_info *ui)
+{
+
+ const char *password_type = NULL;
+
+ if (ui->password_type != NULL) {
+ password_type = ui->password_type;
+ } else if (ui->auth_description != NULL &&
+ strncmp("ServerAuthenticate", ui->auth_description, 18) == 0)
+ {
+ if (ui->netlogon_trust_account.negotiate_flags
+ & NETLOGON_NEG_SUPPORTS_AES) {
+ password_type = "HMAC-SHA256";
+ } else if (ui->netlogon_trust_account.negotiate_flags
+ & NETLOGON_NEG_STRONG_KEYS) {
+ password_type = "HMAC-MD5";
+ } else {
+ password_type = "DES";
+ }
+ } else if (ui->password_state == AUTH_PASSWORD_RESPONSE &&
+ (ui->logon_parameters & MSV1_0_ALLOW_MSVCHAPV2) &&
+ ui->password.response.nt.length == 24) {
+ password_type = "MSCHAPv2";
+ } else if ((ui->logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED)
+ || (ui->password_state == AUTH_PASSWORD_PLAIN)) {
+ password_type = "Plaintext";
+ } else if (ui->password_state == AUTH_PASSWORD_HASH) {
+ password_type = "Supplied-NT-Hash";
+ } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+ && ui->password.response.nt.length > 24) {
+ password_type = "NTLMv2";
+ } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+ && ui->password.response.nt.length == 24) {
+ password_type = "NTLMv1";
+ } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+ && ui->password.response.lanman.length == 24) {
+ password_type = "LANMan";
+ } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
+ && ui->password.response.nt.length == 0
+ && ui->password.response.lanman.length == 0) {
+ password_type = "No-Password";
+ }
+ return password_type;
+}
+
+/*
+ * Write a human readable authentication log entry.
+ *
+ */
+static void log_authentication_event_human_readable(
+ const struct auth_usersupplied_info *ui,
+ NTSTATUS status,
+ const char *domain_name,
+ const char *account_name,
+ const char *unix_username,
+ struct dom_sid *sid,
+ int debug_level)