Check "auth event notification" param in log_json
[samba.git] / auth / auth_log.c
index 9ff2491dee313b4a172a98e396125295f90f12e3..c143ae306fb2bfd342ec302f8dd1e8822ff4cd02 100644 (file)
 #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"
 
 /*
  * Get a human readable timestamp.
@@ -62,7 +67,7 @@
  * It is the callers responsibility to free it.
  *
  */
-static const char* get_timestamp( TALLOC_CTX *frame )
+static const char* get_timestamp(TALLOC_CTX *frame)
 {
        char buffer[40];        /* formatted time less usec and timezone */
        char tz[10];            /* formatted time zone                   */
@@ -75,7 +80,7 @@ static const char* get_timestamp( TALLOC_CTX *frame )
        if (r) {
                DBG_ERR("Unable to get time of day: (%d) %s\n",
                        errno,
-                       strerror( errno));
+                       strerror(errno));
                return NULL;
        }
 
@@ -116,27 +121,107 @@ struct json_context {
        bool error;
 };
 
+static NTSTATUS get_auth_event_server(struct imessaging_context *msg_ctx,
+                                     struct server_id *auth_event_server)
+{
+       NTSTATUS status;
+       TALLOC_CTX *frame = talloc_stackframe();
+       unsigned num_servers, i;
+       struct server_id *servers;
+
+       status = irpc_servers_byname(msg_ctx, frame,
+                                    AUTH_EVENT_NAME,
+                                    &num_servers, &servers);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_NOTICE("Failed to find 'auth_event' registered on the "
+                          "message bus to send JSON authentication events to: %s\n",
+                          nt_errstr(status));
+               TALLOC_FREE(frame);
+               return status;
+       }
+
+       /*
+        * Select the first server that is listening, because
+        * we get connection refused as
+        * NT_STATUS_OBJECT_NAME_NOT_FOUND without waiting
+        */
+       for (i = 0; i < num_servers; i++) {
+               status = imessaging_send(msg_ctx, servers[i], MSG_PING,
+                                        &data_blob_null);
+               if (NT_STATUS_IS_OK(status)) {
+                       *auth_event_server = servers[i];
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_OK;
+               }
+       }
+       DBG_NOTICE("Failed to find a running 'auth_event' server "
+                  "registered on the message bus to send JSON "
+                  "authentication events to\n");
+       TALLOC_FREE(frame);
+       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+static void auth_message_send(struct imessaging_context *msg_ctx,
+                             const char *json)
+{
+       struct server_id auth_event_server;
+       NTSTATUS status;
+       DATA_BLOB json_blob = data_blob_string_const(json);
+       if (msg_ctx == NULL) {
+               return;
+       }
+
+       /* Need to refetch the address each time as the destination server may
+        * have disconnected and reconnected in the interim, in which case
+        * messages may get lost, manifests in the auth_log tests
+        */
+       status = get_auth_event_server(msg_ctx, &auth_event_server);
+       if (!NT_STATUS_IS_OK(status)) {
+               return;
+       }
+
+       status = imessaging_send(msg_ctx, auth_event_server, MSG_AUTH_LOG,
+                                &json_blob);
+
+       /* If the server crashed, try to find it again */
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               status = get_auth_event_server(msg_ctx, &auth_event_server);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return;
+               }
+               imessaging_send(msg_ctx, auth_event_server, MSG_AUTH_LOG,
+                               &json_blob);
+
+       }
+}
+
 /*
- * Write the json object to the debug lines.
+ * Write the json object to the debug logs.
  *
  */
