int cli_credentials_update_keytab(struct cli_credentials *cred) { krb5_error_code ret; struct keytab_container *ktc; struct smb_krb5_context *smb_krb5_context; TALLOC_CTX *mem_ctx; mem_ctx = talloc_new(cred); if (!mem_ctx) { return ENOMEM; } ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context); if (ret) { talloc_free(mem_ctx); return ret; } ret = cli_credentials_get_keytab(cred, &ktc); if (ret != 0) { talloc_free(mem_ctx); return ret; } ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, ktc); talloc_free(mem_ctx); return ret; }
_PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, struct loadparm_context *lp_ctx, struct gssapi_creds_container **_gcc) { int ret = 0; OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct keytab_container *ktc; struct smb_krb5_context *smb_krb5_context; TALLOC_CTX *mem_ctx; krb5_principal princ; const char *error_string; enum credentials_obtained obtained; mem_ctx = talloc_new(cred); if (!mem_ctx) { return ENOMEM; } ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context); if (ret) { return ret; } ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string); if (ret) { DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n", error_string)); talloc_free(mem_ctx); return ret; } if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) { talloc_free(mem_ctx); *_gcc = cred->server_gss_creds; return 0; } ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc); if (ret) { DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); return ret; } gcc = talloc(cred, struct gssapi_creds_container); if (!gcc) { talloc_free(mem_ctx); return ENOMEM; } if (ktc->password_based || obtained < CRED_SPECIFIED) { /* This creates a GSSAPI cred_id_t for match-by-key with only the keytab set */ maj_stat = gss_krb5_import_cred(&min_stat, NULL, NULL, ktc->keytab, &gcc->creds); } else { /* This creates a GSSAPI cred_id_t with the principal and keytab set, matching by name */ maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab, &gcc->creds); } if (maj_stat) { if (min_stat) { ret = min_stat; } else { ret = EINVAL; } } if (ret == 0) { cred->server_gss_creds_obtained = cred->keytab_obtained; talloc_set_destructor(gcc, free_gssapi_creds); cred->server_gss_creds = gcc; *_gcc = gcc; } talloc_free(mem_ctx); return ret; }
int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, struct gssapi_creds_container **_gcc) { int ret = 0; OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct keytab_container *ktc; struct smb_krb5_context *smb_krb5_context; TALLOC_CTX *mem_ctx; krb5_principal princ; if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, MAX(cred->principal_obtained, cred->username_obtained)))) { *_gcc = cred->server_gss_creds; return 0; } ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context); if (ret) { return ret; } ret = cli_credentials_get_keytab(cred, &ktc); if (ret) { DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); return ret; } mem_ctx = talloc_new(cred); if (!mem_ctx) { return ENOMEM; } ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ); if (ret) { DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } gcc = talloc(cred, struct gssapi_creds_container); if (!gcc) { talloc_free(mem_ctx); return ENOMEM; } /* This creates a GSSAPI cred_id_t with the principal and keytab set */ maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab, &gcc->creds); if (maj_stat) { if (min_stat) { ret = min_stat; } else { ret = EINVAL; } } if (ret == 0) { cred->server_gss_creds_obtained = cred->keytab_obtained; talloc_set_destructor(gcc, free_gssapi_creds); cred->server_gss_creds = gcc; *_gcc = gcc; } talloc_free(mem_ctx); return ret; }
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; krb5_error_code ret = 0; NTSTATUS nt_status; switch (gensec_krb5_state->state_position) { case GENSEC_KRB5_CLIENT_START: { 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); /* wrap that up in a nice GSS-API wrapping */ *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ); } else { *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length); } if (gensec_krb5_state->ap_req_options & AP_OPTS_MUTUAL_REQUIRED) { gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH; nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; } else { gensec_krb5_state->state_position = GENSEC_KRB5_DONE; nt_status = NT_STATUS_OK; } return nt_status; } case GENSEC_KRB5_CLIENT_MUTUAL_AUTH: { DATA_BLOB unwrapped_in; krb5_data inbuf; krb5_ap_rep_enc_part *repl = NULL; uint8_t tok_id[2]; if (gensec_krb5_state->gssapi) { if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) { DEBUG(1,("gensec_gssapi_parse_krb5_wrap(mutual authentication) failed to parse\n")); dump_data_pw("Mutual authentication message:\n", in.data, in.length); return NT_STATUS_INVALID_PARAMETER; } } else { unwrapped_in = in; } /* TODO: check the tok_id */ inbuf.data = unwrapped_in.data; inbuf.length = unwrapped_in.length; ret = krb5_rd_rep(gensec_krb5_state->smb_krb5_context->krb5_context, gensec_krb5_state->auth_context, &inbuf, &repl); if (ret) { DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, out_mem_ctx))); dump_data_pw("Mutual authentication message:\n", (uint8_t *)inbuf.data, inbuf.length); nt_status = NT_STATUS_ACCESS_DENIED; } else { *out = data_blob(NULL, 0); nt_status = NT_STATUS_OK; gensec_krb5_state->state_position = GENSEC_KRB5_DONE; } if (repl) { krb5_free_ap_rep_enc_part(gensec_krb5_state->smb_krb5_context->krb5_context, repl); } return nt_status; } case GENSEC_KRB5_SERVER_START: { DATA_BLOB unwrapped_in; DATA_BLOB unwrapped_out = data_blob(NULL, 0); krb5_data inbuf, outbuf; uint8_t tok_id[2]; struct keytab_container *keytab; krb5_principal server_in_keytab; const char *error_string; enum credentials_obtained obtained; if (!in.data) { return NT_STATUS_INVALID_PARAMETER; } /* Grab the keytab, however generated */ ret = cli_credentials_get_keytab(gensec_get_credentials(gensec_security), gensec_security->settings->lp_ctx, &keytab); if (ret) { return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } /* This ensures we lookup the correct entry in that keytab */ ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security), gensec_krb5_state->smb_krb5_context, &server_in_keytab, &obtained, &error_string); if (ret) { DEBUG(2,("Failed to make credentials from principal: %s\n", error_string)); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } /* Parse the GSSAPI wrapping, if it's there... (win2k3 allows it to be omited) */ if (gensec_krb5_state->gssapi && gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) { inbuf.data = unwrapped_in.data; inbuf.length = unwrapped_in.length; } else { inbuf.data = in.data; inbuf.length = in.length; } ret = smb_rd_req_return_stuff(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context, &inbuf, keytab->keytab, server_in_keytab, &outbuf, &gensec_krb5_state->ticket, &gensec_krb5_state->keyblock); if (ret) { return NT_STATUS_LOGON_FAILURE; } unwrapped_out.data = (uint8_t *)outbuf.data; unwrapped_out.length = outbuf.length; gensec_krb5_state->state_position = GENSEC_KRB5_DONE; /* wrap that up in a nice GSS-API wrapping */ if (gensec_krb5_state->gssapi) { *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REP); } else { *out = data_blob_talloc(out_mem_ctx, outbuf.data, outbuf.length); } krb5_data_free(&outbuf); return NT_STATUS_OK; } case GENSEC_KRB5_DONE: default: /* Asking too many times... */ return NT_STATUS_INVALID_PARAMETER; } }