static krb5_error_code return_pkinit_kx(krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, krb5_pa_data **out_padata) { krb5_error_code ret = 0; krb5_keyblock *session = reply->ticket->enc_part2->session; krb5_keyblock *new_session = NULL; krb5_pa_data *pa = NULL; krb5_enc_data enc; krb5_data *scratch = NULL; *out_padata = NULL; enc.ciphertext.data = NULL; if (!krb5_principal_compare(context, request->client, krb5_anonymous_principal())) return 0; /* * The KDC contribution key needs to be a fresh key of an enctype supported * by the client and server. The existing session key meets these * requirements so we use it. */ ret = krb5_c_fx_cf2_simple(context, session, "PKINIT", encrypting_key, "KEYEXCHANGE", &new_session); if (ret) goto cleanup; ret = encode_krb5_encryption_key( session, &scratch); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, encrypting_key, KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc); if (ret) goto cleanup; memset(scratch->data, 0, scratch->length); krb5_free_data(context, scratch); scratch = NULL; ret = encode_krb5_enc_data(&enc, &scratch); if (ret) goto cleanup; pa = malloc(sizeof(krb5_pa_data)); if (pa == NULL) { ret = ENOMEM; goto cleanup; } pa->pa_type = KRB5_PADATA_PKINIT_KX; pa->length = scratch->length; pa->contents = (krb5_octet *) scratch->data; *out_padata = pa; scratch->data = NULL; memset(session->contents, 0, session->length); krb5_free_keyblock_contents(context, session); *session = *new_session; new_session->contents = NULL; cleanup: krb5_free_data_contents(context, &enc.ciphertext); krb5_free_keyblock(context, new_session); krb5_free_data(context, scratch); return ret; }
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; }
static krb5_error_code kdc_return_preauth(krb5_context context, krb5_pa_data *padata, struct _krb5_db_entry_new *client, krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, struct _krb5_key_data *client_keys, krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, preauth_get_entry_data_proc get_entry_proc, void *pa_module_context, void **pa_request_context) { krb5_error_code retval = 0; krb5_keyblock *challenge_key = *pa_request_context; krb5_pa_enc_ts ts; krb5_data *plain = NULL; krb5_enc_data enc; krb5_data *encoded = NULL; krb5_pa_data *pa = NULL; krb5int_access kaccess; if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) return 0; if (challenge_key == NULL) return 0; * pa_request_context = NULL; /*this function will free the * challenge key*/ enc.ciphertext.data = NULL; /* In case of error pass through */ retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = kaccess.encode_enc_ts(&ts, &plain); if (retval == 0) retval = kaccess.encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, plain, &enc); if (retval == 0) retval = kaccess.encode_enc_data(&enc, &encoded); if (retval == 0) { pa = calloc(1, sizeof(krb5_pa_data)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; pa->contents = (unsigned char *) encoded->data; pa->length = encoded->length; encoded->data = NULL; *send_pa = pa; pa = NULL; } if (challenge_key) krb5_free_keyblock(context, challenge_key); if (encoded) krb5_free_data(context, encoded); if (plain) krb5_free_data(context, plain); if (enc.ciphertext.data) krb5_free_data_contents(context, &enc.ciphertext); return retval; }
/* Obtain and return any preauthentication data (which is destined for the * client) which matches type data->pa_type. */ static krb5_error_code server_get_edata(krb5_context kcontext, krb5_kdc_req *request, struct _krb5_db_entry_new *client, struct _krb5_db_entry_new *server, preauth_get_entry_data_proc server_get_entry_data, void *pa_module_context, krb5_pa_data *data) { krb5_data *key_data; krb5_keyblock *keys, *key; krb5_int32 *enctypes, enctype; int i; /* Retrieve the client's keys. */ key_data = NULL; if ((*server_get_entry_data)(kcontext, request, client, krb5plugin_preauth_keys, &key_data) != 0) { #ifdef DEBUG fprintf(stderr, "Error retrieving client keys.\n"); #endif return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; } /* Count which types of keys we've got, freeing the contents, which we * don't need at this point. */ keys = (krb5_keyblock *) key_data->data; key = NULL; for (i = 0; keys[i].enctype != 0; i++) krb5_free_keyblock_contents(kcontext, &keys[i]); /* Return the list of encryption types. */ enctypes = malloc((unsigned)i * 4); if (enctypes == NULL) { krb5_free_data(kcontext, key_data); return ENOMEM; } #ifdef DEBUG fprintf(stderr, "Supported enctypes = {"); #endif for (i = 0; keys[i].enctype != 0; i++) { #ifdef DEBUG fprintf(stderr, "%s%d", (i > 0) ? ", " : "", keys[i].enctype); #endif enctype = htonl(keys[i].enctype); memcpy(&enctypes[i], &enctype, 4); } #ifdef DEBUG fprintf(stderr, "}.\n"); #endif data->pa_type = KRB5_PADATA_CKSUM_BODY_REQ; data->length = (i * 4); data->contents = (unsigned char *) enctypes; krb5_free_data(kcontext, key_data); return 0; }
/* * This routine is the "obtain" function for the ENC_TIMESTAMP * preauthentication type. It take the current time and encrypts it * in the user's key. */ static krb5_error_code obtain_enc_ts_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata) { krb5_pa_enc_ts pa_enc; krb5_error_code retval; krb5_data * scratch; krb5_enc_data enc_data; krb5_pa_data * pa; retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec); if (retval) return retval; if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0) return retval; enc_data.ciphertext.data = 0; if ((retval = krb5_encrypt_helper(context, def_enc_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, scratch, &enc_data))) goto cleanup; krb5_free_data(context, scratch); scratch = 0; if ((retval = encode_krb5_enc_data(&enc_data, &scratch)) != 0) goto cleanup; if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) { retval = ENOMEM; goto cleanup; } pa->magic = KV5M_PA_DATA; pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP; pa->length = scratch->length; pa->contents = (krb5_octet *) scratch->data; *out_padata = pa; free(scratch); scratch = 0; retval = 0; cleanup: if (scratch) krb5_free_data(context, scratch); if (enc_data.ciphertext.data) free(enc_data.ciphertext.data); return retval; }
static krb5_error_code ec_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq) { krb5_error_code retval = 0; krb5_keyblock *challenge_key = (krb5_keyblock *)modreq; krb5_pa_enc_ts ts; krb5_data *plain = NULL; krb5_enc_data enc; krb5_data *encoded = NULL; krb5_pa_data *pa = NULL; if (challenge_key == NULL) return 0; enc.ciphertext.data = NULL; /* In case of error pass through */ retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = encode_krb5_pa_enc_ts(&ts, &plain); if (retval == 0) retval = krb5_encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, plain, &enc); if (retval == 0) retval = encode_krb5_enc_data(&enc, &encoded); if (retval == 0) { pa = calloc(1, sizeof(krb5_pa_data)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; pa->contents = (unsigned char *) encoded->data; pa->length = encoded->length; encoded->data = NULL; *send_pa = pa; pa = NULL; } if (challenge_key) krb5_free_keyblock(context, challenge_key); if (encoded) krb5_free_data(context, encoded); if (plain) krb5_free_data(context, plain); if (enc.ciphertext.data) krb5_free_data_contents(context, &enc.ciphertext); return retval; }
static krb5_error_code make_ad_signedpath_checksum(krb5_context context, krb5_const_principal for_user_princ, const krb5_db_entry *krbtgt, krb5_keyblock *krbtgt_key, krb5_enc_tkt_part *enc_tkt_part, krb5_principal *deleg_path, krb5_pa_data **method_data, krb5_checksum *cksum) { krb5_error_code code; krb5_data *data; krb5_cksumtype cksumtype; krb5_const_principal client; if (for_user_princ != NULL) client = for_user_princ; else client = enc_tkt_part->client; code = make_ad_signedpath_data(context, client, enc_tkt_part->times.authtime, deleg_path, method_data, enc_tkt_part->authorization_data, &data); if (code != 0) return code; code = krb5int_c_mandatory_cksumtype(context, krbtgt_key->enctype, &cksumtype); if (code != 0) { krb5_free_data(context, data); return code; } if (!krb5_c_is_keyed_cksum(cksumtype)) { krb5_free_data(context, data); return KRB5KRB_AP_ERR_INAPP_CKSUM; } code = krb5_c_make_checksum(context, cksumtype, krbtgt_key, KRB5_KEYUSAGE_AD_SIGNEDPATH, data, cksum); krb5_free_data(context, data); return code; }
krb5_boolean kdc_check_lookaside(krb5_data *inpkt, krb5_data **outpkt) { krb5_int32 timenow; register krb5_kdc_replay_ent *eptr, *last, *hold; time_t db_age; if (krb5_timeofday(kdc_context, &timenow) || krb5_db_get_age(kdc_context, 0, &db_age)) return FALSE; calls++; /* search for a replay entry in the queue, possibly removing stale entries while we're here */ if (root_ptr.next) { for (last = &root_ptr, eptr = root_ptr.next; eptr; eptr = eptr->next) { if (MATCH(eptr)) { eptr->num_hits++; hits++; if (krb5_copy_data(kdc_context, eptr->reply_packet, outpkt)) return FALSE; else return TRUE; /* return here, don't bother flushing even if it is stale. if we just matched, we may get another retransmit... */ } if (STALE(eptr)) { /* flush it and collect stats */ max_hits_per_entry = max(max_hits_per_entry, eptr->num_hits); krb5_free_data(kdc_context, eptr->req_packet); krb5_free_data(kdc_context, eptr->reply_packet); hold = eptr; last->next = eptr->next; eptr = last; free(hold); } else { /* this isn't it, just move along */ last = eptr; } } } return FALSE; }
static void free_paid(krb5_context context, struct pa_info_data *ppaid) { krb5_free_salt(context, ppaid->salt); if (ppaid->s2kparams) krb5_free_data(context, ppaid->s2kparams); }
/* frees memory associated with the lookaside queue for memory profiling */ void kdc_free_lookaside(krb5_context kcontext) { register krb5_kdc_replay_ent *eptr, *last, *hold; if (root_ptr.next) { for (last = &root_ptr, eptr = root_ptr.next; eptr; eptr = eptr->next) { krb5_free_data(kcontext, eptr->req_packet); krb5_free_data(kcontext, eptr->reply_packet); hold = eptr; last->next = eptr->next; eptr = last; free(hold); } } }
/* * encrypt the enc_part of krb5_cred */ static krb5_error_code encrypt_credencpart(krb5_context context, krb5_cred_enc_part *pcredpart, krb5_key pkey, krb5_enc_data *pencdata) { krb5_error_code retval; krb5_data * scratch; /* start by encoding to-be-encrypted part of the message */ if ((retval = encode_krb5_enc_cred_part(pcredpart, &scratch))) return retval; /* * If the keyblock is NULL, just copy the data from the encoded * data to the ciphertext area. */ if (pkey == NULL) { pencdata->ciphertext.data = scratch->data; pencdata->ciphertext.length = scratch->length; free(scratch); return 0; } /* call the encryption routine */ retval = k5_encrypt_keyhelper(context, pkey, KRB5_KEYUSAGE_KRB_CRED_ENCPART, scratch, pencdata); memset(scratch->data, 0, scratch->length); krb5_free_data(context, scratch); return retval; }
static krb5_error_code greet_authdata(krb5_context context, krb5_kdcauthdata_moddata moddata, unsigned int flags, krb5_db_entry *client, krb5_db_entry *server, krb5_db_entry *tgs, krb5_keyblock *client_key, krb5_keyblock *server_key, krb5_keyblock *krbtgt_key, krb5_data *req_pkt, krb5_kdc_req *request, krb5_const_principal for_user_princ, krb5_enc_tkt_part *enc_tkt_request, krb5_enc_tkt_part *enc_tkt_reply) { krb5_error_code code; krb5_data *greeting = NULL; if (request->msg_type != KRB5_TGS_REQ) return 0; code = greet_hello(context, &greeting); if (code != 0) return code; code = greet_kdc_sign(context, enc_tkt_reply, tgs->princ, greeting); krb5_free_data(context, greeting); return code; }
static krb5_error_code nonce_verify(krb5_context ctx, krb5_keyblock *armor_key, const krb5_data *nonce) { krb5_error_code retval; krb5_timestamp ts; krb5_data *er = NULL; if (armor_key == NULL || nonce->data == NULL) { retval = EINVAL; goto out; } /* Decode the PA-OTP-ENC-REQUEST structure. */ retval = decode_krb5_pa_otp_enc_req(nonce, &er); if (retval != 0) goto out; /* Make sure the nonce is exactly the same size as the one generated. */ if (er->length != armor_key->length + sizeof(krb5_timestamp)) goto out; /* Check to make sure the timestamp at the beginning is still valid. */ ts = load_32_be(er->data); retval = krb5_check_clockskew(ctx, ts); out: krb5_free_data(ctx, er); return retval; }
static void test_kdc_check_lookaside_hit_multiple(void **state) { struct entry *e1, *e2; krb5_boolean result; krb5_data *result_data; krb5_context context = *state; krb5_data req1 = string2data("I'm a test request"); krb5_data rep1 = string2data("I'm a test response"); krb5_data req2 = string2data("I'm a different test request"); e1 = insert_entry(context, &req1, &rep1, 0); e2 = insert_entry(context, &req2, NULL, 0); result = kdc_check_lookaside(context, &req1, &result_data); assert_true(result); assert_true(data_eq(rep1, *result_data)); assert_int_equal(hits, 1); assert_int_equal(e1->num_hits, 1); assert_int_equal(e2->num_hits, 0); krb5_free_data(context, result_data); /* Set result_data so we can verify that it is reset to NULL. */ result_data = &req1; result = kdc_check_lookaside(context, &req2, &result_data); assert_true(result); assert_null(result_data); assert_int_equal(hits, 2); assert_int_equal(e1->num_hits, 1); assert_int_equal(e2->num_hits, 1); }
static void otp_edata(krb5_context context, krb5_kdc_req *request, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type, krb5_kdcpreauth_edata_respond_fn respond, void *arg) { krb5_otp_tokeninfo ti, *tis[2] = { &ti, NULL }; krb5_keyblock *armor_key = NULL; krb5_pa_otp_challenge chl; krb5_pa_data *pa = NULL; krb5_error_code retval; krb5_data *encoding; char *config; /* Determine if otp is enabled for the user. */ retval = cb->get_string(context, rock, "otp", &config); if (retval == 0 && config == NULL) retval = ENOENT; if (retval != 0) goto out; cb->free_string(context, rock, config); /* Get the armor key. This indicates the length of random data to use in * the nonce. */ armor_key = cb->fast_armor(context, rock); if (armor_key == NULL) { retval = ENOENT; goto out; } /* Build the (mostly empty) challenge. */ memset(&ti, 0, sizeof(ti)); memset(&chl, 0, sizeof(chl)); chl.tokeninfo = tis; ti.format = -1; ti.length = -1; ti.iteration_count = -1; /* Generate the nonce. */ retval = nonce_generate(context, armor_key->length, &chl.nonce); if (retval != 0) goto out; /* Build the output pa-data. */ retval = encode_krb5_pa_otp_challenge(&chl, &encoding); if (retval != 0) goto out; pa = k5alloc(sizeof(krb5_pa_data), &retval); if (pa == NULL) { krb5_free_data(context, encoding); goto out; } pa->pa_type = KRB5_PADATA_OTP_CHALLENGE; pa->contents = (krb5_octet *)encoding->data; pa->length = encoding->length; free(encoding); out: (*respond)(arg, retval, pa); }
krb5_error_code krb5int_fast_prep_req_body(krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_req *request, krb5_data **encoded_request_body) { krb5_error_code retval = 0; krb5_data *local_encoded_request_body = NULL; assert(state != NULL); *encoded_request_body = NULL; if (state->armor_key == NULL) return encode_krb5_kdc_req_body(request, encoded_request_body); state->fast_outer_request = *request; state->fast_outer_request.padata = NULL; if (retval == 0) retval = encode_krb5_kdc_req_body(&state->fast_outer_request, &local_encoded_request_body); if (retval == 0) { *encoded_request_body = local_encoded_request_body; local_encoded_request_body = NULL; } if (local_encoded_request_body != NULL) krb5_free_data(context, local_encoded_request_body); return retval; }
krb5_error_code KRB5_CALLCONV krb5_encode_authdata_container(krb5_context context, krb5_authdatatype type, krb5_authdata *const*authdata, krb5_authdata ***container) { krb5_error_code code; krb5_data *data; krb5_authdata ad_datum; krb5_authdata *ad_data[2]; *container = NULL; code = encode_krb5_authdata((krb5_authdata * const *)authdata, &data); if (code) return code; ad_datum.ad_type = type & AD_TYPE_FIELD_TYPE_MASK; ad_datum.length = data->length; ad_datum.contents = (unsigned char *)data->data; ad_data[0] = &ad_datum; ad_data[1] = NULL; code = krb5_copy_authdata(context, ad_data, container); krb5_free_data(context, data); return code; }
static krb5_error_code encrypt_fast_reply(struct kdc_request_state *state, const krb5_fast_response *response, krb5_data **fx_fast_reply) { krb5_error_code retval = 0; krb5_enc_data encrypted_reply; krb5_data *encoded_response = NULL; kdc_realm_t *kdc_active_realm = state->realm_data; assert(state->armor_key); retval = encode_krb5_fast_response(response, &encoded_response); if (retval== 0) retval = krb5_encrypt_helper(kdc_context, state->armor_key, KRB5_KEYUSAGE_FAST_REP, encoded_response, &encrypted_reply); if (encoded_response) krb5_free_data(kdc_context, encoded_response); encoded_response = NULL; if (retval == 0) { retval = encode_krb5_pa_fx_fast_reply(&encrypted_reply, fx_fast_reply); krb5_free_data_contents(kdc_context, &encrypted_reply.ciphertext); } return retval; }
void k5_free_data_ptr_list(krb5_data **list) { int i; for (i = 0; list != NULL && list[i] != NULL; i++) krb5_free_data(NULL, list[i]); free(list); }
krb5_error_code securid_make_sam_challenge_2_and_cksum(krb5_context context, krb5_sam_challenge_2 *sc2, krb5_sam_challenge_2_body *sc2b, krb5_keyblock *cksum_key) { krb5_error_code retval; krb5_checksum **cksum_array = NULL; krb5_checksum *cksum = NULL; krb5_cksumtype cksumtype; krb5_data *encoded_challenge_body = NULL; if (!cksum_key) return KRB5_PREAUTH_NO_KEY; if (!sc2 || !sc2b) return KRB5KDC_ERR_PREAUTH_FAILED; retval = encode_krb5_sam_challenge_2_body(sc2b, &encoded_challenge_body); if (retval || !encoded_challenge_body) { encoded_challenge_body = NULL; goto cksum_cleanup; } cksum_array = calloc(2, sizeof(krb5_checksum *)); if (!cksum_array) { retval = ENOMEM; goto cksum_cleanup; } cksum = (krb5_checksum *)k5alloc(sizeof(krb5_checksum), &retval); if (retval) goto cksum_cleanup; cksum_array[0] = cksum; cksum_array[1] = NULL; retval = krb5int_c_mandatory_cksumtype(context, cksum_key->enctype, &cksumtype); if (retval) goto cksum_cleanup; retval = krb5_c_make_checksum(context, cksumtype, cksum_key, KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM, encoded_challenge_body, cksum); if (retval) goto cksum_cleanup; sc2->sam_cksum = cksum_array; sc2->sam_challenge_2_body = *encoded_challenge_body; return 0; cksum_cleanup: krb5_free_data(context, encoded_challenge_body); free(cksum_array); free(cksum); return retval; }
void KRB5_CALLCONV krb5_free_iakerb_header(krb5_context context, krb5_iakerb_header *val) { if (val == NULL) return ; krb5_free_data_contents(context, &val->target_realm); krb5_free_data(context, val->cookie); free(val); }
krb5_error_code krb5int_fast_process_response(krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_rep *resp, krb5_keyblock **strengthen_key) { krb5_error_code retval = 0; krb5_fast_response *fast_response = NULL; krb5_data *encoded_ticket = NULL; krb5_boolean cksum_valid; krb5_clear_error_message(context); *strengthen_key = NULL; if (state->armor_key == 0) return 0; retval = decrypt_fast_reply(context, state, resp->padata, &fast_response); if (retval == 0) { if (fast_response->finished == 0) { retval = KRB5_KDCREP_MODIFIED; krb5_set_error_message(context, retval, _("FAST response missing finish message " "in KDC reply")); } } if (retval == 0) retval = encode_krb5_ticket(resp->ticket, &encoded_ticket); if (retval == 0) retval = krb5_c_verify_checksum(context, state->armor_key, KRB5_KEYUSAGE_FAST_FINISHED, encoded_ticket, &fast_response->finished->ticket_checksum, &cksum_valid); if (retval == 0 && cksum_valid == 0) { retval = KRB5_KDCREP_MODIFIED; krb5_set_error_message(context, retval, _("Ticket modified in KDC reply")); } if (retval == 0) { krb5_free_principal(context, resp->client); resp->client = fast_response->finished->client; fast_response->finished->client = NULL; *strengthen_key = fast_response->strengthen_key; fast_response->strengthen_key = NULL; krb5_free_pa_data(context, resp->padata); resp->padata = fast_response->padata; fast_response->padata = NULL; } if (fast_response) krb5_free_fast_response(context, fast_response); if (encoded_ticket) krb5_free_data(context, encoded_ticket); return retval; }
static krb5_error_code make_proxy_request(struct conn_state *state, const krb5_data *realm, const krb5_data *message, char **req_out, size_t *len_out) { krb5_kkdcp_message pm; krb5_data *encoded_pm = NULL; struct k5buf buf; const char *uri_path; krb5_error_code ret; *req_out = NULL; *len_out = 0; /* * Stuff the message length in at the front of the kerb_message field * before encoding. The proxied messages are actually the payload we'd * be sending and receiving if we were using plain TCP. */ memset(&pm, 0, sizeof(pm)); ret = alloc_data(&pm.kerb_message, message->length + 4); if (ret != 0) goto cleanup; store_32_be(message->length, pm.kerb_message.data); memcpy(pm.kerb_message.data + 4, message->data, message->length); pm.target_domain = *realm; ret = encode_krb5_kkdcp_message(&pm, &encoded_pm); if (ret != 0) goto cleanup; /* Build the request to transmit: the headers + the proxy message. */ k5_buf_init_dynamic(&buf); uri_path = (state->http.uri_path != NULL) ? state->http.uri_path : ""; k5_buf_add_fmt(&buf, "POST /%s HTTP/1.0\r\n", uri_path); k5_buf_add(&buf, "Cache-Control: no-cache\r\n"); k5_buf_add(&buf, "Pragma: no-cache\r\n"); k5_buf_add(&buf, "User-Agent: kerberos/1.0\r\n"); k5_buf_add(&buf, "Content-type: application/kerberos\r\n"); k5_buf_add_fmt(&buf, "Content-Length: %d\r\n\r\n", encoded_pm->length); k5_buf_add_len(&buf, encoded_pm->data, encoded_pm->length); if (k5_buf_status(&buf) != 0) { ret = ENOMEM; goto cleanup; } *req_out = buf.data; *len_out = buf.len; cleanup: krb5_free_data_contents(NULL, &pm.kerb_message); krb5_free_data(NULL, encoded_pm); return ret; }
/* Dispatch routine for set/change password */ void dispatch(void *handle, struct sockaddr *local_saddr, const krb5_fulladdr *remote_faddr, krb5_data *request, int is_tcp, verto_ctx *vctx, loop_respond_fn respond, void *arg) { krb5_error_code ret; krb5_keytab kt = NULL; kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; krb5_fulladdr local_faddr; krb5_address **local_kaddrs = NULL, local_kaddr_buf; krb5_data *response = NULL; if (local_saddr == NULL) { ret = krb5_os_localaddr(server_handle->context, &local_kaddrs); if (ret != 0) goto egress; local_faddr.address = local_kaddrs[0]; local_faddr.port = 0; } else { local_faddr.address = &local_kaddr_buf; init_addr(&local_faddr, local_saddr); } ret = krb5_kt_resolve(server_handle->context, "KDB:", &kt); if (ret != 0) { krb5_klog_syslog(LOG_ERR, _("chpw: Couldn't open admin keytab %s"), krb5_get_error_message(server_handle->context, ret)); goto egress; } response = k5alloc(sizeof(krb5_data), &ret); if (response == NULL) goto egress; ret = process_chpw_request(server_handle->context, handle, server_handle->params.realm, kt, &local_faddr, remote_faddr, request, response); egress: if (ret) krb5_free_data(server_handle->context, response); krb5_free_addresses(server_handle->context, local_kaddrs); krb5_kt_close(server_handle->context, kt); (*respond)(arg, ret, ret == 0 ? response : NULL); }
krb5_error_code krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code_out, krb5_data *result_data_out) { krb5_error_code ret; krb5_data result_data, *clear = NULL; krb5_boolean is_error; char *ptr; int result_code; *result_code_out = 0; *result_data_out = empty_data(); ret = get_clear_result(context, auth_context, packet, &clear, &is_error); if (ret) return ret; if (clear->length < 2) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } /* Decode and check the result code. */ ptr = clear->data; result_code = (*ptr++ & 0xff); result_code = (result_code << 8) | (*ptr++ & 0xff); if (result_code < KRB5_KPASSWD_SUCCESS || result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } /* Successful replies must not come from errors. */ if (is_error && result_code == KRB5_KPASSWD_SUCCESS) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } result_data = make_data(ptr, clear->data + clear->length - ptr); ret = krb5int_copy_data_contents(context, &result_data, result_data_out); if (ret) goto cleanup; *result_code_out = result_code; cleanup: krb5_free_data(context, clear); return ret; }
static int krb4_sendto(int s, const char *msg, int len, int flags, const struct sockaddr *to, int to_len) { if ( !(response = (krb5_data *) malloc( sizeof *response))) { return ENOMEM; } if ( !(response->data = (char *) malloc( len))) { krb5_free_data(kdc_context, response); return ENOMEM; } response->length = len; memcpy( response->data, msg, len); return( 0); }
static OM_uint32 create_constrained_deleg_creds(OM_uint32 *minor_status, krb5_gss_cred_id_t verifier_cred_handle, krb5_ticket *ticket, krb5_gss_cred_id_t *out_cred, krb5_context context) { OM_uint32 major_status; krb5_creds krb_creds; krb5_data *data; krb5_error_code code; assert(out_cred != NULL); assert(verifier_cred_handle->usage == GSS_C_BOTH); memset(&krb_creds, 0, sizeof(krb_creds)); krb_creds.client = ticket->enc_part2->client; krb_creds.server = ticket->server; krb_creds.keyblock = *(ticket->enc_part2->session); krb_creds.ticket_flags = ticket->enc_part2->flags; krb_creds.times = ticket->enc_part2->times; krb_creds.magic = KV5M_CREDS; krb_creds.authdata = NULL; code = encode_krb5_ticket(ticket, &data); if (code) { *minor_status = code; return GSS_S_FAILURE; } krb_creds.ticket = *data; major_status = kg_compose_deleg_cred(minor_status, verifier_cred_handle, &krb_creds, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, out_cred, NULL, NULL, context); krb5_free_data(context, data); return major_status; }
krb5_error_code KRB5_CALLCONV krb5_authdata_export_attributes(krb5_context kcontext, krb5_authdata_context context, krb5_flags flags, krb5_data **attrsp) { krb5_error_code code; size_t required = 0; krb5_octet *bp; size_t remain; krb5_data *attrs; code = k5_ad_size(kcontext, context, AD_USAGE_MASK, &required); if (code != 0) return code; attrs = malloc(sizeof(*attrs)); if (attrs == NULL) return ENOMEM; attrs->magic = KV5M_DATA; attrs->length = 0; attrs->data = malloc(required); if (attrs->data == NULL) { free(attrs); return ENOMEM; } bp = (krb5_octet *)attrs->data; remain = required; code = k5_ad_externalize(kcontext, context, AD_USAGE_MASK, &bp, &remain); if (code != 0) { krb5_free_data(kcontext, attrs); return code; } attrs->length = (bp - (krb5_octet *)attrs->data); *attrsp = attrs; return 0; }
/* * AIX krb5 has krb5_decrypt_tkt_part, but no krb5_c_decrypt. So, implement our * own krb5_c_decrypt. Note that this krb5_c_decrypt is only suitable for * decrypting an encrypted krb5_enc_tkt_part. But since that's all we ever use * it for, that should be fine. */ static krb5_error_code krb5_c_decrypt(krb5_context context, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *cipher_state, const krb5_enc_data *input, krb5_data *output) { krb5_ticket tkt; krb5_error_code code; krb5_data *tout = NULL; /* We only handle a subset of possible arguments; if we somehow get passed * something else, bail out with EINVAL. */ if (cipher_state != NULL) return EINVAL; if (usage != KRB5_KEYUSAGE_KDC_REP_TICKET) return EINVAL; memset(&tkt, 0, sizeof(tkt)); tkt.enc_part = *input; code = krb5_decrypt_tkt_part(context, key, &tkt); if (code != 0) return code; code = encode_krb5_enc_tkt_part(tkt.enc_part2, &tout); if (code != 0) return code; if (tout->length > output->length) { /* This should never happen, but don't assert since we may be dealing * with untrusted user data. */ code = EINVAL; goto error; } memcpy(output->data, tout->data, tout->length); output->length = tout->length; error: if (tout) krb5_free_data(context, tout); return code; }
static void test_kdc_check_lookaside_hit(void **state) { struct entry *e; krb5_boolean result; krb5_data *result_data; krb5_context context = *state; krb5_data req = string2data("I'm a test request"); krb5_data rep = string2data("I'm a test response"); e = insert_entry(context, &req, &rep, 0); result = kdc_check_lookaside(context, &req, &result_data); assert_true(result); assert_true(data_eq(rep, *result_data)); assert_int_equal(hits, 1); assert_int_equal(e->num_hits, 1); krb5_free_data(context, result_data); }