heimdal: Pass extra information to hdb_auth_status() to log success and failures
authorAndrew Bartlett <abartlet@samba.org>
Tue, 21 Feb 2017 01:07:54 +0000 (14:07 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 29 Mar 2017 00:37:28 +0000 (02:37 +0200)
We now pass on the original client name and the client address to allow
consistent audit logging in Samba across multiple protocols.

We use config->db[0] to find the first database to record incorrect
users.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
auth/auth_log.c
auth/common_auth.h
selftest/knownfail
source4/heimdal/kdc/kerberos5.c
source4/heimdal/lib/hdb/hdb.h
source4/kdc/db-glue.c
source4/kdc/hdb-samba4.c
source4/kdc/kdc-heimdal.c
source4/kdc/samba_kdc.h

index 63b531ca1a07dc3b4dd1e98b029fd091b99cfc7e..cec135e45cf3f9650370f488480139ef9f237f6c 100644 (file)
@@ -637,9 +637,11 @@ 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->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)) {
index db59cbb99f3423dc71fef5a89681af0269f9cd26..507971794f3b3068f7fdf562ca67e46ed2150ae6 100644 (file)
@@ -83,6 +83,13 @@ struct auth_usersupplied_info
 
        const char *service_description;
        const char *auth_description;
+
+       /*
+        * for logging only, normally worked out from the password but
+        * for krb5 logging only (krb5 normally doesn't use this) we
+        * record the enc type here
+        */
+       const char *password_type;
 };
 
 struct auth_method_context;