-static void log_json( struct json_context *context,
+static void log_json(struct imessaging_context *msg_ctx,
+                    struct loadparm_context *lp_ctx,
+                    struct json_context *context,
                     const char *type, int debug_class, int debug_level)
 {
        char* json = NULL;
 
-       ifcontext->error) {
+       if (context->error) {
                return;
        }
 
-       json = json_dumps( context->root, 0);
+       json = json_dumps(context->root, 0);
        if (json == NULL) {
-               DBG_ERR( "Unable to convert JSON object to string\n");
+               DBG_ERR("Unable to convert JSON object to string\n");
                context->error = true;
                return;
        }
 
-       DEBUGC( debug_class, debug_level, ( "JSON %s: %s\n", type, json));
+       DEBUGC(debug_class, debug_level, ("JSON %s: %s\n", type, json));
+       if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
+               auth_message_send(msg_ctx, json);
+       }
 
        if (json) {
                free(json);
@@ -150,7 +235,7 @@ static void log_json( struct json_context *context,
  * Free with a call to free_json_context
  *
  */
-static struct json_context get_json_context( void) {
+static struct json_context get_json_context(void) {
 
        struct json_context context;
        context.error = false;
@@ -170,7 +255,7 @@ static struct json_context get_json_context( void) {
 static void free_json_context(struct json_context *context)
 {
        if (context->root) {
-               json_decref( context->root);
+               json_decref(context->root);
        }
 }
 
@@ -188,7 +273,7 @@ static void add_int(struct json_context *context,
                return;
        }
 
-       rc = json_object_set_new( context->root, name, json_integer( value));
+       rc = json_object_set_new(context->root, name, json_integer(value));
        if (rc) {
                DBG_ERR("Unable to set name [%s] value [%d]\n", name, value);
                context->error = true;
@@ -251,7 +336,7 @@ static void add_object(struct json_context *context,
  * "version":{"major":1,"minor":0}
  *
  */
-static void add_version( struct json_context *context, int major, int minor)
+static void add_version(struct json_context *context, int major, int minor)
 {
        struct json_context version = get_json_context();
        add_int(&version, "major", major);
@@ -265,7 +350,7 @@ static void add_version( struct json_context *context, int major, int minor)
  * "timestamp":"2017-03-06T17:18:04.455081+1300"
  *
  */
-static void add_timestamp( struct json_context *context)
+static void add_timestamp(struct json_context *context)
 {
        char buffer[40];        /* formatted time less usec and timezone */
        char timestamp[50];     /* the formatted ISO 8601 time stamp     */
@@ -282,7 +367,7 @@ static void add_timestamp( struct json_context *context)
        if (r) {
                DBG_ERR("Unable to get time of day: (%d) %s\n",
                        errno,
-                       strerror( errno));
+                       strerror(errno));
                context->error = true;
                return;
        }
@@ -366,6 +451,8 @@ static void add_sid(struct json_context *context,
  *           \t\(.Authentication.localAddress)"'
  */
 static void log_authentication_event_json(
+                       struct imessaging_context *msg_ctx,
+                       struct loadparm_context *lp_ctx,
                        const struct auth_usersupplied_info *ui,
                        NTSTATUS status,
                        const char *domain_name,
@@ -383,7 +470,7 @@ static void log_authentication_event_json(
 
        authentication = get_json_context();
        add_version(&authentication, AUTH_MAJOR, AUTH_MINOR);
-       add_string(&authentication, "status", nt_errstr( status));
+       add_string(&authentication, "status", nt_errstr(status));
        add_address(&authentication, "localAddress", ui->local_host);
        add_address(&authentication, "remoteAddress", ui->remote_host);
        add_string(&authentication,
@@ -415,10 +502,15 @@ static void log_authentication_event_json(
        add_sid(&authentication,
                "netlogonTrustAccountSid",
                ui->netlogon_trust_account.sid);
-       add_string(&authentication, "passwordType", get_password_type( ui));
+       add_string(&authentication, "passwordType", get_password_type(ui));
        add_object(&context,AUTH_JSON_TYPE, &authentication);
 
-       log_json(&context, AUTH_JSON_TYPE, DBGC_AUTH_AUDIT, debug_level);
+       log_json(msg_ctx,
+                lp_ctx,
+                &context,
+                AUTH_JSON_TYPE,
+                DBGC_AUTH_AUDIT,
+                debug_level);
        free_json_context(&context);
 }
 
@@ -443,6 +535,8 @@ static void log_authentication_event_json(
  *
  */
 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,
@@ -473,13 +567,15 @@ static void log_successful_authz_event_json(
        add_string(&authorization, "transportProtection", transport_protection);
 
        snprintf(account_flags,
-                sizeof( account_flags),
+                sizeof(account_flags),
                 "0x%08X",
                 session_info->info->acct_flags);
        add_string(&authorization, "accountFlags", account_flags);
        add_object(&context,AUTHZ_JSON_TYPE, &authorization);
 
-       log_json(&context,
+       log_json(msg_ctx,
+                lp_ctx,
+                &context,
                 AUTHZ_JSON_TYPE,
                 DBGC_AUTH_AUDIT,
                 debug_level);
@@ -488,7 +584,29 @@ static void log_successful_authz_event_json(
 
 #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 auth_usersupplied_info *ui,
                        NTSTATUS status,
                        const char *domain_name,
@@ -497,10 +615,13 @@ static void log_authentication_event_json(
                        struct dom_sid *sid,
                        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,
@@ -509,6 +630,7 @@ static void log_successful_authz_event_json(
                                struct auth_session_info *session_info,
                                int debug_level)
 {
+       log_no_json(msg_ctx, lp_ctx);
        return;
 }
 
@@ -524,9 +646,23 @@ static const char* get_password_type(const struct auth_usersupplied_info *ui)
 
        const char *password_type = NULL;
 
-       if (ui->password_state == AUTH_PASSWORD_RESPONSE &&
-           (ui->logon_parameters & MSV1_0_ALLOW_MSVCHAPV2) &&
-           ui->password.response.nt.length == 24) {
+       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)) {
@@ -576,7 +712,7 @@ static void log_authentication_event_human_readable(
 
        frame = talloc_stackframe();
 
-       password_type = get_password_type( ui);
+       password_type = get_password_type(ui);
        /* Get the current time */
         ts = get_timestamp(frame);
 
@@ -593,7 +729,7 @@ static void log_authentication_event_human_readable(
        }
 
        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];
@@ -612,8 +748,8 @@ static void log_authentication_event_human_readable(
                                log_escape(frame, ui->mapped.account_name));
        }
 
-       DEBUGC( DBGC_AUTH_AUDIT, debug_level, (
-               "Auth: [%s,%s] user [%s]\\[%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]"
@@ -624,13 +760,13 @@ static void log_authentication_event_human_readable(
                log_escape(frame, ui->client.account_name),
                ts,
                password_type,
-               nt_errstr( status),
+               nt_errstr(status),
                log_escape(frame, ui->workstation_name),
                remote,
                logon_line,
                local,
                nl ? nl : ""
-               ));
+              ));
 
        talloc_free(frame);
 }
@@ -642,7 +778,9 @@ static void log_authentication_event_human_readable(
  * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
  * authentication events over the message bus.
  */
-void log_authentication_event( const struct auth_usersupplied_info *ui,
+void log_authentication_event(struct imessaging_context *msg_ctx,
+                             struct loadparm_context *lp_ctx,
+                             const struct auth_usersupplied_info *ui,
                              NTSTATUS status,
                              const char *domain_name,
                              const char *account_name,
@@ -659,7 +797,7 @@ void log_authentication_event( const struct auth_usersupplied_info *ui,
                }
        }
 
-       if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
+       if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
                log_authentication_event_human_readable(ui,
                                                        status,
                                                        domain_name,
@@ -668,8 +806,10 @@ void log_authentication_event( const struct auth_usersupplied_info *ui,
                                                        sid,
                                                        debug_level);
        }
-       if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level)) {
-               log_authentication_event_json(ui,
+       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,
+                                             ui,
                                              status,
                                              domain_name,
                                              account_name,
@@ -708,14 +848,14 @@ static void log_successful_authz_event_human_readable(
         ts = get_timestamp(frame);
 
        remote_str = tsocket_address_string(remote, frame);
-       local_str  = tsocket_address_string(local, frame);
+       local_str = tsocket_address_string(local, frame);
 
        dom_sid_string_buf(&session_info->security_token->sids[0],
                           sid_buf,
                           sizeof(sid_buf));
 
-       DEBUGC( DBGC_AUTH_AUDIT, debug_level, (
-               "Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
+       DEBUGC(DBGC_AUTH_AUDIT, debug_level,
+              ("Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
                " at [%s]"
                " Remote host [%s]"
                " local host [%s]\n",
@@ -743,7 +883,9 @@ static void log_successful_authz_event_human_readable(
  * 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(const struct tsocket_address *remote,
+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,
@@ -757,7 +899,7 @@ void log_successful_authz_event(const struct tsocket_address *remote,
                debug_level = AUTH_ANONYMOUS_LEVEL;
        }
 
-       if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT, debug_level)) {
+       if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
                log_successful_authz_event_human_readable(remote,
                                                          local,
                                                          service_description,
@@ -766,8 +908,10 @@ void log_successful_authz_event(const struct tsocket_address *remote,
                                                          session_info,
                                                          debug_level);
        }
-       if (CHECK_DEBUGLVLC( DBGC_AUTH_AUDIT_JSON, debug_level)) {
-               log_successful_authz_event_json(remote,
+       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,