1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * lib/krb5/krb/get_in_tkt.c
5 * Copyright 1990,1991, 2003, 2008 by the Massachusetts Institute of Technology.
8 * Export of this software from the United States of America may
9 * require a specific license from the United States Government.
10 * It is the responsibility of any person or organization contemplating
11 * export to obtain such a license before exporting.
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission. Furthermore if you modify this software you must label
21 * your software as modified software and not distribute it in such a
22 * fashion that it might be confused with the original M.I.T. software.
23 * M.I.T. makes no representations about the suitability of
24 * this software for any purpose. It is provided "as is" without express
25 * or implied warranty.
34 #include "int-proto.h"
37 #include "init_creds_ctx.h"
40 #define IN_TKT_DEBUG 0
42 #define inTktDebug(args...) printf(args)
44 #define inTktDebug(args...)
46 #endif /* APPLE_PKINIT */
49 All-purpose initial ticket routine, usually called via
50 krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey.
52 Attempts to get an initial ticket for creds->client to use server
53 creds->server, (realm is taken from creds->client), with options
54 options, and using creds->times.starttime, creds->times.endtime,
55 creds->times.renew_till as from, till, and rtime.
56 creds->times.renew_till is ignored unless the RENEWABLE option is requested.
58 key_proc is called to fill in the key to be used for decryption.
59 keyseed is passed on to key_proc.
61 decrypt_proc is called to perform the decryption of the response (the
62 encrypted part is in dec_rep->enc_part; the decrypted part should be
63 allocated and filled into dec_rep->enc_part2
64 arg is passed on to decrypt_proc.
66 If addrs is non-NULL, it is used for the addresses requested. If it is
67 null, the system standard addresses are used.
69 A succesful call will place the ticket in the credentials cache ccache
70 and fill in creds with the ticket information used/returned..
72 returns system errors, encryption errors
77 /* some typedef's for the function args to make things look a bit cleaner */
79 typedef krb5_error_code (*git_key_proc) (krb5_context,
85 typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
86 const krb5_keyblock *,
90 static krb5_error_code make_preauth_list (krb5_context,
92 int, krb5_pa_data ***);
93 static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
95 krb5_pa_data **padata);
98 * This function performs 32 bit bounded addition so we can generate
99 * lifetimes without overflowing krb5_int32
102 krb5int_addint32 (krb5_int32 x, krb5_int32 y)
104 if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
105 /* sum will be be greater than KRB5_INT32_MAX */
106 return KRB5_INT32_MAX;
107 } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
108 /* sum will be less than KRB5_INT32_MIN */
109 return KRB5_INT32_MIN;
117 * Common code to generate krb5_kdc_req.nonce. Like the original MIT code this
118 * just uses krb5_timeofday(); it should use a PRNG. Even more unfortunately this
119 * value is used interchangeably with an explicit now_time throughout this module...
121 static krb5_error_code
122 gen_nonce(krb5_context context,
126 krb5_error_code retval = krb5_timeofday(context, &time_now);
133 #endif /* APPLE_PKINIT */
136 * This function sends a request to the KDC, and gets back a response;
137 * the response is parsed into ret_err_reply or ret_as_reply if the
138 * reponse is a KRB_ERROR or a KRB_AS_REP packet. If it is some other
139 * unexpected response, an error is returned.
141 static krb5_error_code
142 send_as_request(krb5_context context,
143 krb5_data *packet, const krb5_data *realm,
144 krb5_error ** ret_err_reply,
145 krb5_kdc_rep ** ret_as_reply,
148 krb5_kdc_rep *as_reply = 0;
149 krb5_error_code retval;
151 char k4_version; /* same type as *(krb5_data::data) */
156 /* set the nonce if the caller expects us to do it */
158 k4_version = packet->data[0];
160 retval = krb5_sendto_kdc(context, packet,
162 &reply, use_master, tcp_only);
164 inTktDebug("krb5_sendto_kdc returned %d\n", (int)retval);
165 #endif /* APPLE_PKINIT */
170 /* now decode the reply...could be error or as_rep */
171 if (krb5_is_krb_error(&reply)) {
172 krb5_error *err_reply;
174 if ((retval = decode_krb5_error(&reply, &err_reply)))
175 /* some other error code--??? */
179 if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG
182 krb5_free_error(context, err_reply);
187 *ret_err_reply = err_reply;
189 krb5_free_error(context, err_reply);
194 * Check to make sure it isn't a V4 reply.
196 if (!krb5_is_as_rep(&reply)) {
197 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
198 #define V4_KRB_PROT_VERSION 4
199 #define V4_AUTH_MSG_ERR_REPLY (5<<1)
200 /* check here for V4 reply */
201 unsigned int t_switch;
203 /* From v4 g_in_tkt.c: This used to be
204 switch (pkt_msg_type(rpkt) & ~1) {
205 but SCO 3.2v4 cc compiled that incorrectly. */
206 t_switch = reply.data[1];
209 if (t_switch == V4_AUTH_MSG_ERR_REPLY
210 && (reply.data[0] == V4_KRB_PROT_VERSION
211 || reply.data[0] == k4_version)) {
212 retval = KRB5KRB_AP_ERR_V4_REPLY;
214 retval = KRB5KRB_AP_ERR_MSG_TYPE;
219 /* It must be a KRB_AS_REP message, or an bad returned packet */
220 if ((retval = decode_krb5_as_rep(&reply, &as_reply)))
221 /* some other error code ??? */
224 if (as_reply->msg_type != KRB5_AS_REP) {
225 retval = KRB5KRB_AP_ERR_MSG_TYPE;
226 krb5_free_kdc_rep(context, as_reply);
231 *ret_as_reply = as_reply;
233 krb5_free_kdc_rep(context, as_reply);
241 static krb5_error_code
242 decrypt_as_reply(krb5_context context,
243 krb5_kdc_req *request,
244 krb5_kdc_rep *as_reply,
245 git_key_proc key_proc,
246 krb5_const_pointer keyseed,
248 git_decrypt_proc decrypt_proc,
249 krb5_const_pointer decryptarg)
251 krb5_error_code retval;
252 krb5_keyblock * decrypt_key = 0;
255 if (as_reply->enc_part2)
262 * Use salt corresponding to the client principal supplied by
263 * the KDC, which may differ from the requested principal if
264 * canonicalization is in effect. We will check
265 * as_reply->client later in verify_as_reply.
267 if ((retval = krb5_principal2salt(context, as_reply->client, &salt)))
270 retval = (*key_proc)(context, as_reply->enc_part.enctype,
271 &salt, keyseed, &decrypt_key);
277 if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply)))
281 if (!key && decrypt_key)
282 krb5_free_keyblock(context, decrypt_key);
286 static krb5_error_code
287 verify_as_reply(krb5_context context,
288 krb5_timestamp time_now,
289 krb5_kdc_req *request,
290 krb5_kdc_rep *as_reply)
292 krb5_error_code retval;
296 /* check the contents for sanity: */
297 if (!as_reply->enc_part2->times.starttime)
298 as_reply->enc_part2->times.starttime =
299 as_reply->enc_part2->times.authtime;
302 * We only allow the AS-REP server name to be changed if the
303 * caller set the canonicalize flag (or requested an enterprise
304 * principal) and we requested (and received) a TGT.
306 canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
307 (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL);
309 canon_ok = IS_TGS_PRINC(context, request->server) &&
310 IS_TGS_PRINC(context, as_reply->enc_part2->server);
315 (!krb5_principal_compare(context, as_reply->client, request->client) ||
316 !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)))
317 || !krb5_principal_compare(context, as_reply->enc_part2->server, as_reply->ticket->server)
318 || (request->nonce != as_reply->enc_part2->nonce)
319 /* XXX check for extraneous flags */
320 /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
321 || ((request->kdc_options & KDC_OPT_POSTDATED) &&
322 (request->from != 0) &&
323 (request->from != as_reply->enc_part2->times.starttime))
324 || ((request->till != 0) &&
325 (as_reply->enc_part2->times.endtime > request->till))
326 || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
327 (request->rtime != 0) &&
328 (as_reply->enc_part2->times.renew_till > request->rtime))
329 || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
330 !(request->kdc_options & KDC_OPT_RENEWABLE) &&
331 (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
332 (request->till != 0) &&
333 (as_reply->enc_part2->times.renew_till > request->till))
336 inTktDebug("verify_as_reply: KDCREP_MODIFIED\n");
338 if(request->client->realm.length && request->client->data->length)
339 inTktDebug("request: name %s realm %s\n",
340 request->client->realm.data, request->client->data->data);
341 if(as_reply->client->realm.length && as_reply->client->data->length)
342 inTktDebug("reply : name %s realm %s\n",
343 as_reply->client->realm.data, as_reply->client->data->data);
345 #endif /* APPLE_PKINIT */
346 return KRB5_KDCREP_MODIFIED;
349 if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
350 retval = krb5_set_real_time(context,
351 as_reply->enc_part2->times.authtime, -1);
355 if ((request->from == 0) &&
356 (labs(as_reply->enc_part2->times.starttime - time_now)
357 > context->clockskew))
358 return (KRB5_KDCREP_SKEW);
363 static krb5_error_code
364 stash_as_reply(krb5_context context,
365 krb5_timestamp time_now,
366 krb5_kdc_req *request,
367 krb5_kdc_rep *as_reply,
371 krb5_error_code retval;
373 krb5_principal client;
374 krb5_principal server;
380 if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
384 if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
388 /* fill in the credentials */
389 if ((retval = krb5_copy_keyblock_contents(context,
390 as_reply->enc_part2->session,
394 creds->times = as_reply->enc_part2->times;
395 creds->is_skey = FALSE; /* this is an AS_REQ, so cannot
396 be encrypted in skey */
397 creds->ticket_flags = as_reply->enc_part2->flags;
398 if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
402 creds->second_ticket.length = 0;
403 creds->second_ticket.data = 0;
405 if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
408 creds->ticket = *packet;
411 /* store it in the ccache! */
413 if ((retval = krb5_cc_store_cred(context, ccache, creds)))
417 creds->client = client;
419 creds->server = server;
424 krb5_free_principal(context, client);
426 krb5_free_principal(context, server);
427 if (creds->keyblock.contents) {
428 memset(creds->keyblock.contents, 0,
429 creds->keyblock.length);
430 free(creds->keyblock.contents);
431 creds->keyblock.contents = 0;
432 creds->keyblock.length = 0;
434 if (creds->ticket.data) {
435 free(creds->ticket.data);
436 creds->ticket.data = 0;
438 if (creds->addresses) {
439 krb5_free_addresses(context, creds->addresses);
440 creds->addresses = 0;
446 static krb5_error_code
447 make_preauth_list(krb5_context context,
448 krb5_preauthtype * ptypes,
450 krb5_pa_data *** ret_list)
452 krb5_preauthtype * ptypep;
453 krb5_pa_data ** preauthp;
457 for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
461 /* allocate space for a NULL to terminate the list */
464 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
467 for (i=0; i<nptypes; i++) {
469 (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
475 preauthp[i]->magic = KV5M_PA_DATA;
476 preauthp[i]->pa_type = ptypes[i];
477 preauthp[i]->length = 0;
478 preauthp[i]->contents = 0;
481 /* fill in the terminating NULL */
483 preauthp[nptypes] = NULL;
485 *ret_list = preauthp;
489 #define MAX_IN_TKT_LOOPS 16
490 static const krb5_enctype get_in_tkt_enctypes[] = {
491 ENCTYPE_DES3_CBC_SHA1,
492 ENCTYPE_ARCFOUR_HMAC,
499 static krb5_error_code
500 rewrite_server_realm(krb5_context context,
501 krb5_const_principal old_server,
502 const krb5_data *realm,
504 krb5_principal *server)
506 krb5_error_code retval;
508 assert(*server == NULL);
510 retval = krb5_copy_principal(context, old_server, server);
514 krb5_free_data_contents(context, &(*server)->realm);
515 (*server)->realm.data = NULL;
517 retval = krb5int_copy_data_contents(context, realm, &(*server)->realm);
522 krb5_free_data_contents(context, &(*server)->data[1]);
523 (*server)->data[1].data = NULL;
525 retval = krb5int_copy_data_contents(context, realm, &(*server)->data[1]);
532 krb5_free_principal(context, *server);
540 tgt_is_local_realm(krb5_creds *tgt)
542 return (tgt->server->length == 2
543 && data_eq_string(tgt->server->data[0], KRB5_TGS_NAME)
544 && data_eq(tgt->server->data[1], tgt->client->realm)
545 && data_eq(tgt->server->realm, tgt->client->realm));
548 krb5_error_code KRB5_CALLCONV
549 krb5_get_in_tkt(krb5_context context,
551 krb5_address * const * addrs,
552 krb5_enctype * ktypes,
553 krb5_preauthtype * ptypes,
554 git_key_proc key_proc,
555 krb5_const_pointer keyseed,
556 git_decrypt_proc decrypt_proc,
557 krb5_const_pointer decryptarg,
560 krb5_kdc_rep ** ret_as_reply)
562 krb5_error_code retval;
563 krb5_timestamp time_now;
564 krb5_keyblock * decrypt_key = 0;
565 krb5_kdc_req request;
566 krb5_data *encoded_request;
567 krb5_error * err_reply;
568 krb5_kdc_rep * as_reply = 0;
569 krb5_pa_data ** preauth_to_use = 0;
571 krb5_int32 do_more = 0;
574 int referral_count = 0;
575 krb5_principal_data referred_client;
576 krb5_principal referred_server = NULL;
577 krb5_boolean is_tgt_req;
580 inTktDebug("krb5_get_in_tkt top\n");
581 #endif /* APPLE_PKINIT */
583 if (! krb5_realm_compare(context, creds->client, creds->server))
584 return KRB5_IN_TKT_REALM_MISMATCH;
589 referred_client = *(creds->client);
590 referred_client.realm.data = NULL;
591 referred_client.realm.length = 0;
593 /* per referrals draft, enterprise principals imply canonicalization */
594 canon_flag = ((options & KDC_OPT_CANONICALIZE) != 0) ||
595 creds->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
598 * Set up the basic request structure
600 request.magic = KV5M_KDC_REQ;
601 request.msg_type = KRB5_AS_REQ;
602 request.addresses = 0;
606 request.addresses = (krb5_address **) addrs;
608 if ((retval = krb5_os_localaddr(context, &request.addresses)))
610 request.kdc_options = options;
611 request.client = creds->client;
612 request.server = creds->server;
614 request.from = creds->times.starttime;
615 request.till = creds->times.endtime;
616 request.rtime = creds->times.renew_till;
618 retval = gen_nonce(context, (krb5_int32 *)&time_now);
622 request.nonce = time_now;
623 #endif /* APPLE_PKINIT */
625 request.ktype = malloc (sizeof(get_in_tkt_enctypes));
626 if (request.ktype == NULL) {
630 memcpy(request.ktype, get_in_tkt_enctypes, sizeof(get_in_tkt_enctypes));
631 for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++);
633 int i, req, next = 0;
634 for (req = 0; ktypes[req]; req++) {
635 if (ktypes[req] == request.ktype[next]) {
639 for (i = next + 1; i < request.nktypes; i++)
640 if (ktypes[req] == request.ktype[i]) {
641 /* Found the enctype we want, but not in the
642 position we want. Move it, but keep the old
643 one from the desired slot around in case it's
644 later in our requested-ktypes list. */
646 t = request.ktype[next];
647 request.ktype[next] = request.ktype[i];
648 request.ktype[i] = t;
652 /* If we didn't find it, don't do anything special, just
655 request.ktype[next] = 0;
656 request.nktypes = next;
658 request.authorization_data.ciphertext.length = 0;
659 request.authorization_data.ciphertext.data = 0;
660 request.unenc_authdata = 0;
661 request.second_ticket = 0;
664 * If a list of preauth types are passed in, convert it to a
665 * preauth_to_use list.
668 retval = make_preauth_list(context, ptypes, -1, &preauth_to_use);
673 is_tgt_req = tgt_is_local_realm(creds);
676 if (loopcount++ > MAX_IN_TKT_LOOPS) {
677 retval = KRB5_GET_IN_TKT_LOOP;
682 inTktDebug("krb5_get_in_tkt calling krb5_obtain_padata\n");
683 #endif /* APPLE_PKINIT */
684 if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc,
685 keyseed, creds, &request)) != 0)
688 krb5_free_pa_data(context, preauth_to_use);
694 if ((retval = krb5_timeofday(context, &time_now)))
698 * XXX we know they are the same size... and we should do
699 * something better than just the current time
701 request.nonce = (krb5_int32) time_now;
703 if ((retval = encode_krb5_as_req(&request, &encoded_request)) != 0)
705 retval = send_as_request(context, encoded_request,
706 krb5_princ_realm(context, request.client), &err_reply,
707 &as_reply, &use_master);
708 krb5_free_data(context, encoded_request);
713 if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
714 err_reply->e_data.length > 0) {
715 retval = decode_krb5_padata_sequence(&err_reply->e_data,
717 krb5_free_error(context, err_reply);
720 retval = sort_krb5_padata_sequence(context,
721 &request.server->realm,
726 } else if (canon_flag && err_reply->error == KDC_ERR_WRONG_REALM) {
727 if (++referral_count > KRB5_REFERRAL_MAXHOPS ||
728 err_reply->client == NULL ||
729 err_reply->client->realm.length == 0) {
730 retval = KRB5KDC_ERR_WRONG_REALM;
731 krb5_free_error(context, err_reply);
734 /* Rewrite request.client with realm from error reply */
735 if (referred_client.realm.data) {
736 krb5_free_data_contents(context, &referred_client.realm);
737 referred_client.realm.data = NULL;
739 retval = krb5int_copy_data_contents(context,
740 &err_reply->client->realm,
741 &referred_client.realm);
742 krb5_free_error(context, err_reply);
745 request.client = &referred_client;
747 if (referred_server != NULL) {
748 krb5_free_principal(context, referred_server);
749 referred_server = NULL;
752 retval = rewrite_server_realm(context,
754 &referred_client.realm,
759 request.server = referred_server;
763 retval = (krb5_error_code) err_reply->error
764 + ERROR_TABLE_BASE_krb5;
765 krb5_free_error(context, err_reply);
768 } else if (!as_reply) {
769 retval = KRB5KRB_AP_ERR_MSG_TYPE;
772 if ((retval = krb5_process_padata(context, &request, as_reply,
773 key_proc, keyseed, decrypt_proc,
782 if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc,
783 keyseed, decrypt_key, decrypt_proc,
787 if ((retval = verify_as_reply(context, time_now, &request, as_reply)))
790 if ((retval = stash_as_reply(context, time_now, &request, as_reply,
797 if (!addrs && request.addresses)
798 krb5_free_addresses(context, request.addresses);
800 krb5_free_pa_data(context, request.padata);
802 krb5_free_pa_data(context, preauth_to_use);
804 krb5_free_keyblock(context, decrypt_key);
807 *ret_as_reply = as_reply;
809 krb5_free_kdc_rep(context, as_reply);
811 if (referred_client.realm.data)
812 krb5_free_data_contents(context, &referred_client.realm);
814 krb5_free_principal(context, referred_server);
818 /* begin libdefaults parsing code. This should almost certainly move
819 somewhere else, but I don't know where the correct somewhere else
822 /* XXX Duplicating this is annoying; try to work on a better way.*/
823 static const char *const conf_yes[] = {
824 "y", "yes", "true", "t", "1", "on",
828 static const char *const conf_no[] = {
829 "n", "no", "false", "nil", "0", "off",
834 _krb5_conf_boolean(const char *s)
836 const char *const *p;
838 for(p=conf_yes; *p; p++) {
839 if (!strcasecmp(*p,s))
843 for(p=conf_no; *p; p++) {
844 if (!strcasecmp(*p,s))
848 /* Default to "no" */
852 static krb5_error_code
853 krb5_libdefault_string(krb5_context context, const krb5_data *realm,
854 const char *option, char **ret_value)
857 const char *names[5];
858 char **nameval = NULL;
859 krb5_error_code retval;
862 if (realm->length > sizeof(realmstr)-1)
865 strncpy(realmstr, realm->data, realm->length);
866 realmstr[realm->length] = '\0';
868 if (!context || (context->magic != KV5M_CONTEXT))
871 profile = context->profile;
873 names[0] = KRB5_CONF_LIBDEFAULTS;
887 retval = profile_get_values(profile, names, &nameval);
888 if (retval == 0 && nameval && nameval[0])
900 retval = profile_get_values(profile, names, &nameval);
901 if (retval == 0 && nameval && nameval[0])
911 *ret_value = strdup(nameval[0]);
916 profile_free_list(nameval);
921 /* not static so verify_init_creds() can call it */
922 /* as well as the DNS code */
925 krb5_libdefault_boolean(krb5_context context, const krb5_data *realm,
926 const char *option, int *ret_value)
929 krb5_error_code retval;
931 retval = krb5_libdefault_string(context, realm, option, &string);
936 *ret_value = _krb5_conf_boolean(string);
942 /* Sort a pa_data sequence so that types named in the "preferred_preauth_types"
943 * libdefaults entry are listed before any others. */
944 static krb5_error_code
945 sort_krb5_padata_sequence(krb5_context context, krb5_data *realm,
946 krb5_pa_data **padata)
952 char *q, *preauth_types = NULL;
954 int need_free_string = 1;
956 if ((padata == NULL) || (padata[0] == NULL)) {
960 ret = krb5_libdefault_string(context, realm, KRB5_CONF_PREFERRED_PREAUTH_TYPES,
962 if ((ret != 0) || (preauth_types == NULL)) {
963 /* Try to use PKINIT first. */
964 preauth_types = "17, 16, 15, 14";
965 need_free_string = 0;
969 fprintf (stderr, "preauth data types before sorting:");
970 for (i = 0; padata[i]; i++) {
971 fprintf (stderr, " %d", padata[i]->pa_type);
973 fprintf (stderr, "\n");
977 for (p = preauth_types; *p != '\0';) {
978 /* skip whitespace to find an entry */
979 p += strspn(p, ", ");
981 /* see if we can extract a number */
982 l = strtol(p, &q, 10);
983 if ((q != NULL) && (q > p)) {
984 /* got a valid number; search for a matchin entry */
985 for (i = base; padata[i] != NULL; i++) {
986 /* bubble the matching entry to the front of the list */
987 if (padata[i]->pa_type == l) {
989 for (j = i; j > base; j--)
990 padata[j] = padata[j - 1];
1002 if (need_free_string)
1003 free(preauth_types);
1006 fprintf (stderr, "preauth data types after sorting:");
1007 for (i = 0; padata[i]; i++)
1008 fprintf (stderr, " %d", padata[i]->pa_type);
1009 fprintf (stderr, "\n");
1015 static krb5_error_code
1016 build_in_tkt_name(krb5_context context,
1017 char *in_tkt_service,
1018 krb5_const_principal client,
1019 krb5_principal *server)
1021 krb5_error_code ret;
1025 if (in_tkt_service) {
1026 /* this is ugly, because so are the data structures involved. I'm
1027 in the library, so I'm going to manipulate the data structures
1028 directly, otherwise, it will be worse. */
1030 if ((ret = krb5_parse_name(context, in_tkt_service, server)))
1033 /* stuff the client realm into the server principal.
1034 realloc if necessary */
1035 if ((*server)->realm.length < client->realm.length) {
1036 char *p = realloc((*server)->realm.data,
1037 client->realm.length);
1039 krb5_free_principal(context, *server);
1043 (*server)->realm.data = p;
1046 (*server)->realm.length = client->realm.length;
1047 memcpy((*server)->realm.data, client->realm.data, client->realm.length);
1049 ret = krb5_build_principal_ext(context, server,
1050 client->realm.length,
1054 client->realm.length,
1062 krb5_init_creds_free(krb5_context context,
1063 krb5_init_creds_context ctx)
1068 if (ctx->opte != NULL && krb5_gic_opt_is_shadowed(ctx->opte)) {
1069 krb5_get_init_creds_opt_free(context,
1070 (krb5_get_init_creds_opt *)ctx->opte);
1072 free(ctx->in_tkt_service);
1073 zap(ctx->password.data, ctx->password.length);
1074 krb5_free_data_contents(context, &ctx->password);
1075 krb5_free_error(context, ctx->err_reply);
1076 krb5_free_cred_contents(context, &ctx->cred);
1077 krb5_free_kdc_req(context, ctx->request);
1078 krb5_free_kdc_rep(context, ctx->reply);
1079 krb5_free_data(context, ctx->encoded_request_body);
1080 krb5_free_data(context, ctx->encoded_previous_request);
1081 krb5int_fast_free_state(context, ctx->fast_state);
1082 krb5_free_pa_data(context, ctx->preauth_to_use);
1083 krb5_free_data_contents(context, &ctx->salt);
1084 krb5_free_data_contents(context, &ctx->s2kparams);
1085 krb5_free_keyblock_contents(context, &ctx->as_key);
1089 static krb5_error_code
1090 init_creds_get(krb5_context context,
1091 krb5_init_creds_context ctx,
1094 krb5_error_code code;
1098 unsigned int flags = 0;
1102 request.data = NULL;
1109 code = krb5_init_creds_step(context,
1115 if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !tcp_only)
1117 else if (code != 0 || (flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE))
1120 krb5_free_data_contents(context, &reply);
1122 code = krb5_sendto_kdc(context, &request, &realm,
1123 &reply, use_master, tcp_only);
1127 krb5_free_data_contents(context, &request);
1128 krb5_free_data_contents(context, &realm);
1131 krb5_free_data_contents(context, &request);
1132 krb5_free_data_contents(context, &reply);
1133 krb5_free_data_contents(context, &realm);
1139 krb5_error_code KRB5_CALLCONV
1140 krb5_init_creds_get(krb5_context context,
1141 krb5_init_creds_context ctx)
1145 return init_creds_get(context, ctx, &use_master);
1148 krb5_error_code KRB5_CALLCONV
1149 krb5_init_creds_get_creds(krb5_context context,
1150 krb5_init_creds_context ctx,
1153 if ((ctx->flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE) == 0)
1154 return KRB5_NO_TKT_SUPPLIED;
1156 return krb5int_copy_creds_contents(context, &ctx->cred, creds);
1159 krb5_error_code KRB5_CALLCONV
1160 krb5_init_creds_store_creds(krb5_context context,
1161 krb5_init_creds_context ctx,
1164 if ((ctx->flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE) == 0)
1165 return KRB5_NO_TKT_SUPPLIED;
1167 return krb5_cc_store_cred(context, ccache, &ctx->cred);
1170 krb5_error_code KRB5_CALLCONV
1171 krb5_init_creds_get_times(krb5_context context,
1172 krb5_init_creds_context ctx,
1173 krb5_ticket_times *times)
1175 if ((ctx->flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE) == 0)
1176 return KRB5_NO_TKT_SUPPLIED;
1178 *times = ctx->cred.times;
1183 krb5_error_code KRB5_CALLCONV
1184 krb5_init_creds_get_error(krb5_context context,
1185 krb5_init_creds_context ctx,
1188 krb5_error_code code;
1189 krb5_error *ret = NULL;
1193 if (ctx->err_reply == NULL)
1196 ret = k5alloc(sizeof(*ret), &code);
1200 ret->magic = KV5M_ERROR;
1201 ret->ctime = ctx->err_reply->ctime;
1202 ret->cusec = ctx->err_reply->cusec;
1203 ret->susec = ctx->err_reply->susec;
1204 ret->stime = ctx->err_reply->stime;
1205 ret->error = ctx->err_reply->error;
1207 if (ctx->err_reply->client != NULL) {
1208 code = krb5_copy_principal(context, ctx->err_reply->client,
1214 code = krb5_copy_principal(context, ctx->err_reply->server, &ret->server);
1218 code = krb5int_copy_data_contents(context, &ctx->err_reply->text,
1223 code = krb5int_copy_data_contents(context, &ctx->err_reply->e_data,
1232 krb5_free_error(context, ret);
1237 krb5_error_code KRB5_CALLCONV
1238 krb5_init_creds_init(krb5_context context,
1239 krb5_principal client,
1240 krb5_prompter_fct prompter,
1242 krb5_deltat start_time,
1243 krb5_get_init_creds_opt *options,
1244 krb5_init_creds_context *pctx)
1246 krb5_error_code code;
1247 krb5_init_creds_context ctx;
1250 krb5_gic_opt_ext *opte;
1252 ctx = k5alloc(sizeof(*ctx), &code);
1256 ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
1260 code = krb5_copy_principal(context, client, &ctx->request->client);
1264 ctx->prompter = prompter;
1265 ctx->prompter_data = data;
1266 ctx->gak_fct = krb5_get_as_key_password;
1267 ctx->gak_data = &ctx->password;
1269 ctx->request_time = 0; /* filled in later */
1270 ctx->start_time = start_time;
1272 if (options == NULL) {
1273 code = krb5_get_init_creds_opt_alloc(context, &options);
1278 code = krb5int_gic_opt_to_opte(context, options,
1279 &ctx->opte, 1, "krb5_init_creds_init");
1285 code = krb5int_fast_make_state(context, &ctx->fast_state);
1289 ctx->get_data_rock.magic = CLIENT_ROCK_MAGIC;
1290 ctx->get_data_rock.etype = &ctx->etype;
1291 ctx->get_data_rock.fast_state = ctx->fast_state;
1293 /* Initialise request parameters as per krb5_get_init_creds() */
1294 ctx->request->kdc_options = context->kdc_default_options;
1297 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
1298 tmp = opte->forwardable;
1299 else if (krb5_libdefault_boolean(context, &ctx->request->client->realm,
1300 KRB5_CONF_FORWARDABLE, &tmp) == 0)
1305 ctx->request->kdc_options |= KDC_OPT_FORWARDABLE;
1308 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
1309 tmp = opte->proxiable;
1310 else if (krb5_libdefault_boolean(context, &ctx->request->client->realm,
1311 KRB5_CONF_PROXIABLE, &tmp) == 0)
1316 ctx->request->kdc_options |= KDC_OPT_PROXIABLE;
1319 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
1321 else if (krb5_libdefault_boolean(context, &ctx->request->client->realm,
1322 KRB5_CONF_CANONICALIZE, &tmp) == 0)
1327 ctx->request->kdc_options |= KDC_OPT_CANONICALIZE;
1329 /* allow_postdate */
1330 if (ctx->start_time > 0)
1331 ctx->request->kdc_options |= KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED;
1333 /* ticket lifetime */
1334 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
1335 ctx->tkt_life = options->tkt_life;
1336 else if (krb5_libdefault_string(context, &ctx->request->client->realm,
1337 KRB5_CONF_TICKET_LIFETIME, &str) == 0) {
1338 code = krb5_string_to_deltat(str, &ctx->tkt_life);
1344 ctx->tkt_life = 24 * 60 * 60; /* previously hardcoded in kinit */
1346 /* renewable lifetime */
1347 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
1348 ctx->renew_life = options->renew_life;
1349 else if (krb5_libdefault_string(context, &ctx->request->client->realm,
1350 KRB5_CONF_RENEW_LIFETIME, &str) == 0) {
1351 code = krb5_string_to_deltat(str, &ctx->renew_life);
1357 ctx->renew_life = 0;
1359 if (ctx->renew_life > 0)
1360 ctx->request->kdc_options |= KDC_OPT_RENEWABLE;
1363 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
1364 ctx->request->ktype =
1365 k5alloc((opte->etype_list_length * sizeof(krb5_enctype)),
1369 ctx->request->nktypes = opte->etype_list_length;
1370 memcpy(ctx->request->ktype, opte->etype_list,
1371 ctx->request->nktypes * sizeof(krb5_enctype));
1372 } else if (krb5_get_default_in_tkt_ktypes(context,
1373 &ctx->request->ktype) == 0) {
1374 for (ctx->request->nktypes = 0;
1375 ctx->request->ktype[ctx->request->nktypes] != ENCTYPE_NULL;
1376 ctx->request->nktypes++)
1379 /* there isn't any useful default here. */
1380 code = KRB5_CONFIG_ETYPE_NOSUPP;
1385 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
1386 code = krb5_copy_addresses(context, opte->address_list,
1387 &ctx->request->addresses);
1390 } else if (krb5_libdefault_boolean(context, &ctx->request->client->realm,
1391 KRB5_CONF_NOADDRESSES, &tmp) != 0
1393 ctx->request->addresses = NULL;
1395 code = krb5_os_localaddr(context, &ctx->request->addresses);
1400 /* initial preauth state */
1401 krb5_preauth_request_context_init(context);
1403 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
1404 code = make_preauth_list(context,
1406 opte->preauth_list_length,
1407 &ctx->preauth_to_use);
1412 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
1413 code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
1417 ctx->salt.length = SALT_TYPE_AFS_LENGTH;
1418 ctx->salt.data = NULL;
1423 unsigned char random_buf[4];
1424 krb5_data random_data;
1426 random_data.length = sizeof(random_buf);
1427 random_data.data = (char *)random_buf;
1430 * See RT ticket 3196 at MIT. If we set the high bit, we
1431 * may have compatibility problems with Heimdal, because
1432 * we (incorrectly) encode this value as signed.
1434 if (krb5_c_random_make_octets(context, &random_data) == 0)
1435 ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
1439 code = krb5_timeofday(context, &now);
1443 ctx->request->nonce = (krb5_int32)now;
1453 krb5_init_creds_free(context, ctx);
1460 krb5_error_code KRB5_CALLCONV
1461 krb5_init_creds_set_service(krb5_context context,
1462 krb5_init_creds_context ctx,
1463 const char *service)
1467 s = strdup(service);
1471 free(ctx->in_tkt_service);
1472 ctx->in_tkt_service = s;
1477 static krb5_error_code
1478 init_creds_validate_reply(krb5_context context,
1479 krb5_init_creds_context ctx,
1482 krb5_error_code code;
1483 krb5_error *error = NULL;
1484 krb5_kdc_rep *as_reply = NULL;
1486 krb5_free_error(context, ctx->err_reply);
1487 ctx->err_reply = NULL;
1489 krb5_free_kdc_rep(context, ctx->reply);
1492 if (krb5_is_krb_error(reply)) {
1493 code = decode_krb5_error(reply, &error);
1497 assert(error != NULL);
1499 if (error->error == KRB_ERR_RESPONSE_TOO_BIG) {
1500 krb5_free_error(context, error);
1501 return KRB5KRB_ERR_RESPONSE_TOO_BIG;
1503 ctx->err_reply = error;
1509 * Check to make sure it isn't a V4 reply.
1511 if (reply->length != 0 && !krb5_is_as_rep(reply)) {
1512 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1513 #define V4_KRB_PROT_VERSION 4
1514 #define V4_AUTH_MSG_ERR_REPLY (5<<1)
1515 /* check here for V4 reply */
1516 unsigned int t_switch;
1518 /* From v4 g_in_tkt.c: This used to be
1519 switch (pkt_msg_type(rpkt) & ~1) {
1520 but SCO 3.2v4 cc compiled that incorrectly. */
1521 t_switch = reply->data[1];
1524 if (t_switch == V4_AUTH_MSG_ERR_REPLY
1525 && reply->data[0] == V4_KRB_PROT_VERSION) {
1526 code = KRB5KRB_AP_ERR_V4_REPLY;
1528 code = KRB5KRB_AP_ERR_MSG_TYPE;
1533 /* It must be a KRB_AS_REP message, or an bad returned packet */
1534 code = decode_krb5_as_rep(reply, &as_reply);
1538 if (as_reply->msg_type != KRB5_AS_REP) {
1539 krb5_free_kdc_rep(context, as_reply);
1540 return KRB5KRB_AP_ERR_MSG_TYPE;
1543 ctx->reply = as_reply;
1548 static krb5_error_code
1549 init_creds_step_request(krb5_context context,
1550 krb5_init_creds_context ctx,
1553 krb5_error_code code;
1555 krb5_free_principal(context, ctx->request->server);
1556 ctx->request->server = NULL;
1558 code = build_in_tkt_name(context, ctx->in_tkt_service,
1559 ctx->request->client,
1560 &ctx->request->server);
1564 if (ctx->loopcount == 0) {
1565 code = krb5_timeofday(context, &ctx->request_time);
1569 code = krb5int_fast_as_armor(context, ctx->fast_state,
1570 ctx->opte, ctx->request);
1574 /* give the preauth plugins a chance to prep the request body */
1575 krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
1576 code = krb5int_fast_prep_req_body(context, ctx->fast_state,
1578 &ctx->encoded_request_body);
1582 ctx->request->from = krb5int_addint32(ctx->request_time,
1584 ctx->request->till = krb5int_addint32(ctx->request->from,
1587 if (ctx->renew_life > 0) {
1588 ctx->request->rtime =
1589 krb5int_addint32(ctx->request->from, ctx->renew_life);
1590 if (ctx->request->rtime < ctx->request->till) {
1591 /* don't ask for a smaller renewable time than the lifetime */
1592 ctx->request->rtime = ctx->request->till;
1594 ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
1596 ctx->request->rtime = 0;
1597 } else if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
1598 code = KRB5_GET_IN_TKT_LOOP;
1602 if (ctx->err_reply == NULL) {
1603 /* either our first attempt, or retrying after PREAUTH_NEEDED */
1604 code = krb5_do_preauth(context,
1606 ctx->encoded_request_body,
1607 ctx->encoded_previous_request,
1608 ctx->preauth_to_use,
1609 &ctx->request->padata,
1618 &ctx->get_data_rock,
1623 if (ctx->preauth_to_use != NULL) {
1625 * Retry after an error other than PREAUTH_NEEDED,
1626 * using e-data to figure out what to change.
1628 code = krb5_do_preauth_tryagain(context,
1630 ctx->encoded_request_body,
1631 ctx->encoded_previous_request,
1632 ctx->preauth_to_use,
1633 &ctx->request->padata,
1643 &ctx->get_data_rock,
1646 /* No preauth supplied, so can't query the plugins. */
1647 code = KRB5KRB_ERR_GENERIC;
1650 /* couldn't come up with anything better */
1651 code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
1656 if (ctx->encoded_previous_request != NULL) {
1657 krb5_free_data(context, ctx->encoded_previous_request);
1658 ctx->encoded_previous_request = NULL;
1661 code = krb5int_fast_prep_req(context, ctx->fast_state,
1662 ctx->request, ctx->encoded_request_body,
1664 &ctx->encoded_previous_request);
1668 code = krb5int_copy_data_contents(context,
1669 ctx->encoded_previous_request,
1678 static krb5_error_code
1679 init_creds_step_reply(krb5_context context,
1680 krb5_init_creds_context ctx,
1683 krb5_error_code code;
1684 krb5_pa_data **padata = NULL;
1685 krb5_pa_data **kdc_padata = NULL;
1686 krb5_boolean retry = FALSE;
1688 krb5_keyblock *strengthen_key = NULL;
1689 krb5_keyblock encrypting_key;
1691 encrypting_key.length = 0;
1692 encrypting_key.contents = NULL;
1694 /* process previous KDC response */
1695 code = init_creds_validate_reply(context, ctx, in);
1699 /* per referrals draft, enterprise principals imply canonicalization */
1700 canon_flag = ((ctx->request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
1701 ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
1703 if (ctx->err_reply != NULL) {
1704 code = krb5int_fast_process_error(context, ctx->fast_state,
1705 &ctx->err_reply, &padata, &retry);
1709 if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED && retry) {
1710 /* reset the list of preauth types to try */
1711 krb5_free_pa_data(context, ctx->preauth_to_use);
1712 ctx->preauth_to_use = padata;
1714 /* this will trigger a new call to krb5_do_preauth() */
1715 krb5_free_error(context, ctx->err_reply);
1716 ctx->err_reply = NULL;
1717 code = sort_krb5_padata_sequence(context,
1718 &ctx->request->client->realm,
1719 ctx->preauth_to_use);
1721 } else if (canon_flag && ctx->err_reply->error == KDC_ERR_WRONG_REALM) {
1722 if (ctx->err_reply->client == NULL ||
1723 !krb5_princ_realm(context, ctx->err_reply->client)->length) {
1724 code = KRB5KDC_ERR_WRONG_REALM;
1727 /* Rewrite request.client with realm from error reply */
1728 krb5_free_data_contents(context, &ctx->request->client->realm);
1729 code = krb5int_copy_data_contents(context,
1730 &ctx->err_reply->client->realm,
1731 &ctx->request->client->realm);
1732 /* this will trigger a new call to krb5_do_preauth() */
1733 krb5_free_error(context, ctx->err_reply);
1734 ctx->err_reply = NULL;
1739 /* error + no hints = give up */
1740 code = (krb5_error_code)ctx->err_reply->error +
1741 ERROR_TABLE_BASE_krb5;
1745 /* Return error code, or continue with next iteration */
1749 /* We have a response. Process it. */
1750 assert(ctx->reply != NULL);
1752 /* process any preauth data in the as_reply */
1753 krb5_clear_preauth_context_use_counts(context);
1754 code = krb5int_fast_process_response(context, ctx->fast_state,
1755 ctx->reply, &strengthen_key);
1759 code = sort_krb5_padata_sequence(context, &ctx->request->client->realm,
1760 ctx->reply->padata);
1764 ctx->etype = ctx->reply->enc_part.enctype;
1766 code = krb5_do_preauth(context,
1768 ctx->encoded_request_body,
1769 ctx->encoded_previous_request,
1780 &ctx->get_data_rock,
1786 * If we haven't gotten a salt from another source yet, set up one
1787 * corresponding to the client principal returned by the KDC. We
1788 * could get the same effect by passing local_as_reply->client to
1789 * gak_fct below, but that would put the canonicalized client name
1790 * in the prompt, which raises issues of needing to sanitize
1791 * unprintable characters. So for now we just let it affect the
1792 * salt. local_as_reply->client will be checked later on in
1795 if (ctx->salt.length == SALT_TYPE_AFS_LENGTH && ctx->salt.data == NULL) {
1796 code = krb5_principal2salt(context, ctx->reply->client, &ctx->salt);
1801 /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
1802 the AS_REP comes back encrypted in the user's longterm key
1803 instead of in the SAD. If there was a SAM preauth, there
1804 will be an as_key here which will be the SAD. If that fails,
1805 use the gak_fct to get the password, and try again. */
1807 /* XXX because etypes are handled poorly (particularly wrt SAM,
1808 where the etype is fixed by the kdc), we may want to try
1809 decrypt_as_reply twice. If there's an as_key available, try
1810 it. If decrypting the as_rep fails, or if there isn't an
1811 as_key at all yet, then use the gak_fct to get one, and try
1813 if (ctx->as_key.length) {
1814 code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1818 code = decrypt_as_reply(context, NULL, ctx->reply, NULL, NULL,
1819 &encrypting_key, krb5_kdc_rep_decrypt_proc,
1825 /* if we haven't get gotten a key, get it now */
1826 code = (*ctx->gak_fct)(context, ctx->request->client,
1827 ctx->reply->enc_part.enctype,
1828 ctx->prompter, ctx->prompter_data,
1829 &ctx->salt, &ctx->s2kparams,
1830 &ctx->as_key, ctx->gak_data);
1834 code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1839 code = decrypt_as_reply(context, NULL, ctx->reply, NULL, NULL,
1840 &encrypting_key, krb5_kdc_rep_decrypt_proc,
1846 code = verify_as_reply(context, ctx->request_time,
1847 ctx->request, ctx->reply);
1851 code = stash_as_reply(context, ctx->request_time, ctx->request,
1852 ctx->reply, &ctx->cred, NULL);
1856 krb5_preauth_request_context_fini(context);
1860 ctx->flags |= KRB5_INIT_CREDS_STEP_FLAG_COMPLETE;
1863 krb5_free_pa_data(context, padata);
1864 krb5_free_pa_data(context, kdc_padata);
1865 krb5_free_keyblock(context, strengthen_key);
1866 krb5_free_keyblock_contents(context, &encrypting_key);
1872 * Do next step of credentials acquisition.
1874 * On success returns 0 or KRB5KRB_ERR_RESPONSE_TOO_BIG if the request
1875 * should be sent with TCP.
1877 krb5_error_code KRB5_CALLCONV
1878 krb5_init_creds_step(krb5_context context,
1879 krb5_init_creds_context ctx,
1883 unsigned int *flags)
1885 krb5_error_code code, code2;
1895 if (ctx->flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE)
1898 if (in->length != 0) {
1899 code = init_creds_step_reply(context, ctx, in);
1900 if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1901 code2 = krb5int_copy_data_contents(context,
1902 ctx->encoded_previous_request,
1910 if (code != 0 || (ctx->flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE))
1914 code = init_creds_step_request(context, ctx, out);
1918 /* Only a new request increments the loop count, not a TCP retry */
1922 assert(ctx->request->server != NULL);
1924 code2 = krb5int_copy_data_contents(context,
1925 &ctx->request->server->realm,
1933 if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) {
1936 /* See if we can produce a more detailed error message */
1937 code2 = krb5_unparse_name(context, ctx->request->client, &client_name);
1939 krb5_set_error_message(context, code,
1940 "Client '%s' not found in Kerberos database",
1942 krb5_free_unparsed_name(context, client_name);
1946 *flags = (ctx->flags & KRB5_INIT_CREDS_STEP_FLAG_COMPLETE);
1951 krb5_error_code KRB5_CALLCONV
1952 krb5int_get_init_creds(krb5_context context,
1954 krb5_principal client,
1955 krb5_prompter_fct prompter,
1956 void *prompter_data,
1957 krb5_deltat start_time,
1958 char *in_tkt_service,
1959 krb5_get_init_creds_opt *options,
1960 krb5_gic_get_as_key_fct gak_fct,
1963 krb5_kdc_rep **as_reply)
1965 krb5_error_code code;
1966 krb5_init_creds_context ctx = NULL;
1968 code = krb5_init_creds_init(context,
1978 ctx->gak_fct = gak_fct;
1979 ctx->gak_data = gak_data;
1981 if (in_tkt_service) {
1982 code = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1987 code = init_creds_get(context, ctx, use_master);
1991 code = krb5_init_creds_get_creds(context, ctx, creds);
1995 if (as_reply != NULL) {
1996 *as_reply = ctx->reply;
2001 krb5_init_creds_free(context, ctx);