index e85a8a669075b77f51313c81e7da939eae975b9e..b25038064c3c458811d46f06f4e0e473ec8abaad 100644 (file)
 ^samba3.smb2.credits.skipped_mid.*
 ^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dangling_multi_valued_dbcheck
 ^samba4.blackbox.dbcheck-links.release-4-5-0-pre1.dangling_multi_valued_check_missing
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_ldap\(
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_ip_tcp_krb5_dns
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_ip_tcp_krb5_dns_connect
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_ip_tcp_krb5_dns_seal
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_ip_tcp_krb5_dns_sign
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_np_krb_dns
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_np_krb_dns_sign
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_np_krb_dns_smb2
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_np_krb_srv
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_rpc_ncacn_np_krb_srv_sign
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_smb\(
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_smb_bad_password
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_smb_bad_user
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_smb_bad_user_and_password
-^samba.tests.auth_log.samba.tests.auth_log.AuthLogTests.test_smb_default_connect
index bd339b343a5b11640f68de0ede463f2b05c29db2..4baf90e41d8728d6701fc1919bb924417075d440 100644 (file)
@@ -1090,6 +1090,13 @@ _kdc_as_rep(krb5_context context,
        kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name, msg);
        krb5_free_error_message(context, msg);
        ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+
+       if (config->db[0] && config->db[0]->hdb_auth_status)
+               (config->db[0]->hdb_auth_status)(context, config->db[0], NULL,
+                                                from_addr,
+                                                client_name,
+                                                NULL,
+                                                HDB_AUTH_CLIENT_UNKNOWN);
        goto out;
     }
     ret = _kdc_db_fetch(context, config, server_princ,
@@ -1194,6 +1201,12 @@ _kdc_as_rep(krb5_context context,
            kdc_log(context, config, 0,
                    "PKINIT pre-authentication succeeded -- %s using %s",
                    client_name, client_cert);
+           if (clientdb->hdb_auth_status)
+                   (clientdb->hdb_auth_status)(context, clientdb, client,
+                                               from_addr,
+                                               client_name,
+                                               "PKINIT",
+                                               HDB_AUTH_PKINIT_SUCCESS);
            free(client_cert);
            if (pkp)
                goto preauth_done;
@@ -1291,22 +1304,30 @@ _kdc_as_rep(krb5_context context,
                                              pa_key->key.keytype, &str);
                if (ret2)
                    str = NULL;
+
                kdc_log(context, config, 5,
                        "Failed to decrypt PA-DATA -- %s "
                        "(enctype %s) error %s",
                        client_name, str ? str : "unknown enctype", msg);
                krb5_free_error_message(context, msg);
-               free(str);
 
                if(hdb_next_enctype2key(context, &client->entry,
-                                       enc_data.etype, &pa_key) == 0)
+                                       enc_data.etype, &pa_key) == 0) {
+                   free(str);
                    goto try_next_key;
+               }
                e_text = "Failed to decrypt PA-DATA";
 
                free_EncryptedData(&enc_data);
 
                if (clientdb->hdb_auth_status)
-                   (clientdb->hdb_auth_status)(context, clientdb, client, HDB_AUTH_WRONG_PASSWORD);
+                   (clientdb->hdb_auth_status)(context, clientdb, client,
+                                               from_addr,
+                                               client_name,
+                                               str ? str : "unknown enctype",
+                                               HDB_AUTH_WRONG_PASSWORD);
+
+               free(str);
 
                ret = KRB5KDC_ERR_PREAUTH_FAILED;
                continue;
@@ -1362,6 +1383,13 @@ _kdc_as_rep(krb5_context context,
            kdc_log(context, config, 2,
                    "ENC-TS Pre-authentication succeeded -- %s using %s",
                    client_name, str ? str : "unknown enctype");
+           if (clientdb->hdb_auth_status)
+                   (clientdb->hdb_auth_status)(context, clientdb, client,
+                                               from_addr,
+                                               client_name,
+                                               str ? str : "unknown enctype",
+                                               HDB_AUTH_CORRECT_PASSWORD);
+
            free(str);
            break;
        }
@@ -1414,7 +1442,10 @@ _kdc_as_rep(krb5_context context,
 
     if (clientdb->hdb_auth_status)
        (clientdb->hdb_auth_status)(context, clientdb, client,
-                                   HDB_AUTH_SUCCESS);
+                                   from_addr,
+                                   client_name,
+                                   NULL,
+                                   HDB_AUTHZ_SUCCESS);
 
     /*
      * Selelct the best encryption type for the KDC with out regard to
index 75d18770f01c20d9791ee35d3f033f19979adc18..1af798d3512fa1c4c499dfe9df1bff9cbbdd3181 100644 (file)
@@ -70,9 +70,12 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
 #define HDB_CAP_F_PASSWORD_UPDATE_KEYS 4
 
 /* auth status values */
-#define HDB_AUTH_SUCCESS               0
+#define HDB_AUTHZ_SUCCESS              0
 #define HDB_AUTH_WRONG_PASSWORD                1
 #define HDB_AUTH_INVALID_SIGNATURE     2
+#define HDB_AUTH_CORRECT_PASSWORD      3
+#define HDB_AUTH_PKINIT_SUCCESS        4
+#define HDB_AUTH_CLIENT_UNKNOWN                5
 
 /* key usage for master key */
 #define HDB_KU_MKEY    0x484442
@@ -244,7 +247,11 @@ typedef struct HDB{
      * In case the entry is locked out, the backend should set the
      * hdb_entry.flags.locked-out flag.
      */
-    krb5_error_code (*hdb_auth_status)(krb5_context, struct HDB *, hdb_entry_ex *, int);
+    krb5_error_code (*hdb_auth_status)(krb5_context, struct HDB *,
+                                      hdb_entry_ex *, struct sockaddr *from_addr,
+                                      const char *original_client_name,
+                                      const char *auth_type,
+                                      int);
     /**
      * Check if delegation is allowed.
      */
index bf55befddf80633c1a197c262def9176e35caa3a..ce6a707bb435afe038148f5193d79dd96d4e4d22 100644 (file)
@@ -2677,6 +2677,7 @@ NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_conte
        }
        kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
        kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
+       kdc_db_ctx->msg_ctx = base_ctx->msg_ctx;
 
        /* get default kdc policy */
        lpcfg_default_kdc_policy(base_ctx->lp_ctx,
index 85d166fda67e4f2aae76583c0d9c0aae6b6ec532..c0d0e24713fe39ca818074debe26a383c2051ba1 100644 (file)
 #include "kdc/kdc-glue.h"
 #include "kdc/db-glue.h"
 #include "auth/auth_sam.h"
+#include "auth/common_auth.h"
 #include <ldb.h>
 #include "sdb.h"
 #include "sdb_hdb.h"
+#include "dsdb/samdb/samdb.h"
+#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
 
 static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode)
 {
@@ -292,19 +296,131 @@ hdb_samba4_check_s4u2self(krb5_context context, HDB *db,
 
 static krb5_error_code hdb_samba4_auth_status(krb5_context context, HDB *db,
                                              hdb_entry_ex *entry,
+                                             struct sockaddr *from_addr,
+                                             const char *original_client_name,
+                                             const char *auth_type,
                                              int hdb_auth_status)
 {
        struct samba_kdc_db_context *kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
                                                                        struct samba_kdc_db_context);
-       struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
 
        struct ldb_dn *domain_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
 
-       if (hdb_auth_status == HDB_AUTH_WRONG_PASSWORD) {
-               authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn);
-       } else if (hdb_auth_status == HDB_AUTH_SUCCESS) {
+       /*
+        * Forcing this via the NTLM auth structure is not ideal, but
+        * it is the most practical option right now, and ensures the
+        * logs are consistent, even if some elements are always NULL.
+        */
+       struct auth_usersupplied_info ui = {
+               .mapped_state = true,
+               .was_mapped = true,
+               .client = {
+                       .account_name = original_client_name,
+                       .domain_name = NULL,
+               },
+               .service_description = "Kerberos KDC",
+               .auth_description = "ENC-TS Pre-authentication",
+               .password_type = auth_type
+       };
+
+       size_t sa_socklen = 0;
+
+       switch (from_addr->sa_family) {
+       case AF_INET:
+               sa_socklen = sizeof(struct sockaddr_in);
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               sa_socklen = sizeof(struct sockaddr_in6);
+               break;
+#endif
+       }
+
+       switch (hdb_auth_status) {
+       case HDB_AUTHZ_SUCCESS:
+       {
+               struct samba_kdc_entry *p = talloc_get_type(entry->ctx,
+                                                           struct samba_kdc_entry);
+
+               /*
+                * TODO: We could log the AS-REQ authorization success here as
+                * well.  However before we do that, we need to pass
+                * in the PAC here or re-calculate it.
+                */
                authsam_logon_success_accounting(kdc_db_ctx->samdb, p->msg,
                                                 domain_dn, true);
+               break;
+       }
+       case HDB_AUTH_INVALID_SIGNATURE:
+               break;
+       case HDB_AUTH_CORRECT_PASSWORD:
+       case HDB_AUTH_WRONG_PASSWORD:
+       {
+               TALLOC_CTX *frame = talloc_stackframe();
+               struct samba_kdc_entry *p = talloc_get_type(entry->ctx,
+                                                           struct samba_kdc_entry);
+               struct dom_sid *sid
+                       = samdb_result_dom_sid(frame, p->msg, "objectSid");
+               const char *account_name
+                       = ldb_msg_find_attr_as_string(p->msg, "sAMAccountName", NULL);
+               const char *domain_name = lpcfg_sam_name(p->kdc_db_ctx->lp_ctx);
+               struct tsocket_address *remote_host;
+               NTSTATUS status;
+               int ret;
+
+               if (hdb_auth_status == HDB_AUTH_WRONG_PASSWORD) {
+                       authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn);
+                       status = NT_STATUS_WRONG_PASSWORD;
+               } else {
+                       status = NT_STATUS_OK;
+               }
+
+               ret = tsocket_address_bsd_from_sockaddr(frame, from_addr,
+                                                       sa_socklen,
+                                                       &remote_host);
+               if (ret != 0) {
+                       ui.remote_host = NULL;
+               } else {
+                       ui.remote_host = remote_host;
+               }
+
+               ui.mapped.account_name = account_name;
+               ui.mapped.domain_name = domain_name;
+
+               log_authentication_event(kdc_db_ctx->msg_ctx,
+                                        kdc_db_ctx->lp_ctx,
+                                        &ui,
+                                        status,
+                                        domain_name,
+                                        account_name,
+                                        NULL,
+                                        sid);
+               TALLOC_FREE(frame);
+               break;
+       }
+       case HDB_AUTH_CLIENT_UNKNOWN:
+       {
+               struct tsocket_address *remote_host;
+               int ret;
+               TALLOC_CTX *frame = talloc_stackframe();
+               ret = tsocket_address_bsd_from_sockaddr(frame, from_addr,
+                                                       sa_socklen,
+                                                       &remote_host);
+               if (ret != 0) {
+                       ui.remote_host = NULL;
+               } else {
+                       ui.remote_host = remote_host;
+               }
+
+               log_authentication_event(kdc_db_ctx->msg_ctx,
+                                        kdc_db_ctx->lp_ctx,
+                                        &ui,
+                                        NT_STATUS_NO_SUCH_USER,
+                                        NULL, NULL,
+                                        NULL, NULL);
+               TALLOC_FREE(frame);
+               break;
+       }
        }
        return 0;
 }
index 061296a4f407173dc4cf706e6df3f9fc45691b54..25bb3916038595c5c048e1849559388cd1f70469 100644 (file)
@@ -391,6 +391,7 @@ static void kdc_task_init(struct task_server *task)
 
        kdc->base_ctx->ev_ctx = task->event_ctx;
        kdc->base_ctx->lp_ctx = task->lp_ctx;
+       kdc->base_ctx->msg_ctx = task->msg_ctx;
 
        status = hdb_samba4_create_kdc(kdc->base_ctx,
                                       kdc->smb_krb5_context->krb5_context,
index 0827c193897b9803a27baf5a772734fec0029f97..b76cc31ffda1f195865f5ca251653e850232ac26 100644 (file)
@@ -33,6 +33,7 @@ struct samba_kdc_policy {
 struct samba_kdc_base_context {
        struct tevent_context *ev_ctx;
        struct loadparm_context *lp_ctx;
+       struct imessaging_context *msg_ctx;
 };
 
 struct samba_kdc_seq;
@@ -40,6 +41,7 @@ struct samba_kdc_seq;
 struct samba_kdc_db_context {
        struct tevent_context *ev_ctx;
        struct loadparm_context *lp_ctx;
+       struct imessaging_context *msg_ctx;
        struct ldb_context *samdb;
        struct samba_kdc_seq *seq_ctx;
        bool rodc;