s4-gensec: zero the gssapi_state
[samba.git] / source4 / auth / gensec / gensec_gssapi.c
index 51d59d9f214d42d62c2c15c0af7429d4f05bfb03..f0da54d711360b4195772b5b0dcb7c31df3ee0db 100644 (file)
@@ -147,10 +147,9 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 {
        struct gensec_gssapi_state *gensec_gssapi_state;
        krb5_error_code ret;
-       struct gsskrb5_send_to_kdc send_to_kdc;
        const char *realm;
 
-       gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
+       gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state);
        if (!gensec_gssapi_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -209,7 +208,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        gensec_gssapi_state->pac = data_blob(NULL, 0);
 
        ret = smb_krb5_init_context(gensec_gssapi_state,
-                                   gensec_security->event_ctx,
+                                   NULL,
                                    gensec_security->settings->lp_ctx,
                                    &gensec_gssapi_state->smb_krb5_context);
        if (ret) {
@@ -237,16 +236,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 
        talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor);
 
-       send_to_kdc.func = smb_krb5_send_and_recv_func;
-       send_to_kdc.ptr = gensec_security->event_ctx;
-
-       ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
-       if (ret) {
-               DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
-               talloc_free(gensec_gssapi_state);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
        realm = lpcfg_realm(gensec_security->settings->lp_ctx);
        if (realm != NULL) {
                ret = gsskrb5_set_default_realm(realm);
@@ -290,7 +279,6 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        } else {
                ret = cli_credentials_get_server_gss_creds(machine_account, 
-                                                          gensec_security->event_ctx, 
                                                           gensec_security->settings->lp_ctx, &gcc);
                if (ret) {
                        DEBUG(1, ("Aquiring acceptor credentials failed: %s\n", 
@@ -327,7 +315,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        gss_OID name_type;
        OM_uint32 maj_stat, min_stat;
        const char *hostname = gensec_get_target_hostname(gensec_security);
-       const char *principal;
        struct gssapi_creds_container *gcc;
        const char *error_string;
 
@@ -351,18 +338,18 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
 
        gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
 
-       principal = gensec_get_target_principal(gensec_security);
-       if (principal) {
+       gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security);
+       if (gensec_gssapi_state->target_principal) {
                name_type = GSS_C_NULL_OID;
        } else {
-               principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s",
+               gensec_gssapi_state->target_principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s",
                                            gensec_get_target_service(gensec_security), 
                                            hostname, lpcfg_realm(gensec_security->settings->lp_ctx));
 
                name_type = GSS_C_NT_USER_NAME;
        }
-       name_token.value  = discard_const_p(uint8_t, principal);
-       name_token.length = strlen(principal);
+       name_token.value  = discard_const_p(uint8_t, gensec_gssapi_state->target_principal);
+       name_token.length = strlen(gensec_gssapi_state->target_principal);
 
 
        maj_stat = gss_import_name (&min_stat,
@@ -383,14 +370,16 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        case 0:
                break;
        case KRB5KDC_ERR_PREAUTH_FAILED:
+       case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+               DEBUG(1, ("Wrong username or password: %s\n", error_string));
                return NT_STATUS_LOGON_FAILURE;
        case KRB5_KDC_UNREACH:
-               DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", principal, error_string));
-               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+               DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
+               return NT_STATUS_NO_LOGON_SERVERS;
        case KRB5_CC_NOTFOUND:
        case KRB5_CC_END:
-               DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string));
-               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+               DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string));
+               return NT_STATUS_TIME_DIFFERENCE_AT_DC;
        default:
                DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string));
                return NT_STATUS_UNSUCCESSFUL;
