s4-gensec: Move parsing of the PAC blob and creating the session_info into auth
[ddiss/samba.git] / source4 / auth / gensec / gensec_krb5.c
index b3a20e4b63d31b4edfda66083b18851b29d40098..d5f5f8a438b2a68a8cb932f7becb5341413f10fc 100644 (file)
@@ -232,16 +232,9 @@ static NTSTATUS gensec_fake_gssapi_krb5_server_start(struct gensec_security *gen
 
 static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_security, bool gssapi)
 {
+       const char *hostname;
        struct gensec_krb5_state *gensec_krb5_state;
-       krb5_error_code ret;
        NTSTATUS nt_status;
-       struct ccache_container *ccache_container;
-       const char *hostname;
-       const char *error_string;
-       const char *principal;
-       krb5_data in_data;
-       struct tevent_context *previous_ev;
-
        hostname = gensec_get_target_hostname(gensec_security);
        if (!hostname) {
                DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
@@ -276,11 +269,29 @@ static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_s
                        gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
                }
        }
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_security,
+                                               struct tevent_context *ev,
+                                               bool gssapi)
+{
+       struct gensec_krb5_state *gensec_krb5_state;
+       krb5_error_code ret;
+       struct ccache_container *ccache_container;
+       const char *error_string;
+       const char *principal;
+       const char *hostname;
+       krb5_data in_data;
+       struct tevent_context *previous_ev;
+
+       gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 
        principal = gensec_get_target_principal(gensec_security);
+       hostname = gensec_get_target_hostname(gensec_security);
 
        ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), 
-                                        gensec_security->event_ctx, 
+                                        ev,
                                         gensec_security->settings->lp_ctx, &ccache_container, &error_string);
        switch (ret) {
        case 0:
@@ -302,7 +313,7 @@ static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_s
        in_data.length = 0;
        
        /* Do this every time, in case we have weird recursive issues here */
-       ret = smb_krb5_context_set_event_ctx(gensec_krb5_state->smb_krb5_context, gensec_security->event_ctx, &previous_ev);
+       ret = smb_krb5_context_set_event_ctx(gensec_krb5_state->smb_krb5_context, ev, &previous_ev);
        if (ret != 0) {
                DEBUG(1, ("gensec_krb5_start: Setting event context failed\n"));
                return NT_STATUS_NO_MEMORY;
@@ -331,7 +342,7 @@ static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_s
                                  &gensec_krb5_state->enc_ticket);
        }
 
-       smb_krb5_context_remove_event_ctx(gensec_krb5_state->smb_krb5_context, previous_ev, gensec_security->event_ctx);
+       smb_krb5_context_remove_event_ctx(gensec_krb5_state->smb_krb5_context, previous_ev, ev);
 
        switch (ret) {
        case 0:
@@ -414,6 +425,7 @@ static NTSTATUS gensec_fake_gssapi_krb5_magic(struct gensec_security *gensec_sec
 
 static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, 
                                   TALLOC_CTX *out_mem_ctx, 
+                                  struct tevent_context *ev,
                                   const DATA_BLOB in, DATA_BLOB *out) 
 {
        struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
@@ -425,6 +437,11 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
        {
                DATA_BLOB unwrapped_out;
                
+               nt_status = gensec_krb5_common_client_creds(gensec_security, ev, gensec_krb5_state->gssapi);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       return nt_status;
+               }
+
                if (gensec_krb5_state->gssapi) {
                        unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
                        
@@ -504,7 +521,10 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
                        return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
                }
                
-               /* This ensures we lookup the correct entry in that keytab */
+               /* This ensures we lookup the correct entry in that
+                * keytab.  A NULL principal is acceptable, and means
+                * that the krb5 libs should search the keytab at
+                * accept time for any matching key */
                ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security), 
                                                 gensec_krb5_state->smb_krb5_context, 
                                                 &server_in_keytab, &obtained, &error_string);
@@ -598,14 +618,12 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
        struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
        krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
-       struct auth_user_info_dc *user_info_dc = NULL;
        struct auth_session_info *session_info = NULL;
