static krb5_error_code prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request, int error, krb5_pa_data **e_data, krb5_boolean typed_e_data, krb5_principal canon_client, krb5_data **response, const char *status) { krb5_error errpkt; krb5_error_code retval; krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL; kdc_realm_t *kdc_active_realm = rstate->realm_data; errpkt.ctime = request->nonce; errpkt.cusec = 0; retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); if (retval) return retval; errpkt.error = error; errpkt.server = request->server; errpkt.client = (error == KRB5KDC_ERR_WRONG_REALM) ? canon_client : request->client; errpkt.text = string2data((char *)status); if (e_data != NULL) { if (typed_e_data) retval = encode_krb5_typed_data(e_data, &e_data_asn1); else retval = encode_krb5_padata_sequence(e_data, &e_data_asn1); if (retval) goto cleanup; errpkt.e_data = *e_data_asn1; } else errpkt.e_data = empty_data(); retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data, &errpkt, &fast_edata); if (retval) goto cleanup; if (fast_edata != NULL) errpkt.e_data = *fast_edata; scratch = k5alloc(sizeof(*scratch), &retval); if (scratch == NULL) goto cleanup; if (kdc_fast_hide_client(rstate) && errpkt.client != NULL) errpkt.client = (krb5_principal)krb5_anonymous_principal(); retval = krb5_mk_error(kdc_context, &errpkt, scratch); if (retval) goto cleanup; *response = scratch; scratch = NULL; cleanup: krb5_free_data(kdc_context, fast_edata); krb5_free_data(kdc_context, e_data_asn1); free(scratch); return retval; }
/* this function allocates 'data' using malloc. * The caller is responsible for freeing it */ static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data) { krb5_error_code ret = 0; krb5_pa_data pa, *ppa = NULL; krb5_data *d = NULL; if (!e_data) return; e_data->data = NULL; e_data->length = 0; pa.magic = KV5M_PA_DATA; pa.pa_type = KRB5_PADATA_PW_SALT; pa.length = 12; pa.contents = malloc(pa.length); if (!pa.contents) { return; } SIVAL(pa.contents, 0, NT_STATUS_V(nt_status)); SIVAL(pa.contents, 4, 0); SIVAL(pa.contents, 8, 1); ppa = &pa; ret = encode_krb5_padata_sequence(&ppa, &d); free(pa.contents); if (ret) { return; } e_data->data = (uint8_t *)d->data; e_data->length = d->length; /* free d, not d->data - gd */ free(d); return; }
static krb5_error_code prepare_error_tgs (struct kdc_request_state *state, krb5_kdc_req *request, krb5_ticket *ticket, int error, krb5_principal canon_server, krb5_data **response, const char *status, krb5_pa_data **e_data) { krb5_error errpkt; krb5_error_code retval = 0; krb5_data *scratch, *e_data_asn1 = NULL, *fast_edata = NULL; errpkt.ctime = request->nonce; errpkt.cusec = 0; if ((retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec))) return(retval); errpkt.error = error; errpkt.server = request->server; if (ticket && ticket->enc_part2) errpkt.client = ticket->enc_part2->client; else errpkt.client = NULL; errpkt.text.length = strlen(status); if (!(errpkt.text.data = strdup(status))) return ENOMEM; if (!(scratch = (krb5_data *)malloc(sizeof(*scratch)))) { free(errpkt.text.data); return ENOMEM; } if (e_data != NULL) { retval = encode_krb5_padata_sequence(e_data, &e_data_asn1); if (retval) { free(scratch); free(errpkt.text.data); return retval; } errpkt.e_data = *e_data_asn1; } else errpkt.e_data = empty_data(); if (state) { retval = kdc_fast_handle_error(kdc_context, state, request, e_data, &errpkt, &fast_edata); } if (retval) { free(scratch); free(errpkt.text.data); krb5_free_data(kdc_context, e_data_asn1); return retval; } if (fast_edata) errpkt.e_data = *fast_edata; retval = krb5_mk_error(kdc_context, &errpkt, scratch); free(errpkt.text.data); krb5_free_data(kdc_context, e_data_asn1); krb5_free_data(kdc_context, fast_edata); if (retval) free(scratch); else *response = scratch; return retval; }
static void kdc_verify_preauth(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa_data, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_verify_respond_fn respond, void *arg) { krb5_error_code retval, saved_retval = 0; krb5_sam_response_2 *sr2 = NULL; krb5_data scratch, *scratch2, *e_data = NULL; char *client_name = NULL; krb5_sam_challenge_2 *out_sc2 = NULL; krb5_db_entry *client = cb->client_entry(context, rock); scratch.data = (char *) pa_data->contents; scratch.length = pa_data->length; retval = krb5_unparse_name(context, client->princ, &client_name); if (retval) goto cleanup; retval = decode_krb5_sam_response_2(&scratch, &sr2); if (retval) { com_err("krb5kdc", retval, "while decoding SAM_RESPONSE_2 in verify_sam_response_2"); sr2 = NULL; goto cleanup; } switch (sr2->sam_type) { #ifdef ARL_SECURID_PREAUTH case PA_SAM_TYPE_SECURID: retval = verify_securid_data_2(context, client, sr2, enc_tkt_reply, pa_data, &out_sc2); if (retval) goto cleanup; break; #endif /* ARL_SECURID_PREAUTH */ #ifdef GRAIL_PREAUTH case PA_SAM_TYPE_GRAIL: retval = verify_grail_data(context, client, sr2, enc_tkt_reply, pa_data, &out_sc2); if (retval) goto cleanup; break; #endif /* GRAIL_PREAUTH */ default: retval = KRB5_PREAUTH_BAD_TYPE; com_err("krb5kdc", retval, "while verifying SAM 2 data"); break; } /* * It is up to the method-specific verify routine to set the * ticket flags to indicate TKT_FLG_HW_AUTH and/or * TKT_FLG_PRE_AUTH. Some methods may require more than one round * of dialog with the client and must return successfully from * their verify routine. If does not set the TGT flags, the * required_preauth conditions will not be met and it will try * again to get enough preauth data from the client. Do not set * TGT flags here. */ cleanup: /* * Note that e_data is an output even in error conditions. If we * successfully encode the output e_data, we return whatever error is * received above. Otherwise we return the encoding error. */ saved_retval = retval; if (out_sc2) { krb5_pa_data pa_out; krb5_pa_data *pa_array[2]; pa_array[0] = &pa_out; pa_array[1] = NULL; pa_out.pa_type = KRB5_PADATA_SAM_CHALLENGE_2; retval = encode_krb5_sam_challenge_2(out_sc2, &scratch2); krb5_free_sam_challenge_2(context, out_sc2); if (retval) goto encode_error; pa_out.contents = (krb5_octet *) scratch2->data; pa_out.length = scratch2->length; retval = encode_krb5_padata_sequence(pa_array, &e_data); krb5_free_data(context, scratch2); } encode_error: krb5_free_sam_response_2(context, sr2); free(client_name); if (retval == 0) retval = saved_retval; (*respond)(arg, retval, NULL, NULL, NULL); }
/* * We assume the caller is responsible for passing us an in_padata * sufficient to include in a FAST error. In the FAST case we will * set *fast_edata_out to the edata to be included in the error; in * the non-FAST case we will set it to NULL. */ krb5_error_code kdc_fast_handle_error(krb5_context context, struct kdc_request_state *state, krb5_kdc_req *request, krb5_pa_data **in_padata, krb5_error *err, krb5_data **fast_edata_out) { krb5_error_code retval = 0; krb5_fast_response resp; krb5_error fx_error; krb5_data *encoded_fx_error = NULL, *encrypted_reply = NULL; krb5_pa_data pa[1]; krb5_pa_data *outer_pa[3], *cookie = NULL; krb5_pa_data **inner_pa = NULL; size_t size = 0; kdc_realm_t *kdc_active_realm = state->realm_data; *fast_edata_out = NULL; memset(outer_pa, 0, sizeof(outer_pa)); if (state->armor_key == NULL) return 0; fx_error = *err; fx_error.e_data.data = NULL; fx_error.e_data.length = 0; for (size = 0; in_padata&&in_padata[size]; size++); size +=3; inner_pa = calloc(size, sizeof(krb5_pa_data *)); if (inner_pa == NULL) retval = ENOMEM; if (retval == 0) for (size=0; in_padata&&in_padata[size]; size++) inner_pa[size] = in_padata[size]; if (retval == 0) retval = encode_krb5_error(&fx_error, &encoded_fx_error); if (retval == 0) { pa[0].pa_type = KRB5_PADATA_FX_ERROR; pa[0].length = encoded_fx_error->length; pa[0].contents = (unsigned char *) encoded_fx_error->data; inner_pa[size++] = &pa[0]; if (krb5int_find_pa_data(kdc_context, inner_pa, KRB5_PADATA_FX_COOKIE) == NULL) retval = kdc_preauth_get_cookie(state, &cookie); } if (cookie != NULL) inner_pa[size++] = cookie; if (retval == 0) { resp.padata = inner_pa; resp.nonce = request->nonce; resp.strengthen_key = NULL; resp.finished = NULL; } if (retval == 0) retval = encrypt_fast_reply(state, &resp, &encrypted_reply); if (inner_pa) free(inner_pa); /*contained storage from caller and our stack*/ if (cookie) { free(cookie->contents); free(cookie); cookie = NULL; } if (retval == 0) { pa[0].pa_type = KRB5_PADATA_FX_FAST; pa[0].length = encrypted_reply->length; pa[0].contents = (unsigned char *) encrypted_reply->data; outer_pa[0] = &pa[0]; } retval = encode_krb5_padata_sequence(outer_pa, fast_edata_out); if (encrypted_reply) krb5_free_data(kdc_context, encrypted_reply); if (encoded_fx_error) krb5_free_data(kdc_context, encoded_fx_error); return retval; }
static krb5_error_code prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request, krb5_db_entry *local_tgt, int error, krb5_pa_data **e_data_in, krb5_boolean typed_e_data, krb5_principal canon_client, krb5_data **response, const char *status) { krb5_error errpkt; krb5_error_code retval; krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL; krb5_pa_data **e_data = NULL, *cookie = NULL; kdc_realm_t *kdc_active_realm = rstate->realm_data; size_t count; if (e_data_in != NULL) { /* Add a PA-FX-COOKIE to e_data_in. e_data is a shallow copy * containing aliases. */ for (count = 0; e_data_in[count] != NULL; count++); e_data = calloc(count + 2, sizeof(*e_data)); if (e_data == NULL) return ENOMEM; memcpy(e_data, e_data_in, count * sizeof(*e_data)); retval = kdc_fast_make_cookie(kdc_context, rstate, local_tgt, request->client, &cookie); e_data[count] = cookie; } errpkt.ctime = request->nonce; errpkt.cusec = 0; retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); if (retval) goto cleanup; errpkt.error = error; errpkt.server = request->server; errpkt.client = (error == KDC_ERR_WRONG_REALM) ? canon_client : request->client; errpkt.text = string2data((char *)status); if (e_data != NULL) { if (typed_e_data) retval = encode_krb5_typed_data(e_data, &e_data_asn1); else retval = encode_krb5_padata_sequence(e_data, &e_data_asn1); if (retval) goto cleanup; errpkt.e_data = *e_data_asn1; } else errpkt.e_data = empty_data(); retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data, &errpkt, &fast_edata); if (retval) goto cleanup; if (fast_edata != NULL) errpkt.e_data = *fast_edata; scratch = k5alloc(sizeof(*scratch), &retval); if (scratch == NULL) goto cleanup; if (kdc_fast_hide_client(rstate) && errpkt.client != NULL) errpkt.client = (krb5_principal)krb5_anonymous_principal(); retval = krb5_mk_error(kdc_context, &errpkt, scratch); if (retval) goto cleanup; *response = scratch; scratch = NULL; cleanup: krb5_free_data(kdc_context, fast_edata); krb5_free_data(kdc_context, e_data_asn1); free(scratch); free(e_data); if (cookie != NULL) free(cookie->contents); free(cookie); return retval; }