2 * lib/krb5/krb/get_in_tkt.c
4 * Copyright 1990,1991, 2003 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
33 #include "int-proto.h"
37 All-purpose initial ticket routine, usually called via
38 krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey.
40 Attempts to get an initial ticket for creds->client to use server
41 creds->server, (realm is taken from creds->client), with options
42 options, and using creds->times.starttime, creds->times.endtime,
43 creds->times.renew_till as from, till, and rtime.
44 creds->times.renew_till is ignored unless the RENEWABLE option is requested.
46 key_proc is called to fill in the key to be used for decryption.
47 keyseed is passed on to key_proc.
49 decrypt_proc is called to perform the decryption of the response (the
50 encrypted part is in dec_rep->enc_part; the decrypted part should be
51 allocated and filled into dec_rep->enc_part2
52 arg is passed on to decrypt_proc.
54 If addrs is non-NULL, it is used for the addresses requested. If it is
55 null, the system standard addresses are used.
57 A succesful call will place the ticket in the credentials cache ccache
58 and fill in creds with the ticket information used/returned..
60 returns system errors, encryption errors
65 /* some typedef's for the function args to make things look a bit cleaner */
67 typedef krb5_error_code (*git_key_proc) (krb5_context,
73 typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
74 const krb5_keyblock *,
78 static krb5_error_code make_preauth_list (krb5_context,
80 int, krb5_pa_data ***);
82 * This function sends a request to the KDC, and gets back a response;
83 * the response is parsed into ret_err_reply or ret_as_reply if the
84 * reponse is a KRB_ERROR or a KRB_AS_REP packet. If it is some other
85 * unexpected response, an error is returned.
87 static krb5_error_code
88 send_as_request(krb5_context context,
89 krb5_kdc_req *request,
90 krb5_timestamp *time_now,
91 krb5_error ** ret_err_reply,
92 krb5_kdc_rep ** ret_as_reply,
95 krb5_kdc_rep *as_reply = 0;
96 krb5_error_code retval;
97 krb5_data *packet = 0;
99 char k4_version; /* same type as *(krb5_data::data) */
104 if ((retval = krb5_timeofday(context, time_now)))
108 * XXX we know they are the same size... and we should do
109 * something better than just the current time
111 request->nonce = (krb5_int32) *time_now;
113 /* encode & send to KDC */
114 if ((retval = encode_krb5_as_req(request, &packet)) != 0)
117 k4_version = packet->data[0];
119 retval = krb5_sendto_kdc(context, packet,
120 krb5_princ_realm(context, request->client),
121 &reply, use_master, tcp_only);
125 /* now decode the reply...could be error or as_rep */
126 if (krb5_is_krb_error(&reply)) {
127 krb5_error *err_reply;
129 if ((retval = decode_krb5_error(&reply, &err_reply)))
130 /* some other error code--??? */
134 if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG
137 krb5_free_error(context, err_reply);
142 *ret_err_reply = err_reply;
144 krb5_free_error(context, err_reply);
149 * Check to make sure it isn't a V4 reply.
151 if (!krb5_is_as_rep(&reply)) {
152 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
153 #define V4_KRB_PROT_VERSION 4
154 #define V4_AUTH_MSG_ERR_REPLY (5<<1)
155 /* check here for V4 reply */
156 unsigned int t_switch;
158 /* From v4 g_in_tkt.c: This used to be
159 switch (pkt_msg_type(rpkt) & ~1) {
160 but SCO 3.2v4 cc compiled that incorrectly. */
161 t_switch = reply.data[1];
164 if (t_switch == V4_AUTH_MSG_ERR_REPLY
165 && (reply.data[0] == V4_KRB_PROT_VERSION
166 || reply.data[0] == k4_version)) {
167 retval = KRB5KRB_AP_ERR_V4_REPLY;
169 retval = KRB5KRB_AP_ERR_MSG_TYPE;
174 /* It must be a KRB_AS_REP message, or an bad returned packet */
175 if ((retval = decode_krb5_as_rep(&reply, &as_reply)))
176 /* some other error code ??? */
179 if (as_reply->msg_type != KRB5_AS_REP) {
180 retval = KRB5KRB_AP_ERR_MSG_TYPE;
181 krb5_free_kdc_rep(context, as_reply);
186 *ret_as_reply = as_reply;
188 krb5_free_kdc_rep(context, as_reply);
192 krb5_free_data(context, packet);
198 static krb5_error_code
199 decrypt_as_reply(krb5_context context,
200 krb5_kdc_req *request,
201 krb5_kdc_rep *as_reply,
202 git_key_proc key_proc,
203 krb5_const_pointer keyseed,
205 git_decrypt_proc decrypt_proc,
206 krb5_const_pointer decryptarg)
208 krb5_error_code retval;
209 krb5_keyblock * decrypt_key = 0;
212 if (as_reply->enc_part2)
218 if ((retval = krb5_principal2salt(context, request->client, &salt)))
221 retval = (*key_proc)(context, as_reply->enc_part.enctype,
222 &salt, keyseed, &decrypt_key);
223 krb5_xfree(salt.data);
228 if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply)))
232 if (!key && decrypt_key)
233 krb5_free_keyblock(context, decrypt_key);
237 static krb5_error_code
238 verify_as_reply(krb5_context context,
239 krb5_timestamp time_now,
240 krb5_kdc_req *request,
241 krb5_kdc_rep *as_reply)
243 krb5_error_code retval;
245 /* check the contents for sanity: */
246 if (!as_reply->enc_part2->times.starttime)
247 as_reply->enc_part2->times.starttime =
248 as_reply->enc_part2->times.authtime;
250 if (!krb5_principal_compare(context, as_reply->client, request->client)
251 || !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)
252 || !krb5_principal_compare(context, as_reply->ticket->server, request->server)
253 || (request->nonce != as_reply->enc_part2->nonce)
254 /* XXX check for extraneous flags */
255 /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
256 || ((request->kdc_options & KDC_OPT_POSTDATED) &&
257 (request->from != 0) &&
258 (request->from != as_reply->enc_part2->times.starttime))
259 || ((request->till != 0) &&
260 (as_reply->enc_part2->times.endtime > request->till))
261 || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
262 (request->rtime != 0) &&
263 (as_reply->enc_part2->times.renew_till > request->rtime))
264 || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
265 (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
266 (request->till != 0) &&
267 (as_reply->enc_part2->times.renew_till > request->till))
269 return KRB5_KDCREP_MODIFIED;
271 if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
272 retval = krb5_set_real_time(context,
273 as_reply->enc_part2->times.authtime, 0);
277 if ((request->from == 0) &&
278 (labs(as_reply->enc_part2->times.starttime - time_now)
279 > context->clockskew))
280 return (KRB5_KDCREP_SKEW);
285 static krb5_error_code
286 stash_as_reply(krb5_context context,
287 krb5_timestamp time_now,
288 krb5_kdc_req *request,
289 krb5_kdc_rep *as_reply,
293 krb5_error_code retval;
295 krb5_principal client;
296 krb5_principal server;
302 if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
306 if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
310 /* fill in the credentials */
311 if ((retval = krb5_copy_keyblock_contents(context,
312 as_reply->enc_part2->session,
316 creds->times = as_reply->enc_part2->times;
317 creds->is_skey = FALSE; /* this is an AS_REQ, so cannot
318 be encrypted in skey */
319 creds->ticket_flags = as_reply->enc_part2->flags;
320 if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
324 creds->second_ticket.length = 0;
325 creds->second_ticket.data = 0;
327 if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
330 creds->ticket = *packet;
333 /* store it in the ccache! */
335 if ((retval = krb5_cc_store_cred(context, ccache, creds)))
339 creds->client = client;
341 creds->server = server;
346 krb5_free_principal(context, client);
348 krb5_free_principal(context, server);
349 if (creds->keyblock.contents) {
350 memset((char *)creds->keyblock.contents, 0,
351 creds->keyblock.length);
352 krb5_xfree(creds->keyblock.contents);
353 creds->keyblock.contents = 0;
354 creds->keyblock.length = 0;
356 if (creds->ticket.data) {
357 krb5_xfree(creds->ticket.data);
358 creds->ticket.data = 0;
360 if (creds->addresses) {
361 krb5_free_addresses(context, creds->addresses);
362 creds->addresses = 0;
368 static krb5_error_code
369 make_preauth_list(krb5_context context,
370 krb5_preauthtype * ptypes,
372 krb5_pa_data *** ret_list)
374 krb5_preauthtype * ptypep;
375 krb5_pa_data ** preauthp;
379 for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
383 /* allocate space for a NULL to terminate the list */
386 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
389 for (i=0; i<nptypes; i++) {
391 (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
397 preauthp[i]->magic = KV5M_PA_DATA;
398 preauthp[i]->pa_type = ptypes[i];
399 preauthp[i]->length = 0;
400 preauthp[i]->contents = 0;
403 /* fill in the terminating NULL */
405 preauthp[nptypes] = NULL;
407 *ret_list = preauthp;
411 #define MAX_IN_TKT_LOOPS 16
413 krb5_error_code KRB5_CALLCONV
414 krb5_get_in_tkt(krb5_context context,
415 const krb5_flags options,
416 krb5_address * const * addrs,
417 krb5_enctype * ktypes,
418 krb5_preauthtype * ptypes,
419 git_key_proc key_proc,
420 krb5_const_pointer keyseed,
421 git_decrypt_proc decrypt_proc,
422 krb5_const_pointer decryptarg,
425 krb5_kdc_rep ** ret_as_reply)
427 krb5_error_code retval;
428 krb5_timestamp time_now;
429 krb5_keyblock * decrypt_key = 0;
430 krb5_kdc_req request;
431 krb5_pa_data **padata = 0;
432 krb5_error * err_reply;
433 krb5_kdc_rep * as_reply = 0;
434 krb5_pa_data ** preauth_to_use = 0;
436 krb5_int32 do_more = 0;
438 if (! krb5_realm_compare(context, creds->client, creds->server))
439 return KRB5_IN_TKT_REALM_MISMATCH;
445 * Set up the basic request structure
447 request.magic = KV5M_KDC_REQ;
448 request.msg_type = KRB5_AS_REQ;
449 request.addresses = 0;
453 request.addresses = (krb5_address **) addrs;
455 if ((retval = krb5_os_localaddr(context, &request.addresses)))
457 request.kdc_options = options;
458 request.client = creds->client;
459 request.server = creds->server;
460 request.from = creds->times.starttime;
461 request.till = creds->times.endtime;
462 request.rtime = creds->times.renew_till;
463 if ((retval = krb5_get_default_in_tkt_ktypes(context, &request.ktype)))
465 for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++);
467 int i, req, next = 0;
468 for (req = 0; ktypes[req]; req++) {
469 if (ktypes[req] == request.ktype[next]) {
473 for (i = next + 1; i < request.nktypes; i++)
474 if (ktypes[req] == request.ktype[i]) {
475 /* Found the enctype we want, but not in the
476 position we want. Move it, but keep the old
477 one from the desired slot around in case it's
478 later in our requested-ktypes list. */
480 t = request.ktype[next];
481 request.ktype[next] = request.ktype[i];
482 request.ktype[i] = t;
486 /* If we didn't find it, don't do anything special, just
489 request.ktype[next] = 0;
490 request.nktypes = next;
492 request.authorization_data.ciphertext.length = 0;
493 request.authorization_data.ciphertext.data = 0;
494 request.unenc_authdata = 0;
495 request.second_ticket = 0;
498 * If a list of preauth types are passed in, convert it to a
499 * preauth_to_use list.
502 retval = make_preauth_list(context, ptypes, -1, &preauth_to_use);
508 if (loopcount++ > MAX_IN_TKT_LOOPS) {
509 retval = KRB5_GET_IN_TKT_LOOP;
513 if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc,
514 keyseed, creds, &request)) != 0)
517 krb5_free_pa_data(context, preauth_to_use);
522 if ((retval = send_as_request(context, &request, &time_now, &err_reply,
527 if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
528 err_reply->e_data.length > 0) {
529 retval = decode_krb5_padata_sequence(&err_reply->e_data,
531 krb5_free_error(context, err_reply);
536 retval = (krb5_error_code) err_reply->error
537 + ERROR_TABLE_BASE_krb5;
538 krb5_free_error(context, err_reply);
541 } else if (!as_reply) {
542 retval = KRB5KRB_AP_ERR_MSG_TYPE;
545 if ((retval = krb5_process_padata(context, &request, as_reply,
546 key_proc, keyseed, decrypt_proc,
555 if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc,
556 keyseed, decrypt_key, decrypt_proc,
560 if ((retval = verify_as_reply(context, time_now, &request, as_reply)))
563 if ((retval = stash_as_reply(context, time_now, &request, as_reply,
570 if (!addrs && request.addresses)
571 krb5_free_addresses(context, request.addresses);
573 krb5_free_pa_data(context, request.padata);
575 krb5_free_pa_data(context, padata);
577 krb5_free_pa_data(context, preauth_to_use);
579 krb5_free_keyblock(context, decrypt_key);
582 *ret_as_reply = as_reply;
584 krb5_free_kdc_rep(context, as_reply);
589 /* begin libdefaults parsing code. This should almost certainly move
590 somewhere else, but I don't know where the correct somewhere else
593 /* XXX Duplicating this is annoying; try to work on a better way.*/
594 static const char *const conf_yes[] = {
595 "y", "yes", "true", "t", "1", "on",
599 static const char *const conf_no[] = {
600 "n", "no", "false", "nil", "0", "off",
605 _krb5_conf_boolean(const char *s)
607 const char *const *p;
609 for(p=conf_yes; *p; p++) {
610 if (!strcasecmp(*p,s))
614 for(p=conf_no; *p; p++) {
615 if (!strcasecmp(*p,s))
619 /* Default to "no" */
623 static krb5_error_code
624 krb5_libdefault_string(krb5_context context, const krb5_data *realm,
625 const char *option, char **ret_value)
628 const char *names[5];
629 char **nameval = NULL;
630 krb5_error_code retval;
633 if (realm->length > sizeof(realmstr)-1)
636 strncpy(realmstr, realm->data, realm->length);
637 realmstr[realm->length] = '\0';
639 if (!context || (context->magic != KV5M_CONTEXT))
642 profile = context->profile;
644 names[0] = "libdefaults";
658 retval = profile_get_values(profile, names, &nameval);
659 if (retval == 0 && nameval && nameval[0])
671 retval = profile_get_values(profile, names, &nameval);
672 if (retval == 0 && nameval && nameval[0])
682 *ret_value = malloc(strlen(nameval[0]) + 1);
686 strcpy(*ret_value, nameval[0]);
689 profile_free_list(nameval);
694 /* not static so verify_init_creds() can call it */
695 /* as well as the DNS code */
698 krb5_libdefault_boolean(krb5_context context, const krb5_data *realm,
699 const char *option, int *ret_value)
702 krb5_error_code retval;
704 retval = krb5_libdefault_string(context, realm, option, &string);
709 *ret_value = _krb5_conf_boolean(string);
715 krb5_error_code KRB5_CALLCONV
716 krb5_get_init_creds(krb5_context context,
718 krb5_principal client,
719 krb5_prompter_fct prompter,
721 krb5_deltat start_time,
722 char *in_tkt_service,
723 krb5_get_init_creds_opt *options,
724 krb5_gic_get_as_key_fct gak_fct,
727 krb5_kdc_rep **as_reply)
730 krb5_kdc_req request;
731 krb5_pa_data **padata;
734 krb5_deltat renew_life;
738 krb5_keyblock as_key;
739 krb5_error *err_reply;
740 krb5_kdc_rep *local_as_reply;
741 krb5_timestamp time_now;
742 krb5_enctype etype = 0;
744 /* initialize everything which will be freed at cleanup */
746 s2kparams.data = NULL;
747 s2kparams.length = 0;
748 request.server = NULL;
749 request.ktype = NULL;
750 request.addresses = NULL;
751 request.padata = NULL;
760 * Set up the basic request structure
762 request.magic = KV5M_KDC_REQ;
763 request.msg_type = KRB5_AS_REQ;
765 /* request.padata is filled in later */
767 request.kdc_options = 0;
771 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE))
772 tempint = options->forwardable;
773 else if ((ret = krb5_libdefault_boolean(context, &client->realm,
774 "forwardable", &tempint)) == 0)
779 request.kdc_options |= KDC_OPT_FORWARDABLE;
783 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE))
784 tempint = options->proxiable;
785 else if ((ret = krb5_libdefault_boolean(context, &client->realm,
786 "proxiable", &tempint)) == 0)
791 request.kdc_options |= KDC_OPT_PROXIABLE;
795 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
796 renew_life = options->renew_life;
797 } else if ((ret = krb5_libdefault_string(context, &client->realm,
798 "renew_lifetime", &tempstr))
800 if ((ret = krb5_string_to_deltat(tempstr, &renew_life))) {
808 request.kdc_options |= KDC_OPT_RENEWABLE;
813 request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED);
817 request.client = client;
819 if (in_tkt_service) {
820 /* this is ugly, because so are the data structures involved. I'm
821 in the library, so I'm going to manipulate the data structures
822 directly, otherwise, it will be worse. */
824 if ((ret = krb5_parse_name(context, in_tkt_service, &request.server)))
827 /* stuff the client realm into the server principal.
828 realloc if necessary */
829 if (request.server->realm.length < request.client->realm.length)
830 if ((request.server->realm.data =
831 (char *) realloc(request.server->realm.data,
832 request.client->realm.length)) == NULL) {
837 request.server->realm.length = request.client->realm.length;
838 memcpy(request.server->realm.data, request.client->realm.data,
839 request.client->realm.length);
841 if ((ret = krb5_build_principal_ext(context, &request.server,
842 request.client->realm.length,
843 request.client->realm.data,
846 request.client->realm.length,
847 request.client->realm.data,
852 if ((ret = krb5_timeofday(context, &request.from)))
854 request.from += start_time;
856 request.till = request.from;
857 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE))
858 request.till += options->tkt_life;
860 request.till += 10*60*60; /* this used to be hardcoded in kinit.c */
862 if (renew_life > 0) {
863 request.rtime = request.from;
864 request.rtime += renew_life;
869 /* nonce is filled in by send_as_request */
871 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) {
872 request.ktype = options->etype_list;
873 request.nktypes = options->etype_list_length;
874 } else if ((ret = krb5_get_default_in_tkt_ktypes(context,
875 &request.ktype)) == 0) {
876 for (request.nktypes = 0;
877 request.ktype[request.nktypes];
881 /* there isn't any useful default here. ret is set from above */
885 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) {
886 request.addresses = options->address_list;
888 /* it would be nice if this parsed out an address list, but
889 that would be work. */
890 else if (((ret = krb5_libdefault_boolean(context, &client->realm,
891 "noaddresses", &tempint)) != 0)
895 if ((ret = krb5_os_localaddr(context, &request.addresses)))
899 request.authorization_data.ciphertext.length = 0;
900 request.authorization_data.ciphertext.data = 0;
901 request.unenc_authdata = 0;
902 request.second_ticket = 0;
904 /* set up the other state. */
906 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
907 if ((ret = make_preauth_list(context, options->preauth_list,
908 options->preauth_list_length,
913 /* the salt is allocated from somewhere, unless it is from the caller,
914 then it is a reference */
916 if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) {
917 salt = *options->salt;
919 salt.length = SALT_TYPE_AFS_LENGTH;
923 /* now, loop processing preauth data and talking to the kdc */
925 for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) {
926 if (request.padata) {
927 krb5_free_pa_data(context, request.padata);
928 request.padata = NULL;
931 if ((ret = krb5_do_preauth(context, &request,
932 padata, &request.padata,
933 &salt, &s2kparams, &etype, &as_key, prompter,
934 prompter_data, gak_fct, gak_data)))
938 krb5_free_pa_data(context, padata);
944 if ((ret = send_as_request(context, &request, &time_now, &err_reply,
945 &local_as_reply, use_master)))
949 if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
950 err_reply->e_data.length > 0) {
951 ret = decode_krb5_padata_sequence(&err_reply->e_data,
953 krb5_free_error(context, err_reply);
957 ret = (krb5_error_code) err_reply->error
958 + ERROR_TABLE_BASE_krb5;
959 krb5_free_error(context, err_reply);
962 } else if (local_as_reply) {
965 ret = KRB5KRB_AP_ERR_MSG_TYPE;
970 if (loopcount == MAX_IN_TKT_LOOPS) {
971 ret = KRB5_GET_IN_TKT_LOOP;
975 /* process any preauth data in the as_reply */
977 if ((ret = krb5_do_preauth(context, &request,
978 local_as_reply->padata, &padata,
979 &salt, &s2kparams, &etype, &as_key, prompter,
980 prompter_data, gak_fct, gak_data)))
983 /* XXX if there's padata on output, something is wrong, but it's
984 not obviously an error */
986 /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
987 the AS_REP comes back encrypted in the user's longterm key
988 instead of in the SAD. If there was a SAM preauth, there
989 will be an as_key here which will be the SAD. If that fails,
990 use the gak_fct to get the password, and try again. */
992 /* XXX because etypes are handled poorly (particularly wrt SAM,
993 where the etype is fixed by the kdc), we may want to try
994 decrypt_as_reply twice. If there's an as_key available, try
995 it. If decrypting the as_rep fails, or if there isn't an
996 as_key at all yet, then use the gak_fct to get one, and try
1000 ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1001 NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1007 /* if we haven't get gotten a key, get it now */
1009 if ((ret = ((*gak_fct)(context, request.client,
1010 local_as_reply->enc_part.enctype,
1011 prompter, prompter_data, &salt, &s2kparams,
1012 &as_key, gak_data))))
1015 if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1016 NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1021 if ((ret = verify_as_reply(context, time_now, &request, local_as_reply)))
1024 /* XXX this should be inside stash_as_reply, but as long as
1025 get_in_tkt is still around using that arg as an in/out, I can't
1027 memset(creds, 0, sizeof(*creds));
1029 if ((ret = stash_as_reply(context, time_now, &request, local_as_reply,
1039 krb5_free_principal(context, request.server);
1040 if (request.ktype &&
1041 (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))))
1042 free(request.ktype);
1043 if (request.addresses &&
1045 (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST))))
1046 krb5_free_addresses(context, request.addresses);
1048 krb5_free_pa_data(context, padata);
1050 krb5_free_pa_data(context, request.padata);
1052 krb5_free_keyblock_contents(context, &as_key);
1054 (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT))))
1055 krb5_xfree(salt.data);
1057 *as_reply = local_as_reply;
1058 else if (local_as_reply)
1059 krb5_free_kdc_rep(context, local_as_reply);