@@ -469,6 +458,17 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                switch (gensec_security->gensec_role) {
                case GENSEC_CLIENT:
                {
+                       struct gsskrb5_send_to_kdc send_to_kdc;
+                       krb5_error_code ret;
+                       send_to_kdc.func = smb_krb5_send_and_recv_func;
+                       send_to_kdc.ptr = gensec_security->event_ctx;
+
+                       min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
+                       if (min_stat) {
+                               DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
+                               return NT_STATUS_INTERNAL_ERROR;
+                       }
+
                        maj_stat = gss_init_sec_context(&min_stat, 
                                                        gensec_gssapi_state->client_cred->creds,
                                                        &gensec_gssapi_state->gssapi_context, 
@@ -485,6 +485,16 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        if (gss_oid_p) {
                                gensec_gssapi_state->gss_oid = gss_oid_p;
                        }
+
+                       send_to_kdc.func = smb_krb5_send_and_recv_func;
+                       send_to_kdc.ptr = NULL;
+
+                       ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
+                       if (ret) {
+                               DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
+                               return NT_STATUS_INTERNAL_ERROR;
+                       }
+
                        break;
                }
                case GENSEC_SERVER:
@@ -544,9 +554,9 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                gensec_gssapi_state->sasl_state = STAGE_DONE;
 
                                if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
-                                       DEBUG(5, ("GSSAPI Connection will be cryptographicly sealed\n"));
+                                       DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
                                } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-                                       DEBUG(5, ("GSSAPI Connection will be cryptographicly signed\n"));
+                                       DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
                                } else {
                                        DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
                                }
@@ -560,25 +570,39 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        return NT_STATUS_MORE_PROCESSING_REQUIRED;
                } else if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
                        switch (min_stat) {
+                       case KRB5KRB_AP_ERR_TKT_NYV:
+                               DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
+                                         gensec_gssapi_state->target_principal,
+                                         gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
+                               return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
+                       case KRB5KRB_AP_ERR_TKT_EXPIRED:
+                               DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
+                                         gensec_gssapi_state->target_principal,
+                                         gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
+                               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
                        case KRB5_KDC_UNREACH:
-                               DEBUG(3, ("Cannot reach a KDC we require: %s\n",
+                               DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticetk to %s: %s\n",
+                                         gensec_gssapi_state->target_principal,
                                          gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-                               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+                               return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
                        case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
-                               DEBUG(3, ("Server is not registered with our KDC: %s\n", 
+                               DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
+                                         gensec_gssapi_state->target_principal,
                                          gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
                        case KRB5KRB_AP_ERR_MSG_TYPE:
                                /* garbage input, possibly from the auto-mech detection */
                                return NT_STATUS_INVALID_PARAMETER;
                        default:
-                               DEBUG(1, ("GSS Update(krb5)(%d) Update failed: %s\n", 
+                               DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
+                                         gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
                                          gensec_gssapi_state->gss_exchange_count,
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return nt_status;
                        }
                } else {
-                       DEBUG(1, ("GSS Update(%d) failed: %s\n", 
+                       DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
+                                 gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
                                  gensec_gssapi_state->gss_exchange_count,
                                  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                        return nt_status;
@@ -679,11 +703,11 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        gensec_gssapi_state->sasl_state = STAGE_DONE;
 
                        if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
-                               DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly sealed\n"));
+                               DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
                        } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-                               DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly signed\n"));
+                               DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
                        } else {
-                               DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographicly protection\n"));
+                               DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n"));
                        }
 
                        return NT_STATUS_OK;
@@ -807,9 +831,9 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
                gensec_gssapi_state->sasl_state = STAGE_DONE;
                if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
-                       DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly sealed\n"));
+                       DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
                } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-                       DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly signed\n"));
+                       DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
                } else {
                        DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
                }
@@ -1369,7 +1393,6 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                cli_credentials_set_anonymous(session_info->credentials);
                
                ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
-                                                          gensec_security->event_ctx,
                                                           gensec_security->settings->lp_ctx,
                                                           gensec_gssapi_state->delegated_cred_handle,
                                                           CRED_SPECIFIED, &error_string);