auth log: Increment Authentication version
[vlendec/samba-autobuild/.git] / auth / auth_log.c
index 64b6eaa102cd72348cd3887a61e268c7fb2a71ef..8f1ae61a99ec4030d48e2096f94207a6347205b0 100644 (file)
  * Debug log levels for authentication logging (these both map to
  * LOG_NOTICE in syslog)
  */
-#define AUTH_SUCCESS_LEVEL 4
-#define AUTHZ_SUCCESS_LEVEL 5
 #define AUTH_FAILURE_LEVEL 2
+#define AUTH_SUCCESS_LEVEL 3
+#define AUTHZ_SUCCESS_LEVEL 4
+
+/* 5 is used for both authentication and authorization */
+#define AUTH_ANONYMOUS_LEVEL 5
+#define AUTHZ_ANONYMOUS_LEVEL 5
+
+#define AUTHZ_JSON_TYPE "Authorization"
+#define AUTH_JSON_TYPE  "Authentication"
+
+/*
+ * JSON message version numbers
+ *
+ * If adding a field increment the minor version
+ * If removing or changing the format/meaning of a field
+ * increment the major version.
+ */
+#define AUTH_MAJOR 1
+#define AUTH_MINOR 1
+#define AUTHZ_MAJOR 1
+#define AUTHZ_MINOR 1
 
 #include "includes.h"
 #include "../lib/tsocket/tsocket.h"
 #include "common_auth.h"
 #include "lib/util/util_str_escape.h"
 #include "libcli/security/dom_sid.h"
+#include "libcli/security/security_token.h"
+#include "librpc/gen_ndr/server_id.h"
+#include "source4/lib/messaging/messaging.h"
+#include "source4/lib/messaging/irpc.h"
+#include "lib/util/server_id_db.h"
+#include "lib/param/param.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/windows_event_ids.h"
+#include "lib/audit_logging/audit_logging.h"
+
+/*
+ * Determine the type of the password supplied for the
+ * authorisation attempt.
+ *
+ */
+static const char* get_password_type(const struct auth_usersupplied_info *ui);
+
+#ifdef HAVE_JANSSON
+
+#include <jansson.h>
+#include "system/time.h"
 
 /*
- * Get a human readable timestamp.
+ * Write the json object to the debug logs.
  *
- * Returns the current time formatted as
- *  "Tue, 14 Mar 2017 08:38:42.209028 NZDT"
+ */
+static void log_json(struct imessaging_context *msg_ctx,
+                    struct loadparm_context *lp_ctx,
+                    struct json_object *object,
+                    int debug_class,
+                    int debug_level)
+{
+       audit_log_json(object, debug_class, debug_level);
+       if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
+               audit_message_send(msg_ctx,
+                                  AUTH_EVENT_NAME,
+                                  MSG_AUTH_LOG,
+                                  object);
+       }
+}
+
+/*
+ * Determine the Windows logon type for the current authorisation attempt.
+ *
+ * Currently Samba only supports
  *
- * The returned string is allocated by talloc in the supplied context.
- * It is the callers responsibility to free it.
+ * 2 Interactive      A user logged on to this computer.
+ * 3 Network          A user or computer logged on to this computer from
+ *                    the network.
+ * 8 NetworkCleartext A user logged on to this computer from the network.
+ *                    The user's password was passed to the authentication
+ *                    package in its unhashed form.
  *
  */
