KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_ret_creds_tag(krb5_storage *sp, krb5_creds *creds) { krb5_error_code ret; int8_t dummy8; int32_t dummy32, header; memset(creds, 0, sizeof(*creds)); ret = krb5_ret_int32 (sp, &header); if (ret) goto cleanup; if (header & SC_CLIENT_PRINCIPAL) { ret = krb5_ret_principal (sp, &creds->client); if(ret) goto cleanup; } if (header & SC_SERVER_PRINCIPAL) { ret = krb5_ret_principal (sp, &creds->server); if(ret) goto cleanup; } if (header & SC_SESSION_KEY) { ret = krb5_ret_keyblock (sp, &creds->session); if(ret) goto cleanup; } ret = krb5_ret_times (sp, &creds->times); if(ret) goto cleanup; ret = krb5_ret_int8 (sp, &dummy8); if(ret) goto cleanup; ret = krb5_ret_int32 (sp, &dummy32); if(ret) goto cleanup; creds->flags.b = int2TicketFlags(bitswap32(dummy32)); if (header & SC_ADDRESSES) { ret = krb5_ret_addrs (sp, &creds->addresses); if(ret) goto cleanup; } if (header & SC_AUTHDATA) { ret = krb5_ret_authdata (sp, &creds->authdata); if(ret) goto cleanup; } if (header & SC_TICKET) { ret = krb5_ret_data (sp, &creds->ticket); if(ret) goto cleanup; } if (header & SC_SECOND_TICKET) { ret = krb5_ret_data (sp, &creds->second_ticket); if(ret) goto cleanup; } cleanup: if(ret) { #if 0 krb5_free_cred_contents(context, creds); /* XXX */ #endif } return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_ret_creds(krb5_storage *sp, krb5_creds *creds) { krb5_error_code ret; int8_t dummy8; int32_t dummy32; memset(creds, 0, sizeof(*creds)); ret = krb5_ret_principal (sp, &creds->client); if(ret) goto cleanup; ret = krb5_ret_principal (sp, &creds->server); if(ret) goto cleanup; ret = krb5_ret_keyblock (sp, &creds->session); if(ret) goto cleanup; ret = krb5_ret_times (sp, &creds->times); if(ret) goto cleanup; ret = krb5_ret_int8 (sp, &dummy8); if(ret) goto cleanup; ret = krb5_ret_int32 (sp, &dummy32); if(ret) goto cleanup; /* * Runtime detect the what is the higher bits of the bitfield. If * any of the higher bits are set in the input data, it's either a * new ticket flag (and this code need to be removed), or it's a * MIT cache (or new Heimdal cache), lets change it to our current * format. */ { uint32_t mask = 0xffff0000; creds->flags.i = 0; creds->flags.b.anonymous = 1; if (creds->flags.i & mask) mask = ~mask; if (dummy32 & mask) dummy32 = bitswap32(dummy32); } creds->flags.i = dummy32; ret = krb5_ret_addrs (sp, &creds->addresses); if(ret) goto cleanup; ret = krb5_ret_authdata (sp, &creds->authdata); if(ret) goto cleanup; ret = krb5_ret_data (sp, &creds->ticket); if(ret) goto cleanup; ret = krb5_ret_data (sp, &creds->second_ticket); cleanup: if(ret) { #if 0 krb5_free_cred_contents(context, creds); /* XXX */ #endif } return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_ret_creds(krb5_storage *sp, krb5_creds *creds) { krb5_error_code ret; int8_t dummy8; int32_t dummy32; memset(creds, 0, sizeof(*creds)); ret = krb5_ret_principal (sp, &creds->client); if(ret) goto cleanup; ret = krb5_ret_principal (sp, &creds->server); if(ret) goto cleanup; ret = krb5_ret_keyblock (sp, &creds->session); if(ret) goto cleanup; ret = krb5_ret_times (sp, &creds->times); if(ret) goto cleanup; ret = krb5_ret_int8 (sp, &dummy8); if(ret) goto cleanup; ret = krb5_ret_int32 (sp, &dummy32); if(ret) goto cleanup; creds->flags.b = int2TicketFlags(bitswap32(dummy32)); ret = krb5_ret_addrs (sp, &creds->addresses); if(ret) goto cleanup; ret = krb5_ret_authdata (sp, &creds->authdata); if(ret) goto cleanup; ret = krb5_ret_data (sp, &creds->ticket); if(ret) goto cleanup; ret = krb5_ret_data (sp, &creds->second_ticket); cleanup: if(ret) { #if 0 krb5_free_cred_contents(context, creds); /* XXX */ #endif } return ret; }
OM_uint32 gss_import_sec_context ( OM_uint32 * minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t * context_handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_error_code kret; krb5_storage *sp; krb5_auth_context ac; krb5_address local, remote; krb5_address *localp, *remotep; krb5_data data; gss_buffer_desc buffer; krb5_keyblock keyblock; int32_t tmp; int32_t flags; OM_uint32 minor; int is_cfx = 0; GSSAPI_KRB5_INIT (); localp = remotep = NULL; sp = krb5_storage_from_mem (interprocess_token->value, interprocess_token->length); if (sp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } *context_handle = malloc(sizeof(**context_handle)); if (*context_handle == NULL) { *minor_status = ENOMEM; krb5_storage_free (sp); return GSS_S_FAILURE; } memset (*context_handle, 0, sizeof(**context_handle)); HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex); kret = krb5_auth_con_init (gssapi_krb5_context, &(*context_handle)->auth_context); if (kret) { gssapi_krb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* flags */ *minor_status = 0; if (krb5_ret_int32 (sp, &flags) != 0) goto failure; /* retrieve the auth context */ ac = (*context_handle)->auth_context; krb5_ret_int32 (sp, &ac->flags); if (flags & SC_LOCAL_ADDRESS) { if (krb5_ret_address (sp, localp = &local) != 0) goto failure; } if (flags & SC_REMOTE_ADDRESS) { if (krb5_ret_address (sp, remotep = &remote) != 0) goto failure; } krb5_auth_con_setaddrs (gssapi_krb5_context, ac, localp, remotep); if (localp) krb5_free_address (gssapi_krb5_context, localp); if (remotep) krb5_free_address (gssapi_krb5_context, remotep); localp = remotep = NULL; if (krb5_ret_int16 (sp, &ac->local_port) != 0) goto failure; if (krb5_ret_int16 (sp, &ac->remote_port) != 0) goto failure; if (flags & SC_KEYBLOCK) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setlocalsubkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setremotesubkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (krb5_ret_int32 (sp, &ac->local_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &ac->remote_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->keytype = tmp; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->cksumtype = tmp; /* names */ if (krb5_ret_data (sp, &data)) goto failure; buffer.value = data.data; buffer.length = data.length; ret = gss_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &(*context_handle)->source); if (ret) { ret = gss_import_name (minor_status, &buffer, GSS_C_NO_OID, &(*context_handle)->source); if (ret) { krb5_data_free (&data); goto failure; } } krb5_data_free (&data); if (krb5_ret_data (sp, &data) != 0) goto failure; buffer.value = data.data; buffer.length = data.length; ret = gss_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &(*context_handle)->target); if (ret) { ret = gss_import_name (minor_status, &buffer, GSS_C_NO_OID, &(*context_handle)->target); if (ret) { krb5_data_free (&data); goto failure; } } krb5_data_free (&data); if (krb5_ret_int32 (sp, &tmp)) goto failure; (*context_handle)->flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; (*context_handle)->more_flags = tmp; if (krb5_ret_int32 (sp, &tmp) == 0) (*context_handle)->lifetime = tmp; else (*context_handle)->lifetime = GSS_C_INDEFINITE; gsskrb5_is_cfx(*context_handle, &is_cfx); ret = _gssapi_msg_order_create(minor_status, &(*context_handle)->order, _gssapi_msg_order_f((*context_handle)->flags), 0, 0, is_cfx); if (ret) goto failure; krb5_storage_free (sp); return GSS_S_COMPLETE; failure: krb5_auth_con_free (gssapi_krb5_context, (*context_handle)->auth_context); if ((*context_handle)->source != NULL) gss_release_name(&minor, &(*context_handle)->source); if ((*context_handle)->target != NULL) gss_release_name(&minor, &(*context_handle)->target); if (localp) krb5_free_address (gssapi_krb5_context, localp); if (remotep) krb5_free_address (gssapi_krb5_context, remotep); if((*context_handle)->order) _gssapi_msg_order_destroy(&(*context_handle)->order); HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex); krb5_storage_free (sp); free (*context_handle); *context_handle = GSS_C_NO_CONTEXT; return ret; }
/* * Request: * NameZ * ServerPrincipalPresent * ServerPrincipal OPTIONAL * Key * * Repsonse: * */ static krb5_error_code kcm_op_get_initial_ticket(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *request, krb5_storage *response) { krb5_error_code ret; kcm_ccache ccache; char *name; int8_t not_tgt = 0; krb5_principal server = NULL; krb5_keyblock key; krb5_keyblock_zero(&key); ret = krb5_ret_stringz(request, &name); if (ret) return ret; KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = krb5_ret_int8(request, ¬_tgt); if (ret) { free(name); return ret; } if (not_tgt) { ret = krb5_ret_principal(request, &server); if (ret) { free(name); return ret; } } ret = krb5_ret_keyblock(request, &key); if (ret) { free(name); if (server != NULL) krb5_free_principal(context, server); return ret; } ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); if (ret == 0) { HEIMDAL_MUTEX_lock(&ccache->mutex); if (ccache->server != NULL) { krb5_free_principal(context, ccache->server); ccache->server = NULL; } krb5_free_keyblock(context, &ccache->key.keyblock); ccache->server = server; ccache->key.keyblock = key; ccache->flags |= KCM_FLAGS_USE_CACHED_KEY; ret = kcm_ccache_enqueue_default(context, ccache, NULL); if (ret) { ccache->server = NULL; krb5_keyblock_zero(&ccache->key.keyblock); ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY); } HEIMDAL_MUTEX_unlock(&ccache->mutex); } free(name); if (ret != 0) { krb5_free_principal(context, server); krb5_free_keyblock(context, &key); } kcm_release_ccache(context, ccache); return ret; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_sec_context ( OM_uint32 * minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t * context_handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_context context; krb5_error_code kret; krb5_storage *sp; krb5_auth_context ac; krb5_address local, remote; krb5_address *localp, *remotep; krb5_data data; gss_buffer_desc buffer; krb5_keyblock keyblock; int32_t flags, tmp; gsskrb5_ctx ctx; gss_name_t name; GSSAPI_KRB5_INIT (&context); *context_handle = GSS_C_NO_CONTEXT; localp = remotep = NULL; sp = krb5_storage_from_mem (interprocess_token->value, interprocess_token->length); if (sp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; krb5_storage_free (sp); return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); kret = krb5_auth_con_init (context, &ctx->auth_context); if (kret) { *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* flags */ *minor_status = 0; if (krb5_ret_int32 (sp, &flags) != 0) goto failure; /* retrieve the auth context */ ac = ctx->auth_context; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->flags = tmp; if (flags & SC_LOCAL_ADDRESS) { if (krb5_ret_address (sp, localp = &local) != 0) goto failure; } if (flags & SC_REMOTE_ADDRESS) { if (krb5_ret_address (sp, remotep = &remote) != 0) goto failure; } krb5_auth_con_setaddrs (context, ac, localp, remotep); if (localp) krb5_free_address (context, localp); if (remotep) krb5_free_address (context, remotep); localp = remotep = NULL; if (krb5_ret_int16 (sp, &ac->local_port) != 0) goto failure; if (krb5_ret_int16 (sp, &ac->remote_port) != 0) goto failure; if (flags & SC_KEYBLOCK) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setlocalsubkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setremotesubkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (krb5_ret_uint32 (sp, &ac->local_seqnumber)) goto failure; if (krb5_ret_uint32 (sp, &ac->remote_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->keytype = tmp; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->cksumtype = tmp; /* names */ if (krb5_ret_data (sp, &data)) goto failure; buffer.value = data.data; buffer.length = data.length; ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &name); if (ret) { ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NO_OID, &name); if (ret) { krb5_data_free (&data); goto failure; } } ctx->source = (krb5_principal)name; krb5_data_free (&data); if (krb5_ret_data (sp, &data) != 0) goto failure; buffer.value = data.data; buffer.length = data.length; ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &name); if (ret) { ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NO_OID, &name); if (ret) { krb5_data_free (&data); goto failure; } } ctx->target = (krb5_principal)name; krb5_data_free (&data); if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->more_flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->endtime = tmp; ret = _gssapi_msg_order_import(minor_status, sp, &ctx->gk5c.order); if (ret) goto failure; krb5_storage_free (sp); _gsskrb5i_is_cfx(context, ctx, (ctx->more_flags & LOCAL) == 0); *context_handle = (gss_ctx_id_t)ctx; return GSS_S_COMPLETE; failure: krb5_auth_con_free (context, ctx->auth_context); if (ctx->source != NULL) krb5_free_principal(context, ctx->source); if (ctx->target != NULL) krb5_free_principal(context, ctx->target); if (localp) krb5_free_address (context, localp); if (remotep) krb5_free_address (context, remotep); if(ctx->gk5c.order) _gssapi_msg_order_destroy(&ctx->gk5c.order); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); krb5_storage_free (sp); free (ctx); *context_handle = GSS_C_NO_CONTEXT; return ret; }
static OM_uint32 gsskrb5_extract_key(OM_uint32 *minor_status, gss_ctx_id_t context_handle, const gss_OID oid, krb5_keyblock **keyblock) { krb5_error_code ret; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 major_status; krb5_context context = NULL; krb5_storage *sp = NULL; if (context_handle == GSS_C_NO_CONTEXT) { ret = EINVAL; return GSS_S_FAILURE; } ret = krb5_init_context(&context); if(ret) { *minor_status = ret; return GSS_S_FAILURE; } major_status = gss_inquire_sec_context_by_oid (minor_status, context_handle, oid, &data_set); if (major_status) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } sp = krb5_storage_from_mem(data_set->elements[0].value, data_set->elements[0].length); if (sp == NULL) { ret = ENOMEM; goto out; } *keyblock = calloc(1, sizeof(**keyblock)); if (keyblock == NULL) { ret = ENOMEM; goto out; } ret = krb5_ret_keyblock(sp, *keyblock); out: gss_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (ret && keyblock) { krb5_free_keyblock(context, *keyblock); *keyblock = NULL; } if (context) krb5_free_context(context); *minor_status = ret; if (ret) return GSS_S_FAILURE; return GSS_S_COMPLETE; }
OM_uint32 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, OM_uint32 version, void **rctx) { krb5_context context = NULL; krb5_error_code ret; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 major_status; gss_krb5_lucid_context_v1_t *ctx = NULL; krb5_storage *sp = NULL; uint32_t num; if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT || version != 1) { ret = EINVAL; return GSS_S_FAILURE; } major_status = gss_inquire_sec_context_by_oid (minor_status, *context_handle, GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, &data_set); if (major_status) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } ret = krb5_init_context(&context); if (ret) goto out; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { ret = ENOMEM; goto out; } sp = krb5_storage_from_mem(data_set->elements[0].value, data_set->elements[0].length); if (sp == NULL) { ret = ENOMEM; goto out; } ret = krb5_ret_uint32(sp, &num); if (ret) goto out; if (num != 1) { ret = EINVAL; goto out; } ctx->version = 1; /* initiator */ ret = krb5_ret_uint32(sp, &ctx->initiate); if (ret) goto out; /* endtime */ ret = krb5_ret_uint32(sp, &ctx->endtime); if (ret) goto out; /* send_seq */ ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->send_seq = ((uint64_t)num) << 32; ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->send_seq |= num; /* recv_seq */ ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->recv_seq = ((uint64_t)num) << 32; ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->recv_seq |= num; /* protocol */ ret = krb5_ret_uint32(sp, &ctx->protocol); if (ret) goto out; if (ctx->protocol == 0) { krb5_keyblock key; /* sign_alg */ ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); if (ret) goto out; /* seal_alg */ ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); if (ret) goto out; /* ctx_key */ ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); krb5_free_keyblock_contents(context, &key); if (ret) goto out; } else if (ctx->protocol == 1) { krb5_keyblock key; /* acceptor_subkey */ ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); if (ret) goto out; /* ctx_key */ ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->cfx_kd.ctx_key); krb5_free_keyblock_contents(context, &key); if (ret) goto out; /* acceptor_subkey */ if (ctx->cfx_kd.have_acceptor_subkey) { ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); krb5_free_keyblock_contents(context, &key); if (ret) goto out; } } else { ret = EINVAL; goto out; } *rctx = ctx; out: gss_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (context) krb5_free_context(context); if (ret) { if (ctx) gss_krb5_free_lucid_sec_context(NULL, ctx); *minor_status = ret; return GSS_S_FAILURE; } *minor_status = 0; return GSS_S_COMPLETE; }
kadm5_ret_t kadm5_c_randkey_principal(void *server_handle, krb5_principal princ, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **new_keys, int *n_keys) { kadm5_client_context *context = server_handle; kadm5_ret_t ret; krb5_storage *sp; unsigned char buf[1536]; int32_t tmp; size_t i; krb5_data reply; ret = _kadm5_connect(server_handle); if(ret) return ret; sp = krb5_storage_from_mem(buf, sizeof(buf)); if (sp == NULL) { krb5_clear_error_message(context->context); return ENOMEM; } /* * NOTE WELL: This message is extensible. It currently consists of: * * - opcode (kadm_randkey) * - principal name (princ) * * followed by optional items, each of which must be present if * there are any items following them that are also present: * * - keepold boolean (whether to delete old kvnos) * - number of key/salt type tuples * - array of {enctype, salttype} * * Eventually we may add: * * - opaque string2key parameters (salt, rounds, ...) */ krb5_store_int32(sp, kadm_randkey); krb5_store_principal(sp, princ); if (keepold == TRUE || n_ks_tuple > 0) krb5_store_uint32(sp, keepold); if (n_ks_tuple > 0) krb5_store_uint32(sp, n_ks_tuple); for (i = 0; i < n_ks_tuple; i++) { krb5_store_int32(sp, ks_tuple[i].ks_enctype); krb5_store_int32(sp, ks_tuple[i].ks_salttype); } /* Future extensions go here */ ret = _kadm5_client_send(context, sp); krb5_storage_free(sp); if (ret) return ret; ret = _kadm5_client_recv(context, &reply); if(ret) return ret; sp = krb5_storage_from_data(&reply); if (sp == NULL) { krb5_clear_error_message(context->context); krb5_data_free (&reply); return ENOMEM; } krb5_clear_error_message(context->context); krb5_ret_int32(sp, &tmp); ret = tmp; if(ret == 0){ krb5_keyblock *k; krb5_ret_int32(sp, &tmp); if (tmp < 0) { ret = EOVERFLOW; goto out; } k = malloc(tmp * sizeof(*k)); if (k == NULL) { ret = ENOMEM; goto out; } for(i = 0; i < tmp; i++) krb5_ret_keyblock(sp, &k[i]); if (n_keys && new_keys) { *n_keys = tmp; *new_keys = k; } } out: krb5_storage_free(sp); krb5_data_free (&reply); return ret; }