krb5_error_code krb5int_confounder_verify(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, const krb5_data *input, krb5_boolean *valid) { krb5_error_code ret; unsigned char *plaintext = NULL; krb5_key xorkey = NULL; krb5_data computed = empty_data(); krb5_crypto_iov *hash_iov = NULL, iov; size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize; plaintext = k5memdup(input->data, input->length, &ret); if (plaintext == NULL) return ret; ret = mk_xorkey(key, &xorkey); if (ret != 0) goto cleanup; /* Decrypt the input checksum. */ iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = make_data(plaintext, input->length); ret = ctp->enc->decrypt(xorkey, NULL, &iov, 1); if (ret != 0) goto cleanup; /* Hash the confounder, then the input data. */ hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); if (hash_iov == NULL) goto cleanup; hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA; hash_iov[0].data = make_data(plaintext, blocksize); memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov)); ret = alloc_data(&computed, hashsize); if (ret != 0) goto cleanup; ret = ctp->hash->hash(hash_iov, num_data + 1, &computed); if (ret != 0) goto cleanup; /* Compare the decrypted hash to the computed one. */ *valid = (memcmp(plaintext + blocksize, computed.data, hashsize) == 0); cleanup: zapfree(plaintext, input->length); zapfree(computed.data, hashsize); free(hash_iov); krb5_k_free_key(NULL, xorkey); return ret; }
/* Derive a key by XOR with 0xF0 bytes. */ static krb5_error_code mk_xorkey(krb5_key origkey, krb5_key *xorkey) { krb5_error_code retval = 0; unsigned char *xorbytes; krb5_keyblock xorkeyblock; size_t i = 0; xorbytes = k5memdup(origkey->keyblock.contents, origkey->keyblock.length, &retval); if (xorbytes == NULL) return retval; for (i = 0; i < origkey->keyblock.length; i++) xorbytes[i] ^= 0xf0; /* Do a shallow copy here. */ xorkeyblock = origkey->keyblock; xorkeyblock.contents = xorbytes; retval = krb5_k_create_key(0, &xorkeyblock, xorkey); zapfree(xorbytes, sizeof(xorbytes)); return retval; }
krb5_error_code krb5_add_ber_mem_ldap_mod(LDAPMod ***list, char *attribute, int op, struct berval **ber_values) { krb5_error_code ret; LDAPMod *mod; size_t count, i; ret = alloc_mod(list, &mod); if (ret) return ret; mod->mod_type = strdup(attribute); if (mod->mod_type == NULL) return ENOMEM; mod->mod_op = op; for (count = 0; ber_values[count] != NULL; count++); mod->mod_bvalues = calloc(count + 1, sizeof(struct berval *)); if (mod->mod_bvalues == NULL) return ENOMEM; for (i = 0; i < count; i++) { mod->mod_bvalues[i] = calloc(1, sizeof(struct berval)); if (mod->mod_bvalues[i] == NULL) return ENOMEM; mod->mod_bvalues[i]->bv_len = ber_values[i]->bv_len; mod->mod_bvalues[i]->bv_val = k5memdup(ber_values[i]->bv_val, ber_values[i]->bv_len, &ret); if (mod->mod_bvalues[i]->bv_val == NULL) return ret; } mod->mod_bvalues[i] = NULL; return 0; }
krb5_error_code k5_os_hostaddr(krb5_context context, const char *name, krb5_address ***ret_addrs) { krb5_error_code retval; krb5_address **addrs; int i, j, r; struct addrinfo hints, *ai, *aip; if (!name) return KRB5_ERR_BAD_HOSTNAME; memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG; /* We don't care what kind at this point, really, but without this, we can get back multiple sockaddrs per address, for SOCK_DGRAM, SOCK_STREAM, and SOCK_RAW. I haven't checked if that's what the spec indicates. */ hints.ai_socktype = SOCK_DGRAM; r = getaddrinfo (name, 0, &hints, &ai); if (r && AI_NUMERICHOST != 0) { hints.ai_flags &= ~AI_NUMERICHOST; r = getaddrinfo (name, 0, &hints, &ai); } if (r) return KRB5_ERR_BAD_HOSTNAME; for (i = 0, aip = ai; aip; aip = aip->ai_next) { switch (aip->ai_addr->sa_family) { case AF_INET: case AF_INET6: i++; default: /* Ignore addresses of unknown families. */ ; } } addrs = malloc ((i+1) * sizeof(*addrs)); if (!addrs) return ENOMEM; for (j = 0; j < i + 1; j++) addrs[j] = 0; for (i = 0, aip = ai; aip; aip = aip->ai_next) { void *ptr; size_t addrlen; int atype; switch (aip->ai_addr->sa_family) { case AF_INET: addrlen = sizeof (struct in_addr); ptr = &sa2sin(aip->ai_addr)->sin_addr; atype = ADDRTYPE_INET; break; case AF_INET6: addrlen = sizeof (struct in6_addr); ptr = &sa2sin6(aip->ai_addr)->sin6_addr; atype = ADDRTYPE_INET6; break; default: continue; } addrs[i] = (krb5_address *) malloc(sizeof(krb5_address)); if (!addrs[i]) { retval = ENOMEM; goto errout; } addrs[i]->magic = KV5M_ADDRESS; addrs[i]->addrtype = atype; addrs[i]->length = addrlen; addrs[i]->contents = k5memdup(ptr, addrlen, &retval); if (addrs[i]->contents == NULL) goto errout; i++; } *ret_addrs = addrs; if (ai) freeaddrinfo(ai); return 0; errout: if (addrs) { for (i = 0; addrs[i]; i++) { free (addrs[i]->contents); free (addrs[i]); } krb5_free_addresses(context, addrs); } if (ai) freeaddrinfo(ai); return retval; }
krb5_error_code krb5_decode_princ_entry(krb5_context context, krb5_data *content, krb5_db_entry **entry_ptr) { int sizeleft, i; unsigned char * nextloc; krb5_tl_data ** tl_data; krb5_int16 i16; krb5_db_entry * entry; krb5_error_code retval; *entry_ptr = NULL; entry = k5alloc(sizeof(*entry), &retval); if (entry == NULL) return retval; /* * Reverse the encoding of encode_princ_entry. * * The first part is decoding the base type. If the base type is * bigger than the original base type then the additional fields * need to be filled in. If the base type is larger than any * known base type the additional data goes in e_data. */ /* First do the easy stuff */ nextloc = (unsigned char *)content->data; sizeleft = content->length; if (sizeleft < KRB5_KDB_V1_BASE_LENGTH) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= KRB5_KDB_V1_BASE_LENGTH; /* Base Length */ krb5_kdb_decode_int16(nextloc, entry->len); nextloc += 2; /* Attributes */ krb5_kdb_decode_int32(nextloc, entry->attributes); nextloc += 4; /* Max Life */ krb5_kdb_decode_int32(nextloc, entry->max_life); nextloc += 4; /* Max Renewable Life */ krb5_kdb_decode_int32(nextloc, entry->max_renewable_life); nextloc += 4; /* When the client expires */ krb5_kdb_decode_int32(nextloc, entry->expiration); nextloc += 4; /* When its passwd expires */ krb5_kdb_decode_int32(nextloc, entry->pw_expiration); nextloc += 4; /* Last successful passwd */ krb5_kdb_decode_int32(nextloc, entry->last_success); nextloc += 4; /* Last failed passwd attempt */ krb5_kdb_decode_int32(nextloc, entry->last_failed); nextloc += 4; /* # of failed passwd attempt */ krb5_kdb_decode_int32(nextloc, entry->fail_auth_count); nextloc += 4; /* # tl_data strutures */ krb5_kdb_decode_int16(nextloc, entry->n_tl_data); nextloc += 2; if (entry->n_tl_data < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* # key_data strutures */ krb5_kdb_decode_int16(nextloc, entry->n_key_data); nextloc += 2; if (entry->n_key_data < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* Check for extra data */ if (entry->len > KRB5_KDB_V1_BASE_LENGTH) { entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH; entry->e_data = k5memdup(nextloc, entry->e_length, &retval); if (entry->e_data == NULL) goto error_out; nextloc += entry->e_length; } /* * Get the principal name for the entry * (stored as a string which gets unparsed.) */ if (sizeleft < 2) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 2; i = 0; krb5_kdb_decode_int16(nextloc, i16); i = (int) i16; nextloc += 2; if (i <= 0 || i > sizeleft || nextloc[i - 1] != '\0' || memchr((char *)nextloc, '\0', i - 1) != NULL) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } if ((retval = krb5_parse_name(context, (char *)nextloc, &(entry->princ)))) goto error_out; sizeleft -= i; nextloc += i; /* tl_data is a linked list */ tl_data = &entry->tl_data; for (i = 0; i < entry->n_tl_data; i++) { if (sizeleft < 4) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 4; if ((*tl_data = (krb5_tl_data *) malloc(sizeof(krb5_tl_data))) == NULL) { retval = ENOMEM; goto error_out; } (*tl_data)->tl_data_next = NULL; (*tl_data)->tl_data_contents = NULL; krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type); nextloc += 2; krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length); nextloc += 2; if ((*tl_data)->tl_data_length > sizeleft) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= (*tl_data)->tl_data_length; (*tl_data)->tl_data_contents = k5memdup(nextloc, (*tl_data)->tl_data_length, &retval); if ((*tl_data)->tl_data_contents == NULL) goto error_out; nextloc += (*tl_data)->tl_data_length; tl_data = &((*tl_data)->tl_data_next); } /* key_data is an array */ if (entry->n_key_data && ((entry->key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) { retval = ENOMEM; goto error_out; } for (i = 0; i < entry->n_key_data; i++) { krb5_key_data * key_data; int j; if (sizeleft < 4) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 4; key_data = entry->key_data + i; memset(key_data, 0, sizeof(krb5_key_data)); krb5_kdb_decode_int16(nextloc, key_data->key_data_ver); nextloc += 2; krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno); nextloc += 2; /* key_data_ver determins number of elements and how to unparse them. */ if (key_data->key_data_ver >= 0 && key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) { for (j = 0; j < key_data->key_data_ver; j++) { if (sizeleft < 4) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 4; krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]); nextloc += 2; krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]); nextloc += 2; if (key_data->key_data_length[j] > sizeleft) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= key_data->key_data_length[j]; if (key_data->key_data_length[j]) { key_data->key_data_contents[j] = k5memdup(nextloc, key_data->key_data_length[j], &retval); if (key_data->key_data_contents[j] == NULL) goto error_out; nextloc += key_data->key_data_length[j]; } } } else { retval = KRB5_KDB_BAD_VERSION; goto error_out; } } *entry_ptr = entry; return 0; error_out: krb5_db_free_principal(context, entry); return retval; }
/* * Construct a TGS request and return its ASN.1 encoding as well as the * timestamp, nonce, and subkey used. The pacb_fn callback allows the caller * to amend the request padata after the nonce and subkey are determined. */ krb5_error_code k5_make_tgs_req(krb5_context context, struct krb5int_fast_request_state *fast_state, krb5_creds *tgt, krb5_flags kdcoptions, krb5_address *const *addrs, krb5_pa_data **in_padata, krb5_creds *desired, k5_pacb_fn pacb_fn, void *pacb_data, krb5_data *req_asn1_out, krb5_timestamp *timestamp_out, krb5_int32 *nonce_out, krb5_keyblock **subkey_out) { krb5_error_code ret; krb5_kdc_req req; krb5_data *authdata_asn1 = NULL, *req_body_asn1 = NULL; krb5_data *ap_req_asn1 = NULL, *tgs_req_asn1 = NULL; krb5_ticket *sec_ticket = NULL; krb5_ticket *sec_ticket_arr[2]; krb5_timestamp time_now; krb5_pa_data **padata = NULL, *pa; krb5_keyblock *subkey = NULL; krb5_enc_data authdata_enc; krb5_enctype enctypes[2], *defenctypes = NULL; size_t count, i; *req_asn1_out = empty_data(); *timestamp_out = 0; *nonce_out = 0; *subkey_out = NULL; memset(&req, 0, sizeof(req)); memset(&authdata_enc, 0, sizeof(authdata_enc)); /* tgt's client principal must match the desired client principal. */ if (!krb5_principal_compare(context, tgt->client, desired->client)) return KRB5_PRINC_NOMATCH; /* tgt must be an actual credential, not a template. */ if (!tgt->ticket.length) return KRB5_NO_TKT_SUPPLIED; req.kdc_options = kdcoptions; req.server = desired->server; req.from = desired->times.starttime; req.till = desired->times.endtime ? desired->times.endtime : tgt->times.endtime; req.rtime = desired->times.renew_till; ret = krb5_timeofday(context, &time_now); if (ret) return ret; *nonce_out = req.nonce = (krb5_int32)time_now; *timestamp_out = time_now; req.addresses = (krb5_address **)addrs; /* Generate subkey. */ ret = krb5_generate_subkey(context, &tgt->keyblock, &subkey); if (ret) return ret; TRACE_SEND_TGS_SUBKEY(context, subkey); ret = krb5int_fast_tgs_armor(context, fast_state, subkey, &tgt->keyblock, NULL, NULL); if (ret) goto cleanup; if (desired->authdata != NULL) { ret = encode_krb5_authdata(desired->authdata, &authdata_asn1); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, subkey, KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY, authdata_asn1, &authdata_enc); if (ret) goto cleanup; req.authorization_data = authdata_enc; } if (desired->keyblock.enctype != ENCTYPE_NULL) { if (!krb5_c_valid_enctype(desired->keyblock.enctype)) { ret = KRB5_PROG_ETYPE_NOSUPP; goto cleanup; } enctypes[0] = desired->keyblock.enctype; enctypes[1] = ENCTYPE_NULL; req.ktype = enctypes; req.nktypes = 1; } else { /* Get the default TGS enctypes. */ ret = krb5_get_tgs_ktypes(context, desired->server, &defenctypes); if (ret) goto cleanup; for (count = 0; defenctypes[count]; count++); req.ktype = defenctypes; req.nktypes = count; } TRACE_SEND_TGS_ETYPES(context, req.ktype); if (kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) { if (desired->second_ticket.length == 0) { ret = KRB5_NO_2ND_TKT; goto cleanup; } ret = decode_krb5_ticket(&desired->second_ticket, &sec_ticket); if (ret) goto cleanup; sec_ticket_arr[0] = sec_ticket; sec_ticket_arr[1] = NULL; req.second_ticket = sec_ticket_arr; } /* Encode the request body. */ ret = krb5int_fast_prep_req_body(context, fast_state, &req, &req_body_asn1); if (ret) goto cleanup; ret = tgs_construct_ap_req(context, req_body_asn1, tgt, subkey, &ap_req_asn1); if (ret) goto cleanup; for (count = 0; in_padata != NULL && in_padata[count] != NULL; count++); /* Construct a padata array for the request, beginning with the ap-req. */ padata = k5calloc(count + 2, sizeof(krb5_pa_data *), &ret); if (padata == NULL) goto cleanup; padata[0] = k5alloc(sizeof(krb5_pa_data), &ret); if (padata[0] == NULL) goto cleanup; padata[0]->pa_type = KRB5_PADATA_AP_REQ; padata[0]->contents = k5memdup(ap_req_asn1->data, ap_req_asn1->length, &ret); if (padata[0] == NULL) goto cleanup; padata[0]->length = ap_req_asn1->length; /* Append copies of any other supplied padata. */ for (i = 0; in_padata != NULL && in_padata[i] != NULL; i++) { pa = k5alloc(sizeof(krb5_pa_data), &ret); if (pa == NULL) goto cleanup; pa->pa_type = in_padata[i]->pa_type; pa->length = in_padata[i]->length; pa->contents = k5memdup(in_padata[i]->contents, in_padata[i]->length, &ret); if (pa->contents == NULL) goto cleanup; padata[i + 1] = pa; } req.padata = padata; if (pacb_fn != NULL) { ret = (*pacb_fn)(context, subkey, &req, pacb_data); if (ret) goto cleanup; } /* Encode the TGS-REQ. Discard the krb5_data container. */ ret = krb5int_fast_prep_req(context, fast_state, &req, ap_req_asn1, encode_krb5_tgs_req, &tgs_req_asn1); if (ret) goto cleanup; *req_asn1_out = *tgs_req_asn1; free(tgs_req_asn1); tgs_req_asn1 = NULL; *subkey_out = subkey; subkey = NULL; cleanup: krb5_free_data(context, authdata_asn1); krb5_free_data(context, req_body_asn1); krb5_free_data(context, ap_req_asn1); krb5_free_pa_data(context, req.padata); krb5_free_ticket(context, sec_ticket); krb5_free_data_contents(context, &authdata_enc.ciphertext); krb5_free_keyblock(context, subkey); free(defenctypes); return ret; }
static int kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message) { krb5_error_code code = 0; struct sockaddr_storage local_addr; krb5_address local_kaddr; struct sendto_callback_context *ctx = data; GETSOCKNAME_ARG3_TYPE addrlen; krb5_data output; memset (message, 0, sizeof(krb5_data)); /* * We need the local addr from the connection socket */ addrlen = sizeof(local_addr); if (getsockname(fd, ss2sa(&local_addr), &addrlen) < 0) { code = SOCKET_ERRNO; goto cleanup; } /* some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (local_addr.ss_family == AF_INET && ss2sin(&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr); local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr; } else if (local_addr.ss_family == AF_INET6 && memcmp(ss2sin6(&local_addr)->sin6_addr.s6_addr, in6addr_any.s6_addr, sizeof(in6addr_any.s6_addr)) != 0) { local_kaddr.addrtype = ADDRTYPE_INET6; local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr); local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr; } else { krb5_address **addrs; code = krb5_os_localaddr(ctx->context, &addrs); if (code) goto cleanup; local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; local_kaddr.contents = k5memdup(addrs[0]->contents, addrs[0]->length, &code); krb5_free_addresses(ctx->context, addrs); if (local_kaddr.contents == NULL) goto cleanup; } /* * TBD: Does this tamper w/ the auth context in such a way * to break us? Yes - provide 1 per conn-state / host... */ if ((code = krb5_auth_con_setaddrs(ctx->context, ctx->auth_context, &local_kaddr, NULL))) goto cleanup; ctx->auth_context->remote_seq_number = ctx->remote_seq_num; ctx->auth_context->local_seq_number = ctx->local_seq_num; if (ctx->set_password_for) code = krb5int_mk_setpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->set_password_for, ctx->newpw, &output); else code = krb5int_mk_chpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->newpw, &output); if (code) goto cleanup; message->length = output.length; message->data = output.data; cleanup: return code; }
krb5_error_code KRB5_CALLCONV krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime, krb5_const_principal principal, const krb5_keyblock *server_key, const krb5_keyblock *privsvr_key, krb5_data *data) { krb5_error_code ret; krb5_data server_cksum, privsvr_cksum; krb5_cksumtype server_cksumtype, privsvr_cksumtype; krb5_crypto_iov iov[2]; data->length = 0; data->data = NULL; if (principal != NULL) { ret = k5_insert_client_info(context, pac, authtime, principal); if (ret != 0) return ret; } /* Create zeroed buffers for both checksums */ ret = k5_insert_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server_key, &server_cksumtype); if (ret != 0) return ret; ret = k5_insert_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr_key, &privsvr_cksumtype); if (ret != 0) return ret; /* Now, encode the PAC header so that the checksums will include it */ ret = k5_pac_encode_header(context, pac); if (ret != 0) return ret; /* Generate the server checksum over the entire PAC */ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM, &server_cksum); if (ret != 0) return ret; assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH); iov[0].flags = KRB5_CRYPTO_TYPE_DATA; iov[0].data = pac->data; iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM; iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH; iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH; ret = krb5_c_make_checksum_iov(context, server_cksumtype, server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, sizeof(iov)/sizeof(iov[0])); if (ret != 0) return ret; /* Generate the privsvr checksum over the server checksum buffer */ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, &privsvr_cksum); if (ret != 0) return ret; assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH); iov[0].flags = KRB5_CRYPTO_TYPE_DATA; iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH; iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH; iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM; iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH; iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH; ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype, privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, sizeof(iov)/sizeof(iov[0])); if (ret != 0) return ret; data->data = k5memdup(pac->data.data, pac->data.length, &ret); if (data->data == NULL) return ret; data->length = pac->data.length; memset(pac->data.data, 0, PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH)); return 0; }
krb5_error_code kdc_find_fast(krb5_kdc_req **requestptr, krb5_data *checksummed_data, krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session, struct kdc_request_state *state, krb5_data **inner_body_out) { krb5_error_code retval = 0; krb5_pa_data *fast_padata, *cookie_padata = NULL; krb5_data scratch, *inner_body = NULL; krb5_fast_req * fast_req = NULL; krb5_kdc_req *request = *requestptr; krb5_fast_armored_req *fast_armored_req = NULL; krb5_checksum *cksum; krb5_boolean cksum_valid; krb5_keyblock empty_keyblock; kdc_realm_t *kdc_active_realm = state->realm_data; if (inner_body_out != NULL) *inner_body_out = NULL; scratch.data = NULL; krb5_clear_error_message(kdc_context); memset(&empty_keyblock, 0, sizeof(krb5_keyblock)); fast_padata = krb5int_find_pa_data(kdc_context, request->padata, KRB5_PADATA_FX_FAST); if (fast_padata != NULL){ scratch.length = fast_padata->length; scratch.data = (char *) fast_padata->contents; retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req); if (retval == 0 &&fast_armored_req->armor) { switch (fast_armored_req->armor->armor_type) { case KRB5_FAST_ARMOR_AP_REQUEST: if (tgs_subkey) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(kdc_context, retval, _("Ap-request armor not permitted " "with TGS")); break; } retval = armor_ap_request(state, fast_armored_req->armor); break; default: krb5_set_error_message(kdc_context, KRB5KDC_ERR_PREAUTH_FAILED, _("Unknown FAST armor type %d"), fast_armored_req->armor->armor_type); retval = KRB5KDC_ERR_PREAUTH_FAILED; } } if (retval == 0 && !state->armor_key) { if (tgs_subkey) retval = krb5_c_fx_cf2_simple(kdc_context, tgs_subkey, "subkeyarmor", tgs_session, "ticketarmor", &state->armor_key); else { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(kdc_context, retval, _("No armor key but FAST armored " "request present")); } } if (retval == 0) { krb5_data plaintext; plaintext.length = fast_armored_req->enc_part.ciphertext.length; plaintext.data = malloc(plaintext.length); if (plaintext.data == NULL) retval = ENOMEM; retval = krb5_c_decrypt(kdc_context, state->armor_key, KRB5_KEYUSAGE_FAST_ENC, NULL, &fast_armored_req->enc_part, &plaintext); if (retval == 0) retval = decode_krb5_fast_req(&plaintext, &fast_req); if (retval == 0 && inner_body_out != NULL) { retval = fetch_asn1_field((unsigned char *)plaintext.data, 1, 2, &scratch); if (retval == 0) { retval = krb5_copy_data(kdc_context, &scratch, &inner_body); } } if (plaintext.data) free(plaintext.data); } cksum = &fast_armored_req->req_checksum; if (retval == 0) retval = krb5_c_verify_checksum(kdc_context, state->armor_key, KRB5_KEYUSAGE_FAST_REQ_CHKSUM, checksummed_data, cksum, &cksum_valid); if (retval == 0 && !cksum_valid) { retval = KRB5KRB_AP_ERR_MODIFIED; krb5_set_error_message(kdc_context, retval, _("FAST req_checksum invalid; request " "modified")); } if (retval == 0) { if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) { retval = KRB5KDC_ERR_POLICY; krb5_set_error_message(kdc_context, retval, _("Unkeyed checksum used in fast_req")); } } if (retval == 0) { if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) != 0) retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION; } if (retval == 0) cookie_padata = krb5int_find_pa_data(kdc_context, fast_req->req_body->padata, KRB5_PADATA_FX_COOKIE); if (retval == 0) { state->fast_options = fast_req->fast_options; fast_req->req_body->msg_type = request->msg_type; krb5_free_kdc_req( kdc_context, request); *requestptr = fast_req->req_body; fast_req->req_body = NULL; } } else { cookie_padata = krb5int_find_pa_data(kdc_context, request->padata, KRB5_PADATA_FX_COOKIE); } if (retval == 0 && cookie_padata != NULL) { krb5_pa_data *new_padata = malloc(sizeof (krb5_pa_data)); if (new_padata == NULL) { retval = ENOMEM; } else { new_padata->pa_type = KRB5_PADATA_FX_COOKIE; new_padata->length = cookie_padata->length; new_padata->contents = k5memdup(cookie_padata->contents, new_padata->length, &retval); if (new_padata->contents == NULL) free(new_padata); else state->cookie = new_padata; } } if (retval == 0 && inner_body_out != NULL) { *inner_body_out = inner_body; inner_body = NULL; } krb5_free_data(kdc_context, inner_body); if (fast_req) krb5_free_fast_req( kdc_context, fast_req); if (fast_armored_req) krb5_free_fast_armored_req(kdc_context, fast_armored_req); return retval; }
static krb5_error_code process_db_args(krb5_context context, char **db_args, xargs_t *xargs, OPERATION optype) { int i=0; krb5_error_code st=0; char *arg=NULL, *arg_val=NULL; char **dptr=NULL; unsigned int arg_val_len=0; if (db_args) { for (i=0; db_args[i]; ++i) { arg = strtok_r(db_args[i], "=", &arg_val); if (strcmp(arg, TKTPOLICY_ARG) == 0) { dptr = &xargs->tktpolicydn; } else { if (strcmp(arg, USERDN_ARG) == 0) { if (optype == MODIFY_PRINCIPAL || xargs->dn != NULL || xargs->containerdn != NULL || xargs->linkdn != NULL) { st = EINVAL; krb5_set_error_message(context, st, _("%s option not supported"), arg); goto cleanup; } dptr = &xargs->dn; } else if (strcmp(arg, CONTAINERDN_ARG) == 0) { if (optype == MODIFY_PRINCIPAL || xargs->dn != NULL || xargs->containerdn != NULL) { st = EINVAL; krb5_set_error_message(context, st, _("%s option not supported"), arg); goto cleanup; } dptr = &xargs->containerdn; } else if (strcmp(arg, LINKDN_ARG) == 0) { if (xargs->dn != NULL || xargs->linkdn != NULL) { st = EINVAL; krb5_set_error_message(context, st, _("%s option not supported"), arg); goto cleanup; } dptr = &xargs->linkdn; } else { st = EINVAL; krb5_set_error_message(context, st, _("unknown option: %s"), arg); goto cleanup; } xargs->dn_from_kbd = TRUE; if (arg_val == NULL || strlen(arg_val) == 0) { st = EINVAL; krb5_set_error_message(context, st, _("%s option value missing"), arg); goto cleanup; } } if (arg_val == NULL) { st = EINVAL; krb5_set_error_message(context, st, _("%s option value missing"), arg); goto cleanup; } arg_val_len = strlen(arg_val) + 1; if (strcmp(arg, TKTPOLICY_ARG) == 0) { if ((st = krb5_ldap_name_to_policydn (context, arg_val, dptr)) != 0) goto cleanup; } else { *dptr = k5memdup(arg_val, arg_val_len, &st); if (*dptr == NULL) goto cleanup; } } } cleanup: return st; }