-static const char* get_timestamp( TALLOC_CTX *frame )
+static enum event_logon_type get_logon_type(
+       const struct auth_usersupplied_info *ui)
 {
-       char buffer[40];        /* formatted time less usec and timezone */
-       char tz[10];            /* formatted time zone                   */
-       struct tm* tm_info;     /* current local time                    */
-       struct timeval tv;      /* current system time                   */
-       int r;                  /* response code from gettimeofday       */
-       const char * ts;        /* formatted time stamp                  */
-
-       r = gettimeofday(&tv, NULL);
-       if (r) {
-               DBG_ERR("Unable to get time of day: (%d) %s\n",
-                       errno,
-                       strerror( errno));
-               return NULL;
-       }
-
-       tm_info = localtime(&tv.tv_sec);
-       if (tm_info == NULL) {
-               DBG_ERR("Unable to determine local time\n");
-               return NULL;
-       }
-
-       strftime(buffer, sizeof(buffer)-1, "%a, %d %b %Y %H:%M:%S", tm_info);
-       strftime(tz, sizeof(tz)-1, "%Z", tm_info);
-       ts = talloc_asprintf(frame, "%s.%06ld %s", buffer, tv.tv_usec, tz);
-       if (ts == NULL) {
-               DBG_ERR("Out of memory formatting time stamp\n");
-       }
-       return ts;
+       if ((ui->logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED)
+          || (ui->password_state == AUTH_PASSWORD_PLAIN)) {
+               return EVT_LOGON_NETWORK_CLEAR_TEXT;
+       } else if (ui->flags & USER_INFO_INTERACTIVE_LOGON) {
+               return EVT_LOGON_INTERACTIVE;
+       }
+       return EVT_LOGON_NETWORK;
 }
 
 /*
- * Log details of an authentication attempt.
- * Successful and unsuccessful attempts are logged.
+ * Write a machine parsable json formatted authentication log entry.
  *
+ * IF removing or changing the format/meaning of a field please update the
+ *    major version number AUTH_MAJOR
+ *
+ * IF adding a new field please update the minor version number AUTH_MINOR
+ *
+ *  To process the resulting log lines from the commend line use jq to
+ *  parse the json.
+ *
+ *  grep "^  {" log file |
+ *  jq -rc '"\(.timestamp)\t\(.Authentication.status)\t
+ *           \(.Authentication.clientDomain)\t
+ *           \(.Authentication.clientAccount)
+ *           \t\(.Authentication.workstation)
+ *           \t\(.Authentication.remoteAddress)
+ *           \t\(.Authentication.localAddress)"'
  */
-void log_authentication_event(const struct auth_usersupplied_info *ui,
-                             NTSTATUS status,
-                             const char *domain_name,
-                             const char *account_name,
-                             const char *unix_username,
-                             struct dom_sid *sid)
+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(&current_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)
 {
        TALLOC_CTX *frame = NULL;
 
@@ -95,17 +587,13 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
        char *trust_computer_name = NULL;
        char *trust_account_name = NULL;
        char *logon_line = NULL;
-
-       /* set the log level */
-       int  level = NT_STATUS_IS_OK(status) ? AUTH_FAILURE_LEVEL : AUTH_SUCCESS_LEVEL;
-       if (!CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, level)) {
-               return;
-       }
+       const char *password_type = NULL;
 
        frame = talloc_stackframe();
 
+       password_type = get_password_type(ui);
        /* Get the current time */
-        ts = get_timestamp(frame);
+        ts = audit_get_timestamp(frame);
 
        /* Only log the NETLOGON details if they are present */
        if (ui->netlogon_trust_account.computer_name ||
@@ -120,27 +608,27 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
        }
 
        remote = tsocket_address_string(ui->remote_host, frame);
-       local  = tsocket_address_string(ui->local_host, frame);
+       local = tsocket_address_string(ui->local_host, frame);
 
        if (NT_STATUS_IS_OK(status)) {
-               char sid_buf[DOM_SID_STR_BUFLEN];
+               struct dom_sid_buf sid_buf;
 
-               dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
                logon_line = talloc_asprintf(frame,
                                             " became [%s]\\[%s] [%s].",
                                             log_escape(frame, domain_name),
                                             log_escape(frame, account_name),
-                                            sid_buf);
+                                            dom_sid_str_buf(sid, &sid_buf));
        } else {
-               logon_line = talloc_asprintf(frame,
-                                            " mapped to [%s]\\[%s].",
-                                            log_escape(frame, ui->mapped.domain_name),
-                                            log_escape(frame, ui->mapped.account_name));
+               logon_line = talloc_asprintf(
+                               frame,
+                               " mapped to [%s]\\[%s].",
+                               log_escape(frame, ui->mapped.domain_name),
+                               log_escape(frame, ui->mapped.account_name));
        }
 