-       struct PAC_LOGON_INFO *logon_info;
 
        krb5_principal client_principal;
        char *principal_string;
        
-       DATA_BLOB pac;
+       DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
        krb5_data pac_data;
 
        krb5_error_code ret;
@@ -639,49 +657,15 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
                                                      KRB5_AUTHDATA_WIN2K_PAC, 
                                                      &pac_data);
        
-       if (ret && gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
-               DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s \n",
-                         principal_string,
-                         smb_get_krb5_error_message(context, 
-                                                    ret, mem_ctx)));
-               free(principal_string);
-               krb5_free_principal(context, client_principal);
-               talloc_free(mem_ctx);
-               return NT_STATUS_ACCESS_DENIED;
-       } else if (ret) {
+       if (ret) {
                /* NO pac */
                DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n", 
                          smb_get_krb5_error_message(context, 
                                                     ret, mem_ctx)));
-               if (gensec_security->auth_context && 
-                   !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
-                       DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s",
-                                 principal_string, smb_get_krb5_error_message(context, 
-                                                    ret, mem_ctx)));
-                       nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx,
-                                                                                            gensec_security->auth_context, 
-                                                                                            principal_string,
-                                                                                            NULL, &user_info_dc);
-                       if (!NT_STATUS_IS_OK(nt_status)) {
-                               free(principal_string);
-                               krb5_free_principal(context, client_principal);
-                               talloc_free(mem_ctx);
-                               return nt_status;
-                       }
-               } else {
-                       DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n",
-                                 principal_string));
-                       free(principal_string);
-                       krb5_free_principal(context, client_principal);
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_ACCESS_DENIED;
-               }
        } else {
                /* Found pac */
-               union netr_Validation validation;
-
-               pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
-               if (!pac.data) {
+               pac_blob = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
+               if (!pac_blob.data) {
                        free(principal_string);
                        krb5_free_principal(context, client_principal);
                        talloc_free(mem_ctx);
@@ -689,12 +673,12 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
                }
 
                /* decode and verify the pac */
-               nt_status = kerberos_pac_logon_info(gensec_krb5_state, 
-                                                   pac,
-                                                   gensec_krb5_state->smb_krb5_context->krb5_context,
-                                                   NULL, gensec_krb5_state->keyblock,
-                                                   client_principal,
-                                                   gensec_krb5_state->ticket->ticket.authtime, &logon_info);
+               nt_status = kerberos_decode_pac(gensec_krb5_state,
+                                               pac_blob,
+                                               gensec_krb5_state->smb_krb5_context->krb5_context,
+                                               NULL, gensec_krb5_state->keyblock,
+                                               client_principal,
+                                               gensec_krb5_state->ticket->ticket.authtime, NULL);
 
                if (!NT_STATUS_IS_OK(nt_status)) {
                        free(principal_string);
@@ -703,26 +687,19 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
                        return nt_status;
                }
 
-               validation.sam3 = &logon_info->info3;
-               nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
-                                                                NULL,
-                                                                3, &validation,
-                                                                 true, /* This user was authenticated */
-                                                                &user_info_dc);
-               if (!NT_STATUS_IS_OK(nt_status)) {
-                       free(principal_string);
-                       krb5_free_principal(context, client_principal);
-                       talloc_free(mem_ctx);
-                       return nt_status;
-               }
+               pac_blob_ptr = &pac_blob;
        }
 
+       nt_status = gensec_generate_session_info_pac(mem_ctx,
+                                                    gensec_security,
+                                                    gensec_krb5_state->smb_krb5_context,
+                                                    pac_blob_ptr, principal_string,
+                                                    gensec_get_remote_address(gensec_security),
+                                                    &session_info);
+
        free(principal_string);
        krb5_free_principal(context, client_principal);
 
-       /* references the user_info_dc into the session_info */
-       nt_status = gensec_generate_session_info(mem_ctx, gensec_security, user_info_dc, &session_info);
-
        if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(mem_ctx);
                return nt_status;