-       DEBUGC( DBGC_AUTH_AUDIT, level, (
-               "Auth: [%s,%s] user [%s]\\[%s]"
-               " at [%s] status [%s]"
+       DEBUGC(DBGC_AUTH_AUDIT, debug_level,
+              ("Auth: [%s,%s] user [%s]\\[%s]"
+               " at [%s] with [%s] status [%s]"
                " workstation [%s] remote host [%s]"
                "%s local host [%s]"
                " %s\n",
@@ -149,13 +637,169 @@ void log_authentication_event(const struct auth_usersupplied_info *ui,
                log_escape(frame, ui->client.domain_name),
                log_escape(frame, ui->client.account_name),
                ts,
-               nt_errstr( status),
+               password_type,
+               nt_errstr(status),
                log_escape(frame, ui->workstation_name),
                remote,
                logon_line,
                local,
                nl ? nl : ""
-               ));
+       ));
+
+       talloc_free(frame);
+}
+
+/*
+ * Log details of an authentication attempt.
+ * Successful and unsuccessful attempts are logged.
+ *
+ * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
+ * authentication events over the message bus.
+ */
+void log_authentication_event(
+       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)
+{
+       /* set the log level */
+       int debug_level = AUTH_FAILURE_LEVEL;
+       enum event_id_type event_id = EVT_ID_UNSUCCESSFUL_LOGON;
+
+       if (NT_STATUS_IS_OK(status)) {
+               debug_level = AUTH_SUCCESS_LEVEL;
+               event_id = EVT_ID_SUCCESSFUL_LOGON;
+               if (dom_sid_equal(sid, &global_sid_Anonymous)) {
+                       debug_level = AUTH_ANONYMOUS_LEVEL;
+               }
+       }
+
+       if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
+               log_authentication_event_human_readable(ui,
+                                                       status,
+                                                       domain_name,
+                                                       account_name,
+                                                       unix_username,
+                                                       sid,
+                                                       debug_level);
+       }
+       if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT_JSON, debug_level) ||
+           (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
+               log_authentication_event_json(msg_ctx,
+                                             lp_ctx,
+                                             start_time,
+                                             ui,
+                                             status,
+                                             domain_name,
+                                             account_name,
+                                             unix_username,
+                                             sid,
+                                             event_id,
+                                             debug_level);
+       }
+}
+
+
+
+/*
+ * Log details of a successful authorization to a service,
+ * in a human readable format.
+ *
+ */
+static void log_successful_authz_event_human_readable(
+       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)
+{
+       TALLOC_CTX *frame = NULL;
+
+       const char *ts = NULL;       /* formatted current time      */
+       char *remote_str = NULL;     /* formatted remote host       */
+       char *local_str = NULL;      /* formatted local host        */
+       struct dom_sid_buf sid_buf;
+
+       frame = talloc_stackframe();
+
+       /* Get the current time */
+        ts = audit_get_timestamp(frame);
+
+       remote_str = tsocket_address_string(remote, frame);
+       local_str = tsocket_address_string(local, frame);
+
+       DEBUGC(DBGC_AUTH_AUDIT, debug_level,
+              ("Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
+               " at [%s]"
+               " Remote host [%s]"
+               " local host [%s]\n",
+               service_description,
+               auth_type,
+               log_escape(frame, session_info->info->domain_name),
+               log_escape(frame, session_info->info->account_name),
+               dom_sid_str_buf(&session_info->security_token->sids[0],
+                               &sid_buf),
+               ts,
+               remote_str,
+               local_str));
 
        talloc_free(frame);
 }
+
+/*
+ * Log details of a successful authorization to a service.
+ *
+ * Only successful authorizations are logged.  For clarity:
+ * - NTLM bad passwords will be recorded by log_authentication_event
+ * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
+ *
+ * The service may later refuse authorization due to an ACL.
+ *
+ * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
+ * authentication events over the message bus.
+ */
+void log_successful_authz_event(
+       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 = AUTHZ_SUCCESS_LEVEL;
+
+       /* set the log level */
+       if (security_token_is_anonymous(session_info->security_token)) {
+               debug_level = AUTH_ANONYMOUS_LEVEL;
+       }
+
+       if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
+               log_successful_authz_event_human_readable(remote,
+                                                         local,
+                                                         service_description,
+                                                         auth_type,
+                                                         transport_protection,
+                                                         session_info,
+                                                         debug_level);
+       }
+       if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT_JSON, debug_level) ||
+           (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
+               log_successful_authz_event_json(msg_ctx, lp_ctx,
+                                               remote,
+                                               local,
+                                               service_description,
+                                               auth_type,
+                                               transport_protection,
+                                               session_info,
+                                               debug_level);
+       }
+}