2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "krb5_locl.h"
38 typedef struct krb5_get_init_creds_ctx
{
41 krb5_addresses
*addrs
;
43 krb5_preauthtype
*pre_auth_types
;
52 /* password and keytab_data is freed on completion */
54 krb5_keytab_key_proc_args
*keytab_data
;
56 krb5_pointer
*keyseed
;
57 krb5_s2k_proc keyproc
;
59 krb5_get_init_creds_tristate req_pac
;
61 krb5_pk_init_ctx pk_init_ctx
;
66 #define USED_PKINIT_W2K 2
67 #define USED_ENC_TS_GUESS 4
68 #define USED_ENC_TS_INFO 8
73 EncKDCRepPart enc_part
;
75 krb5_prompter_fct prompter
;
78 struct pa_info_data
*ppaid
;
81 #define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 1
82 #define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 2
83 #define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4
84 #define KRB5_FAST_REPLY_REPLY_VERIFED 8
85 #define KRB5_FAST_STRONG 16
86 krb5_keyblock
*reply_key
;
88 } krb5_get_init_creds_ctx
;
98 free_paid(krb5_context context
, struct pa_info_data
*ppaid
)
100 krb5_free_salt(context
, ppaid
->salt
);
101 if (ppaid
->s2kparams
)
102 krb5_free_data(context
, ppaid
->s2kparams
);
105 static krb5_error_code KRB5_CALLCONV
106 default_s2k_func(krb5_context context
, krb5_enctype type
,
107 krb5_const_pointer keyseed
,
108 krb5_salt salt
, krb5_data
*s2kparms
,
115 _krb5_debug(context
, 5, "krb5_get_init_creds: using default_s2k_func");
117 password
.data
= rk_UNCONST(keyseed
);
118 password
.length
= strlen(keyseed
);
122 krb5_data_zero(&opaque
);
124 *key
= malloc(sizeof(**key
));
127 ret
= krb5_string_to_key_data_salt_opaque(context
, type
, password
,
137 free_init_creds_ctx(krb5_context context
, krb5_init_creds_context ctx
)
141 if (ctx
->pre_auth_types
)
142 free (ctx
->pre_auth_types
);
143 if (ctx
->in_tkt_service
)
144 free(ctx
->in_tkt_service
);
145 if (ctx
->keytab_data
)
146 free(ctx
->keytab_data
);
148 memset(ctx
->password
, 0, strlen(ctx
->password
));
151 krb5_data_free(&ctx
->req_buffer
);
152 krb5_free_cred_contents(context
, &ctx
->cred
);
153 free_METHOD_DATA(&ctx
->md
);
154 free_AS_REP(&ctx
->as_rep
);
155 free_EncKDCRepPart(&ctx
->enc_part
);
156 free_KRB_ERROR(&ctx
->error
);
157 free_AS_REQ(&ctx
->as_req
);
159 free_paid(context
, ctx
->ppaid
);
162 memset(ctx
, 0, sizeof(*ctx
));
166 get_config_time (krb5_context context
,
173 ret
= krb5_config_get_time (context
, NULL
,
180 ret
= krb5_config_get_time (context
, NULL
,
189 static krb5_error_code
190 init_cred (krb5_context context
,
192 krb5_principal client
,
193 krb5_deltat start_time
,
194 krb5_get_init_creds_opt
*options
)
200 krb5_timeofday (context
, &now
);
202 memset (cred
, 0, sizeof(*cred
));
205 krb5_copy_principal(context
, client
, &cred
->client
);
207 ret
= krb5_get_default_principal (context
,
214 cred
->times
.starttime
= now
+ start_time
;
216 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_TKT_LIFE
)
217 tmp
= options
->tkt_life
;
220 cred
->times
.endtime
= now
+ tmp
;
222 if ((options
->flags
& KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE
) &&
223 options
->renew_life
> 0) {
224 cred
->times
.renew_till
= now
+ options
->renew_life
;
230 krb5_free_cred_contents (context
, cred
);
235 * Print a message (str) to the user about the expiration in `lr'
239 report_expiration (krb5_context context
,
240 krb5_prompter_fct prompter
,
247 if (asprintf(&p
, "%s%s", str
, ctime(&now
)) < 0 || p
== NULL
)
249 (*prompter
)(context
, data
, NULL
, p
, 0, NULL
);
254 * Check the context, and in the case there is a expiration warning,
255 * use the prompter to print the warning.
257 * @param context A Kerberos 5 context.
258 * @param options An GIC options structure
259 * @param ctx The krb5_init_creds_context check for expiration.
262 static krb5_error_code
263 process_last_request(krb5_context context
,
264 krb5_get_init_creds_opt
*options
,
265 krb5_init_creds_context ctx
)
267 krb5_const_realm realm
;
269 krb5_boolean reported
= FALSE
;
275 * First check if there is a API consumer.
278 realm
= krb5_principal_get_realm (context
, ctx
->cred
.client
);
279 lr
= &ctx
->enc_part
.last_req
;
281 if (options
&& options
->opt_private
&& options
->opt_private
->lr
.func
) {
282 krb5_last_req_entry
**lre
;
284 lre
= calloc(lr
->len
+ 1, sizeof(**lre
));
286 krb5_set_error_message(context
, ENOMEM
,
287 N_("malloc: out of memory", ""));
290 for (i
= 0; i
< lr
->len
; i
++) {
291 lre
[i
] = calloc(1, sizeof(*lre
[i
]));
294 lre
[i
]->lr_type
= lr
->val
[i
].lr_type
;
295 lre
[i
]->value
= lr
->val
[i
].lr_value
;
298 (*options
->opt_private
->lr
.func
)(context
, lre
,
299 options
->opt_private
->lr
.ctx
);
301 for (i
= 0; i
< lr
->len
; i
++)
307 * Now check if we should prompt the user
310 if (ctx
->prompter
== NULL
)
313 krb5_timeofday (context
, &sec
);
315 t
= sec
+ get_config_time (context
,
320 for (i
= 0; i
< lr
->len
; ++i
) {
321 if (lr
->val
[i
].lr_value
<= t
) {
322 switch (abs(lr
->val
[i
].lr_type
)) {
324 report_expiration(context
, ctx
->prompter
,
326 "Your password will expire at ",
327 lr
->val
[i
].lr_value
);
330 case LR_ACCT_EXPTIME
:
331 report_expiration(context
, ctx
->prompter
,
333 "Your account will expire at ",
334 lr
->val
[i
].lr_value
);
342 && ctx
->enc_part
.key_expiration
343 && *ctx
->enc_part
.key_expiration
<= t
) {
344 report_expiration(context
, ctx
->prompter
,
346 "Your password/account will expire at ",
347 *ctx
->enc_part
.key_expiration
);
352 static krb5_addresses no_addrs
= { 0, NULL
};
354 static krb5_error_code
355 get_init_creds_common(krb5_context context
,
356 krb5_principal client
,
357 krb5_deltat start_time
,
358 krb5_get_init_creds_opt
*options
,
359 krb5_init_creds_context ctx
)
361 krb5_get_init_creds_opt
*default_opt
= NULL
;
363 krb5_enctype
*etypes
;
364 krb5_preauthtype
*pre_auth_types
;
366 memset(ctx
, 0, sizeof(*ctx
));
368 if (options
== NULL
) {
369 const char *realm
= krb5_principal_get_realm(context
, client
);
371 krb5_get_init_creds_opt_alloc (context
, &default_opt
);
372 options
= default_opt
;
373 krb5_get_init_creds_opt_set_default_flags(context
, NULL
, realm
, options
);
376 if (options
->opt_private
) {
377 if (options
->opt_private
->password
) {
378 ret
= krb5_init_creds_set_password(context
, ctx
,
379 options
->opt_private
->password
);
384 ctx
->keyproc
= options
->opt_private
->key_proc
;
385 ctx
->req_pac
= options
->opt_private
->req_pac
;
386 ctx
->pk_init_ctx
= options
->opt_private
->pk_init_ctx
;
387 ctx
->ic_flags
= options
->opt_private
->flags
;
389 ctx
->req_pac
= KRB5_INIT_CREDS_TRISTATE_UNSET
;
391 if (ctx
->keyproc
== NULL
)
392 ctx
->keyproc
= default_s2k_func
;
394 /* Enterprise name implicitly turns on canonicalize */
395 if ((ctx
->ic_flags
& KRB5_INIT_CREDS_CANONICALIZE
) ||
396 krb5_principal_get_type(context
, client
) == KRB5_NT_ENTERPRISE_PRINCIPAL
)
397 ctx
->flags
.canonicalize
= 1;
399 ctx
->pre_auth_types
= NULL
;
402 ctx
->pre_auth_types
= NULL
;
404 ret
= init_cred(context
, &ctx
->cred
, client
, start_time
, options
);
407 krb5_get_init_creds_opt_free(context
, default_opt
);
411 ret
= krb5_init_creds_set_service(context
, ctx
, NULL
);
415 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_FORWARDABLE
)
416 ctx
->flags
.forwardable
= options
->forwardable
;
418 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_PROXIABLE
)
419 ctx
->flags
.proxiable
= options
->proxiable
;
422 ctx
->flags
.postdated
= 1;
423 if (ctx
->cred
.times
.renew_till
)
424 ctx
->flags
.renewable
= 1;
425 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST
) {
426 ctx
->addrs
= options
->address_list
;
427 } else if (options
->opt_private
) {
428 switch (options
->opt_private
->addressless
) {
429 case KRB5_INIT_CREDS_TRISTATE_UNSET
:
430 #if KRB5_ADDRESSLESS_DEFAULT == TRUE
431 ctx
->addrs
= &no_addrs
;
436 case KRB5_INIT_CREDS_TRISTATE_FALSE
:
439 case KRB5_INIT_CREDS_TRISTATE_TRUE
:
440 ctx
->addrs
= &no_addrs
;
444 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST
) {
448 etypes
= malloc((options
->etype_list_length
+ 1)
449 * sizeof(krb5_enctype
));
450 if (etypes
== NULL
) {
452 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
455 memcpy (etypes
, options
->etype_list
,
456 options
->etype_list_length
* sizeof(krb5_enctype
));
457 etypes
[options
->etype_list_length
] = ETYPE_NULL
;
458 ctx
->etypes
= etypes
;
460 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST
) {
461 pre_auth_types
= malloc((options
->preauth_list_length
+ 1)
462 * sizeof(krb5_preauthtype
));
463 if (pre_auth_types
== NULL
) {
465 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
468 memcpy (pre_auth_types
, options
->preauth_list
,
469 options
->preauth_list_length
* sizeof(krb5_preauthtype
));
470 pre_auth_types
[options
->preauth_list_length
] = KRB5_PADATA_NONE
;
471 ctx
->pre_auth_types
= pre_auth_types
;
473 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_ANONYMOUS
)
474 ctx
->flags
.request_anonymous
= options
->anonymous
;
476 krb5_get_init_creds_opt_free(context
, default_opt
);
480 krb5_get_init_creds_opt_free(context
, default_opt
);
484 static krb5_error_code
485 change_password (krb5_context context
,
486 krb5_principal client
,
487 const char *password
,
490 krb5_prompter_fct prompter
,
492 krb5_get_init_creds_opt
*old_options
)
494 krb5_prompt prompts
[2];
497 char buf1
[BUFSIZ
], buf2
[BUFSIZ
];
498 krb5_data password_data
[2];
500 krb5_data result_code_string
;
501 krb5_data result_string
;
503 krb5_get_init_creds_opt
*options
;
505 memset (&cpw_cred
, 0, sizeof(cpw_cred
));
507 ret
= krb5_get_init_creds_opt_alloc(context
, &options
);
510 krb5_get_init_creds_opt_set_tkt_life (options
, 60);
511 krb5_get_init_creds_opt_set_forwardable (options
, FALSE
);
512 krb5_get_init_creds_opt_set_proxiable (options
, FALSE
);
513 if (old_options
&& old_options
->flags
& KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST
)
514 krb5_get_init_creds_opt_set_preauth_list (options
,
515 old_options
->preauth_list
,
516 old_options
->preauth_list_length
);
518 krb5_data_zero (&result_code_string
);
519 krb5_data_zero (&result_string
);
521 ret
= krb5_get_init_creds_password (context
,
530 krb5_get_init_creds_opt_free(context
, options
);
535 password_data
[0].data
= buf1
;
536 password_data
[0].length
= sizeof(buf1
);
538 prompts
[0].hidden
= 1;
539 prompts
[0].prompt
= "New password: ";
540 prompts
[0].reply
= &password_data
[0];
541 prompts
[0].type
= KRB5_PROMPT_TYPE_NEW_PASSWORD
;
543 password_data
[1].data
= buf2
;
544 password_data
[1].length
= sizeof(buf2
);
546 prompts
[1].hidden
= 1;
547 prompts
[1].prompt
= "Repeat new password: ";
548 prompts
[1].reply
= &password_data
[1];
549 prompts
[1].type
= KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN
;
551 ret
= (*prompter
) (context
, data
, NULL
, "Changing password",
554 memset (buf1
, 0, sizeof(buf1
));
555 memset (buf2
, 0, sizeof(buf2
));
559 if (strcmp (buf1
, buf2
) == 0)
561 memset (buf1
, 0, sizeof(buf1
));
562 memset (buf2
, 0, sizeof(buf2
));
565 ret
= krb5_set_password (context
,
574 if (asprintf(&p
, "%s: %.*s\n",
575 result_code
? "Error" : "Success",
576 (int)result_string
.length
,
577 result_string
.length
> 0 ? (char*)result_string
.data
: "") < 0)
583 /* return the result */
584 (*prompter
) (context
, data
, NULL
, p
, 0, NULL
);
587 if (result_code
== 0) {
588 strlcpy (newpw
, buf1
, newpw_sz
);
592 krb5_set_error_message(context
, ret
,
593 N_("failed changing password", ""));
597 memset (buf1
, 0, sizeof(buf1
));
598 memset (buf2
, 0, sizeof(buf2
));
599 krb5_data_free (&result_string
);
600 krb5_data_free (&result_code_string
);
601 krb5_free_cred_contents (context
, &cpw_cred
);
606 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
607 krb5_keyblock_key_proc (krb5_context context
,
610 krb5_const_pointer keyseed
,
613 return krb5_copy_keyblock (context
, keyseed
, key
);
620 static krb5_error_code
621 init_as_req (krb5_context context
,
623 const krb5_creds
*creds
,
624 const krb5_addresses
*addrs
,
625 const krb5_enctype
*etypes
,
630 memset(a
, 0, sizeof(*a
));
633 a
->msg_type
= krb_as_req
;
634 a
->req_body
.kdc_options
= opts
;
635 a
->req_body
.cname
= malloc(sizeof(*a
->req_body
.cname
));
636 if (a
->req_body
.cname
== NULL
) {
638 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
641 a
->req_body
.sname
= malloc(sizeof(*a
->req_body
.sname
));
642 if (a
->req_body
.sname
== NULL
) {
644 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
648 ret
= _krb5_principal2principalname (a
->req_body
.cname
, creds
->client
);
651 ret
= copy_Realm(&creds
->client
->realm
, &a
->req_body
.realm
);
655 ret
= _krb5_principal2principalname (a
->req_body
.sname
, creds
->server
);
659 if(creds
->times
.starttime
) {
660 a
->req_body
.from
= malloc(sizeof(*a
->req_body
.from
));
661 if (a
->req_body
.from
== NULL
) {
663 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
666 *a
->req_body
.from
= creds
->times
.starttime
;
668 if(creds
->times
.endtime
){
669 ALLOC(a
->req_body
.till
, 1);
670 *a
->req_body
.till
= creds
->times
.endtime
;
672 if(creds
->times
.renew_till
){
673 a
->req_body
.rtime
= malloc(sizeof(*a
->req_body
.rtime
));
674 if (a
->req_body
.rtime
== NULL
) {
676 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
679 *a
->req_body
.rtime
= creds
->times
.renew_till
;
681 a
->req_body
.nonce
= 0;
682 ret
= _krb5_init_etype(context
,
684 &a
->req_body
.etype
.len
,
685 &a
->req_body
.etype
.val
,
691 * This means no addresses
694 if (addrs
&& addrs
->len
== 0) {
695 a
->req_body
.addresses
= NULL
;
697 a
->req_body
.addresses
= malloc(sizeof(*a
->req_body
.addresses
));
698 if (a
->req_body
.addresses
== NULL
) {
700 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
705 ret
= krb5_copy_addresses(context
, addrs
, a
->req_body
.addresses
);
707 ret
= krb5_get_all_client_addrs (context
, a
->req_body
.addresses
);
708 if(ret
== 0 && a
->req_body
.addresses
->len
== 0) {
709 free(a
->req_body
.addresses
);
710 a
->req_body
.addresses
= NULL
;
717 a
->req_body
.enc_authorization_data
= NULL
;
718 a
->req_body
.additional_tickets
= NULL
;
725 memset(a
, 0, sizeof(*a
));
730 static krb5_error_code
731 set_paid(struct pa_info_data
*paid
, krb5_context context
,
733 krb5_salttype salttype
, void *salt_string
, size_t salt_len
,
734 krb5_data
*s2kparams
)
737 paid
->salt
.salttype
= salttype
;
738 paid
->salt
.saltvalue
.data
= malloc(salt_len
+ 1);
739 if (paid
->salt
.saltvalue
.data
== NULL
) {
740 krb5_clear_error_message(context
);
743 memcpy(paid
->salt
.saltvalue
.data
, salt_string
, salt_len
);
744 ((char *)paid
->salt
.saltvalue
.data
)[salt_len
] = '\0';
745 paid
->salt
.saltvalue
.length
= salt_len
;
749 ret
= krb5_copy_data(context
, s2kparams
, &paid
->s2kparams
);
751 krb5_clear_error_message(context
);
752 krb5_free_salt(context
, paid
->salt
);
756 paid
->s2kparams
= NULL
;
761 static struct pa_info_data
*
762 pa_etype_info2(krb5_context context
,
763 const krb5_principal client
,
765 struct pa_info_data
*paid
,
766 heim_octet_string
*data
)
773 memset(&e
, 0, sizeof(e
));
774 ret
= decode_ETYPE_INFO2(data
->data
, data
->length
, &e
, &sz
);
779 for (j
= 0; j
< asreq
->req_body
.etype
.len
; j
++) {
780 for (i
= 0; i
< e
.len
; i
++) {
781 if (asreq
->req_body
.etype
.val
[j
] == e
.val
[i
].etype
) {
783 if (e
.val
[i
].salt
== NULL
)
784 ret
= krb5_get_pw_salt(context
, client
, &salt
);
786 salt
.saltvalue
.data
= *e
.val
[i
].salt
;
787 salt
.saltvalue
.length
= strlen(*e
.val
[i
].salt
);
791 ret
= set_paid(paid
, context
, e
.val
[i
].etype
,
794 salt
.saltvalue
.length
,
796 if (e
.val
[i
].salt
== NULL
)
797 krb5_free_salt(context
, salt
);
799 free_ETYPE_INFO2(&e
);
806 free_ETYPE_INFO2(&e
);
810 static struct pa_info_data
*
811 pa_etype_info(krb5_context context
,
812 const krb5_principal client
,
814 struct pa_info_data
*paid
,
815 heim_octet_string
*data
)
822 memset(&e
, 0, sizeof(e
));
823 ret
= decode_ETYPE_INFO(data
->data
, data
->length
, &e
, &sz
);
828 for (j
= 0; j
< asreq
->req_body
.etype
.len
; j
++) {
829 for (i
= 0; i
< e
.len
; i
++) {
830 if (asreq
->req_body
.etype
.val
[j
] == e
.val
[i
].etype
) {
832 salt
.salttype
= KRB5_PW_SALT
;
833 if (e
.val
[i
].salt
== NULL
)
834 ret
= krb5_get_pw_salt(context
, client
, &salt
);
836 salt
.saltvalue
= *e
.val
[i
].salt
;
839 if (e
.val
[i
].salttype
)
840 salt
.salttype
= *e
.val
[i
].salttype
;
842 ret
= set_paid(paid
, context
, e
.val
[i
].etype
,
845 salt
.saltvalue
.length
,
847 if (e
.val
[i
].salt
== NULL
)
848 krb5_free_salt(context
, salt
);
862 static struct pa_info_data
*
863 pa_pw_or_afs3_salt(krb5_context context
,
864 const krb5_principal client
,
866 struct pa_info_data
*paid
,
867 heim_octet_string
*data
)
870 if (paid
->etype
== KRB5_ENCTYPE_NULL
)
872 ret
= set_paid(paid
, context
,
885 krb5_preauthtype type
;
886 struct pa_info_data
*(*salt_info
)(krb5_context
,
887 const krb5_principal
,
889 struct pa_info_data
*,
890 heim_octet_string
*);
893 static struct pa_info pa_prefs
[] = {
894 { KRB5_PADATA_ETYPE_INFO2
, pa_etype_info2
},
895 { KRB5_PADATA_ETYPE_INFO
, pa_etype_info
},
896 { KRB5_PADATA_PW_SALT
, pa_pw_or_afs3_salt
},
897 { KRB5_PADATA_AFS3_SALT
, pa_pw_or_afs3_salt
}
901 find_pa_data(const METHOD_DATA
*md
, unsigned type
)
906 for (i
= 0; i
< md
->len
; i
++)
907 if (md
->val
[i
].padata_type
== type
)
912 static struct pa_info_data
*
913 process_pa_info(krb5_context context
,
914 const krb5_principal client
,
916 struct pa_info_data
*paid
,
919 struct pa_info_data
*p
= NULL
;
922 for (i
= 0; p
== NULL
&& i
< sizeof(pa_prefs
)/sizeof(pa_prefs
[0]); i
++) {
923 PA_DATA
*pa
= find_pa_data(md
, pa_prefs
[i
].type
);
926 paid
->salt
.salttype
= (krb5_salttype
)pa_prefs
[i
].type
;
927 p
= (*pa_prefs
[i
].salt_info
)(context
, client
, asreq
,
928 paid
, &pa
->padata_value
);
933 static krb5_error_code
934 make_pa_enc_timestamp(krb5_context context
, METHOD_DATA
*md
,
935 krb5_enctype etype
, krb5_keyblock
*key
)
941 EncryptedData encdata
;
947 krb5_us_timeofday (context
, &p
.patimestamp
, &usec
);
951 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC
, buf
, buf_size
, &p
, &len
, ret
);
955 krb5_abortx(context
, "internal error in ASN.1 encoder");
957 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
962 ret
= krb5_encrypt_EncryptedData(context
,
964 KRB5_KU_PA_ENC_TIMESTAMP
,
970 krb5_crypto_destroy(context
, crypto
);
974 ASN1_MALLOC_ENCODE(EncryptedData
, buf
, buf_size
, &encdata
, &len
, ret
);
975 free_EncryptedData(&encdata
);
979 krb5_abortx(context
, "internal error in ASN.1 encoder");
981 ret
= krb5_padata_add(context
, md
, KRB5_PADATA_ENC_TIMESTAMP
, buf
, len
);
987 static krb5_error_code
988 add_enc_ts_padata(krb5_context context
,
990 krb5_principal client
,
991 krb5_s2k_proc keyproc
,
992 krb5_const_pointer keyseed
,
993 krb5_enctype
*enctypes
,
996 krb5_data
*s2kparams
)
1004 /* default to standard salt */
1005 ret
= krb5_get_pw_salt (context
, client
, &salt2
);
1011 enctypes
= context
->etypes
;
1013 for (ep
= enctypes
; *ep
!= ETYPE_NULL
; ep
++)
1017 for (i
= 0; i
< netypes
; ++i
) {
1020 _krb5_debug(context
, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes
[i
]);
1022 ret
= (*keyproc
)(context
, enctypes
[i
], keyseed
,
1023 *salt
, s2kparams
, &key
);
1026 ret
= make_pa_enc_timestamp (context
, md
, enctypes
[i
], key
);
1027 krb5_free_keyblock (context
, key
);
1032 krb5_free_salt(context
, salt2
);
1036 static krb5_error_code
1037 pa_data_to_md_ts_enc(krb5_context context
,
1039 const krb5_principal client
,
1040 krb5_get_init_creds_ctx
*ctx
,
1041 struct pa_info_data
*ppaid
,
1044 if (ctx
->keyproc
== NULL
|| ctx
->keyseed
== NULL
)
1048 add_enc_ts_padata(context
, md
, client
,
1049 ctx
->keyproc
, ctx
->keyseed
,
1051 &ppaid
->salt
, ppaid
->s2kparams
);
1055 _krb5_debug(context
, 5, "krb5_get_init_creds: pa-info not found, guessing salt");
1057 /* make a v5 salted pa-data */
1058 add_enc_ts_padata(context
, md
, client
,
1059 ctx
->keyproc
, ctx
->keyseed
,
1060 a
->req_body
.etype
.val
, a
->req_body
.etype
.len
,
1063 /* make a v4 salted pa-data */
1064 salt
.salttype
= KRB5_PW_SALT
;
1065 krb5_data_zero(&salt
.saltvalue
);
1066 add_enc_ts_padata(context
, md
, client
,
1067 ctx
->keyproc
, ctx
->keyseed
,
1068 a
->req_body
.etype
.val
, a
->req_body
.etype
.len
,
1074 static krb5_error_code
1075 pa_data_to_key_plain(krb5_context context
,
1076 const krb5_principal client
,
1077 krb5_get_init_creds_ctx
*ctx
,
1079 krb5_data
*s2kparams
,
1081 krb5_keyblock
**key
)
1083 krb5_error_code ret
;
1085 ret
= (*ctx
->keyproc
)(context
, etype
, ctx
->keyseed
,
1086 salt
, s2kparams
, key
);
1091 static krb5_error_code
1092 pa_data_to_md_pkinit(krb5_context context
,
1094 const krb5_principal client
,
1096 krb5_get_init_creds_ctx
*ctx
,
1099 if (ctx
->pk_init_ctx
== NULL
)
1102 return _krb5_pk_mk_padata(context
,
1110 krb5_set_error_message(context
, EINVAL
,
1111 N_("no support for PKINIT compiled in", ""));
1116 static krb5_error_code
1117 pa_data_add_pac_request(krb5_context context
,
1118 krb5_get_init_creds_ctx
*ctx
,
1121 size_t len
= 0, length
;
1122 krb5_error_code ret
;
1126 switch (ctx
->req_pac
) {
1127 case KRB5_INIT_CREDS_TRISTATE_UNSET
:
1128 return 0; /* don't bother */
1129 case KRB5_INIT_CREDS_TRISTATE_TRUE
:
1130 req
.include_pac
= 1;
1132 case KRB5_INIT_CREDS_TRISTATE_FALSE
:
1133 req
.include_pac
= 0;
1136 ASN1_MALLOC_ENCODE(PA_PAC_REQUEST
, buf
, length
,
1141 krb5_abortx(context
, "internal error in ASN.1 encoder");
1143 ret
= krb5_padata_add(context
, md
, KRB5_PADATA_PA_PAC_REQUEST
, buf
, len
);
1151 * Assumes caller always will free `out_md', even on error.
1154 static krb5_error_code
1155 process_pa_data_to_md(krb5_context context
,
1156 const krb5_creds
*creds
,
1158 krb5_get_init_creds_ctx
*ctx
,
1160 METHOD_DATA
**out_md
,
1161 krb5_prompter_fct prompter
,
1162 void *prompter_data
)
1164 krb5_error_code ret
;
1167 if (*out_md
== NULL
) {
1168 krb5_set_error_message(context
, ENOMEM
, N_("malloc: out of memory", ""));
1172 (*out_md
)->val
= NULL
;
1174 if (_krb5_have_debug(context
, 5)) {
1176 _krb5_debug(context
, 5, "KDC send %d patypes", in_md
->len
);
1177 for (i
= 0; i
< in_md
->len
; i
++)
1178 _krb5_debug(context
, 5, "KDC send PA-DATA type: %d", in_md
->val
[i
].padata_type
);
1182 * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
1183 * need to expose our password protecting our PKCS12 key.
1186 if (ctx
->pk_init_ctx
) {
1188 _krb5_debug(context
, 5, "krb5_get_init_creds: "
1189 "prepareing PKINIT padata (%s)",
1190 (ctx
->used_pa_types
& USED_PKINIT_W2K
) ? "win2k" : "ietf");
1192 if (ctx
->used_pa_types
& USED_PKINIT_W2K
) {
1193 krb5_set_error_message(context
, KRB5_GET_IN_TKT_LOOP
,
1194 "Already tried pkinit, looping");
1195 return KRB5_GET_IN_TKT_LOOP
;
1198 ret
= pa_data_to_md_pkinit(context
, a
, creds
->client
,
1199 (ctx
->used_pa_types
& USED_PKINIT
),
1204 if (ctx
->used_pa_types
& USED_PKINIT
)
1205 ctx
->used_pa_types
|= USED_PKINIT_W2K
;
1207 ctx
->used_pa_types
|= USED_PKINIT
;
1209 } else if (in_md
->len
!= 0) {
1210 struct pa_info_data
*paid
, *ppaid
;
1213 paid
= calloc(1, sizeof(*paid
));
1215 paid
->etype
= KRB5_ENCTYPE_NULL
;
1216 ppaid
= process_pa_info(context
, creds
->client
, a
, paid
, in_md
);
1219 flag
= USED_ENC_TS_INFO
;
1221 flag
= USED_ENC_TS_GUESS
;
1223 if (ctx
->used_pa_types
& flag
) {
1225 free_paid(context
, ppaid
);
1226 krb5_set_error_message(context
, KRB5_GET_IN_TKT_LOOP
,
1227 "Already tried ENC-TS-%s, looping",
1228 flag
== USED_ENC_TS_INFO
? "info" : "guess");
1229 return KRB5_GET_IN_TKT_LOOP
;
1232 pa_data_to_md_ts_enc(context
, a
, creds
->client
, ctx
, ppaid
, *out_md
);
1234 ctx
->used_pa_types
|= flag
;
1238 free_paid(context
, ctx
->ppaid
);
1246 pa_data_add_pac_request(context
, ctx
, *out_md
);
1248 if ((*out_md
)->len
== 0) {
1256 static krb5_error_code
1257 process_pa_data_to_key(krb5_context context
,
1258 krb5_get_init_creds_ctx
*ctx
,
1262 const krb5_krbhst_info
*hi
,
1263 krb5_keyblock
**key
)
1265 struct pa_info_data paid
, *ppaid
= NULL
;
1266 krb5_error_code ret
;
1270 memset(&paid
, 0, sizeof(paid
));
1272 etype
= rep
->enc_part
.etype
;
1276 ppaid
= process_pa_info(context
, creds
->client
, a
, &paid
,
1281 if (ppaid
== NULL
) {
1282 ret
= krb5_get_pw_salt (context
, creds
->client
, &paid
.salt
);
1286 paid
.s2kparams
= NULL
;
1293 pa
= krb5_find_padata(rep
->padata
->val
,
1295 KRB5_PADATA_PK_AS_REP
,
1299 pa
= krb5_find_padata(rep
->padata
->val
,
1301 KRB5_PADATA_PK_AS_REP_19
,
1305 if (pa
&& ctx
->pk_init_ctx
) {
1307 _krb5_debug(context
, 5, "krb5_get_init_creds: using PKINIT");
1309 ret
= _krb5_pk_rd_pa_reply(context
,
1320 krb5_set_error_message(context
, ret
, N_("no support for PKINIT compiled in", ""));
1322 } else if (ctx
->keyseed
) {
1323 _krb5_debug(context
, 5, "krb5_get_init_creds: using keyproc");
1324 ret
= pa_data_to_key_plain(context
, creds
->client
, ctx
,
1325 ppaid
->salt
, ppaid
->s2kparams
, etype
, key
);
1328 krb5_set_error_message(context
, ret
, N_("No usable pa data type", ""));
1331 free_paid(context
, &paid
);
1336 * Start a new context to get a new initial credential.
1338 * @param context A Kerberos 5 context.
1339 * @param client The Kerberos principal to get the credential for, if
1340 * NULL is given, the default principal is used as determined by
1341 * krb5_get_default_principal().
1343 * @param prompter_data
1344 * @param start_time the time the ticket should start to be valid or 0 for now.
1345 * @param options a options structure, can be NULL for default options.
1346 * @param rctx A new allocated free with krb5_init_creds_free().
1348 * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message().
1350 * @ingroup krb5_credential
1353 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1354 krb5_init_creds_init(krb5_context context
,
1355 krb5_principal client
,
1356 krb5_prompter_fct prompter
,
1357 void *prompter_data
,
1358 krb5_deltat start_time
,
1359 krb5_get_init_creds_opt
*options
,
1360 krb5_init_creds_context
*rctx
)
1362 krb5_init_creds_context ctx
;
1363 krb5_error_code ret
;
1367 ctx
= calloc(1, sizeof(*ctx
));
1369 krb5_set_error_message(context
, ENOMEM
, N_("malloc: out of memory", ""));
1373 ret
= get_init_creds_common(context
, client
, start_time
, options
, ctx
);
1379 /* Set a new nonce. */
1380 krb5_generate_random_block (&ctx
->nonce
, sizeof(ctx
->nonce
));
1381 ctx
->nonce
&= 0x7fffffff;
1382 /* XXX these just needs to be the same when using Windows PK-INIT */
1383 ctx
->pk_nonce
= ctx
->nonce
;
1385 ctx
->prompter
= prompter
;
1386 ctx
->prompter_data
= prompter_data
;
1394 * Sets the service that the is requested. This call is only neede for
1395 * special initial tickets, by default the a krbtgt is fetched in the default realm.
1397 * @param context a Kerberos 5 context.
1398 * @param ctx a krb5_init_creds_context context.
1399 * @param service the service given as a string, for example
1400 * "kadmind/admin". If NULL, the default krbtgt in the clients
1403 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1404 * @ingroup krb5_credential
1407 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1408 krb5_init_creds_set_service(krb5_context context
,
1409 krb5_init_creds_context ctx
,
1410 const char *service
)
1412 krb5_const_realm client_realm
;
1413 krb5_principal principal
;
1414 krb5_error_code ret
;
1416 client_realm
= krb5_principal_get_realm (context
, ctx
->cred
.client
);
1419 ret
= krb5_parse_name (context
, service
, &principal
);
1422 krb5_principal_set_realm (context
, principal
, client_realm
);
1424 ret
= krb5_make_principal(context
, &principal
,
1425 client_realm
, KRB5_TGS_NAME
, client_realm
,
1432 * This is for Windows RODC that are picky about what name type
1433 * the server principal have, and the really strange part is that
1434 * they are picky about the AS-REQ name type and not the TGS-REQ
1438 if (krb5_principal_is_krbtgt(context
, principal
))
1439 krb5_principal_set_type(context
, principal
, KRB5_NT_SRV_INST
);
1441 krb5_free_principal(context
, ctx
->cred
.server
);
1442 ctx
->cred
.server
= principal
;
1448 * Sets the password that will use for the request.
1450 * @param context a Kerberos 5 context.
1451 * @param ctx ctx krb5_init_creds_context context.
1452 * @param password the password to use.
1454 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1455 * @ingroup krb5_credential
1458 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1459 krb5_init_creds_set_password(krb5_context context
,
1460 krb5_init_creds_context ctx
,
1461 const char *password
)
1463 if (ctx
->password
) {
1464 memset(ctx
->password
, 0, strlen(ctx
->password
));
1465 free(ctx
->password
);
1468 ctx
->password
= strdup(password
);
1469 if (ctx
->password
== NULL
) {
1470 krb5_set_error_message(context
, ENOMEM
, N_("malloc: out of memory", ""));
1473 ctx
->keyseed
= (void *) ctx
->password
;
1475 ctx
->keyseed
= NULL
;
1476 ctx
->password
= NULL
;
1482 static krb5_error_code KRB5_CALLCONV
1483 keytab_key_proc(krb5_context context
, krb5_enctype enctype
,
1484 krb5_const_pointer keyseed
,
1485 krb5_salt salt
, krb5_data
*s2kparms
,
1486 krb5_keyblock
**key
)
1488 krb5_keytab_key_proc_args
*args
= rk_UNCONST(keyseed
);
1489 krb5_keytab keytab
= args
->keytab
;
1490 krb5_principal principal
= args
->principal
;
1491 krb5_error_code ret
;
1492 krb5_keytab real_keytab
;
1493 krb5_keytab_entry entry
;
1496 krb5_kt_default(context
, &real_keytab
);
1498 real_keytab
= keytab
;
1500 ret
= krb5_kt_get_entry (context
, real_keytab
, principal
,
1501 0, enctype
, &entry
);
1504 krb5_kt_close (context
, real_keytab
);
1509 ret
= krb5_copy_keyblock (context
, &entry
.keyblock
, key
);
1510 krb5_kt_free_entry(context
, &entry
);
1516 * Set the keytab to use for authentication.
1518 * @param context a Kerberos 5 context.
1519 * @param ctx ctx krb5_init_creds_context context.
1520 * @param keytab the keytab to read the key from.
1522 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1523 * @ingroup krb5_credential
1526 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1527 krb5_init_creds_set_keytab(krb5_context context
,
1528 krb5_init_creds_context ctx
,
1531 krb5_keytab_key_proc_args
*a
;
1532 krb5_keytab_entry entry
;
1533 krb5_kt_cursor cursor
;
1534 krb5_enctype
*etypes
= NULL
;
1535 krb5_error_code ret
;
1539 a
= malloc(sizeof(*a
));
1541 krb5_set_error_message(context
, ENOMEM
,
1542 N_("malloc: out of memory", ""));
1546 a
->principal
= ctx
->cred
.client
;
1549 ctx
->keytab_data
= a
;
1550 ctx
->keyseed
= (void *)a
;
1551 ctx
->keyproc
= keytab_key_proc
;
1554 * We need to the KDC what enctypes we support for this keytab,
1555 * esp if the keytab is really a password based entry, then the
1556 * KDC might have more enctypes in the database then what we have
1560 ret
= krb5_kt_start_seq_get(context
, keytab
, &cursor
);
1564 while(krb5_kt_next_entry(context
, keytab
, &entry
, &cursor
) == 0){
1567 if (!krb5_principal_compare(context
, entry
.principal
, ctx
->cred
.client
))
1570 /* check if we ahve this kvno already */
1571 if (entry
.vno
> kvno
) {
1572 /* remove old list of etype */
1578 } else if (entry
.vno
!= kvno
)
1581 /* check if enctype is supported */
1582 if (krb5_enctype_valid(context
, entry
.keyblock
.keytype
) != 0)
1585 /* add enctype to supported list */
1586 ptr
= realloc(etypes
, sizeof(etypes
[0]) * (netypes
+ 2));
1591 etypes
[netypes
] = entry
.keyblock
.keytype
;
1592 etypes
[netypes
+ 1] = ETYPE_NULL
;
1595 krb5_kt_free_entry(context
, &entry
);
1597 krb5_kt_end_seq_get(context
, keytab
, &cursor
);
1602 ctx
->etypes
= etypes
;
1609 static krb5_error_code KRB5_CALLCONV
1610 keyblock_key_proc(krb5_context context
, krb5_enctype enctype
,
1611 krb5_const_pointer keyseed
,
1612 krb5_salt salt
, krb5_data
*s2kparms
,
1613 krb5_keyblock
**key
)
1615 return krb5_copy_keyblock (context
, keyseed
, key
);
1618 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1619 krb5_init_creds_set_keyblock(krb5_context context
,
1620 krb5_init_creds_context ctx
,
1621 krb5_keyblock
*keyblock
)
1623 ctx
->keyseed
= (void *)keyblock
;
1624 ctx
->keyproc
= keyblock_key_proc
;
1630 * The core loop if krb5_get_init_creds() function family. Create the
1631 * packets and have the caller send them off to the KDC.
1633 * If the caller want all work been done for them, use
1634 * krb5_init_creds_get() instead.
1636 * @param context a Kerberos 5 context.
1637 * @param ctx ctx krb5_init_creds_context context.
1638 * @param in input data from KDC, first round it should be reset by krb5_data_zer().
1639 * @param out reply to KDC.
1640 * @param hostinfo KDC address info, first round it can be NULL.
1641 * @param flags status of the round, if
1642 * KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round.
1644 * @return 0 for success, or an Kerberos 5 error code, see
1645 * krb5_get_error_message().
1647 * @ingroup krb5_credential
1650 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1651 krb5_init_creds_step(krb5_context context
,
1652 krb5_init_creds_context ctx
,
1655 krb5_krbhst_info
*hostinfo
,
1656 unsigned int *flags
)
1658 krb5_error_code ret
;
1662 krb5_data_zero(out
);
1664 if (ctx
->as_req
.req_body
.cname
== NULL
) {
1665 ret
= init_as_req(context
, ctx
->flags
, &ctx
->cred
,
1666 ctx
->addrs
, ctx
->etypes
, &ctx
->as_req
);
1668 free_init_creds_ctx(context
, ctx
);
1673 #define MAX_PA_COUNTER 10
1674 if (ctx
->pa_counter
> MAX_PA_COUNTER
) {
1675 krb5_set_error_message(context
, KRB5_GET_IN_TKT_LOOP
,
1676 N_("Looping %d times while getting "
1677 "initial credentials", ""),
1679 return KRB5_GET_IN_TKT_LOOP
;
1683 _krb5_debug(context
, 5, "krb5_get_init_creds: loop %d", ctx
->pa_counter
);
1685 /* Lets process the input packet */
1686 if (in
&& in
->length
) {
1689 memset(&rep
, 0, sizeof(rep
));
1691 _krb5_debug(context
, 5, "krb5_get_init_creds: processing input");
1693 ret
= decode_AS_REP(in
->data
, in
->length
, &rep
.kdc_rep
, &size
);
1695 unsigned eflags
= EXTRACT_TICKET_AS_REQ
| EXTRACT_TICKET_TIMESYNC
;
1697 if (ctx
->flags
.canonicalize
) {
1698 eflags
|= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH
;
1699 eflags
|= EXTRACT_TICKET_MATCH_REALM
;
1701 if (ctx
->ic_flags
& KRB5_INIT_CREDS_NO_C_CANON_CHECK
)
1702 eflags
|= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH
;
1704 ret
= process_pa_data_to_key(context
, ctx
, &ctx
->cred
,
1705 &ctx
->as_req
, &rep
.kdc_rep
,
1706 hostinfo
, &ctx
->fast_state
.reply_key
);
1708 free_AS_REP(&rep
.kdc_rep
);
1712 _krb5_debug(context
, 5, "krb5_get_init_creds: extracting ticket");
1714 ret
= _krb5_extract_ticket(context
,
1717 ctx
->fast_state
.reply_key
,
1719 KRB5_KU_AS_REP_ENC_PART
,
1725 krb5_free_keyblock(context
, ctx
->fast_state
.reply_key
);
1726 ctx
->fast_state
.reply_key
= NULL
;
1730 ret
= copy_EncKDCRepPart(&rep
.enc_part
, &ctx
->enc_part
);
1732 free_AS_REP(&rep
.kdc_rep
);
1733 free_EncASRepPart(&rep
.enc_part
);
1738 /* let's try to parse it as a KRB-ERROR */
1740 _krb5_debug(context
, 5, "krb5_get_init_creds: got an error");
1742 free_KRB_ERROR(&ctx
->error
);
1744 ret
= krb5_rd_error(context
, in
, &ctx
->error
);
1745 if(ret
&& in
->length
&& ((char*)in
->data
)[0] == 4)
1746 ret
= KRB5KRB_AP_ERR_V4_REPLY
;
1748 _krb5_debug(context
, 5, "krb5_get_init_creds: failed to read error");
1752 ret
= krb5_error_from_rd_error(context
, &ctx
->error
, &ctx
->cred
);
1754 _krb5_debug(context
, 5, "krb5_get_init_creds: KRB-ERROR %d", ret
);
1757 * If no preauth was set and KDC requires it, give it one
1761 if (ret
== KRB5KDC_ERR_PREAUTH_REQUIRED
) {
1763 free_METHOD_DATA(&ctx
->md
);
1764 memset(&ctx
->md
, 0, sizeof(ctx
->md
));
1766 if (ctx
->error
.e_data
) {
1767 ret
= decode_METHOD_DATA(ctx
->error
.e_data
->data
,
1768 ctx
->error
.e_data
->length
,
1772 krb5_set_error_message(context
, ret
,
1773 N_("Failed to decode METHOD-DATA", ""));
1775 krb5_set_error_message(context
, ret
,
1776 N_("Preauth required but no preauth "
1777 "options send by KDC", ""));
1779 } else if (ret
== KRB5KRB_AP_ERR_SKEW
&& context
->kdc_sec_offset
== 0) {
1781 * Try adapt to timeskrew when we are using pre-auth, and
1782 * if there was a time skew, try again.
1784 krb5_set_real_time(context
, ctx
->error
.stime
, -1);
1785 if (context
->kdc_sec_offset
)
1788 _krb5_debug(context
, 10, "init_creds: err skew updateing kdc offset to %d",
1789 context
->kdc_sec_offset
);
1791 ctx
->used_pa_types
= 0;
1793 } else if (ret
== KRB5_KDC_ERR_WRONG_REALM
&& ctx
->flags
.canonicalize
) {
1794 /* client referal to a new realm */
1796 if (ctx
->error
.crealm
== NULL
) {
1797 krb5_set_error_message(context
, ret
,
1798 N_("Got a client referral, not but no realm", ""));
1801 _krb5_debug(context
, 5,
1802 "krb5_get_init_creds: got referal to realm %s",
1803 *ctx
->error
.crealm
);
1805 ret
= krb5_principal_set_realm(context
,
1807 *ctx
->error
.crealm
);
1809 ctx
->used_pa_types
= 0;
1816 if (ctx
->as_req
.padata
) {
1817 free_METHOD_DATA(ctx
->as_req
.padata
);
1818 free(ctx
->as_req
.padata
);
1819 ctx
->as_req
.padata
= NULL
;
1822 /* Set a new nonce. */
1823 ctx
->as_req
.req_body
.nonce
= ctx
->nonce
;
1825 /* fill_in_md_data */
1826 ret
= process_pa_data_to_md(context
, &ctx
->cred
, &ctx
->as_req
, ctx
,
1827 &ctx
->md
, &ctx
->as_req
.padata
,
1828 ctx
->prompter
, ctx
->prompter_data
);
1832 krb5_data_free(&ctx
->req_buffer
);
1834 ASN1_MALLOC_ENCODE(AS_REQ
,
1835 ctx
->req_buffer
.data
, ctx
->req_buffer
.length
,
1836 &ctx
->as_req
, &len
, ret
);
1839 if(len
!= ctx
->req_buffer
.length
)
1840 krb5_abortx(context
, "internal error in ASN.1 encoder");
1842 out
->data
= ctx
->req_buffer
.data
;
1843 out
->length
= ctx
->req_buffer
.length
;
1845 *flags
= KRB5_INIT_CREDS_STEP_FLAG_CONTINUE
;
1853 * Extract the newly acquired credentials from krb5_init_creds_context
1856 * @param context A Kerberos 5 context.
1858 * @param cred credentials, free with krb5_free_cred_contents().
1860 * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
1863 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1864 krb5_init_creds_get_creds(krb5_context context
,
1865 krb5_init_creds_context ctx
,
1868 return krb5_copy_creds_contents(context
, &ctx
->cred
, cred
);
1872 * Get the last error from the transaction.
1874 * @return Returns 0 or an error code
1876 * @ingroup krb5_credential
1879 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1880 krb5_init_creds_get_error(krb5_context context
,
1881 krb5_init_creds_context ctx
,
1884 krb5_error_code ret
;
1886 ret
= copy_KRB_ERROR(&ctx
->error
, error
);
1888 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
1894 * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
1896 * @param context A Kerberos 5 context.
1897 * @param ctx The krb5_init_creds_context to free.
1899 * @ingroup krb5_credential
1902 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
1903 krb5_init_creds_free(krb5_context context
,
1904 krb5_init_creds_context ctx
)
1906 free_init_creds_ctx(context
, ctx
);
1911 * Get new credentials as setup by the krb5_init_creds_context.
1913 * @param context A Kerberos 5 context.
1914 * @param ctx The krb5_init_creds_context to process.
1916 * @ingroup krb5_credential
1919 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1920 krb5_init_creds_get(krb5_context context
, krb5_init_creds_context ctx
)
1922 krb5_sendto_ctx stctx
= NULL
;
1923 krb5_krbhst_info
*hostinfo
= NULL
;
1924 krb5_error_code ret
;
1926 unsigned int flags
= 0;
1928 krb5_data_zero(&in
);
1929 krb5_data_zero(&out
);
1931 ret
= krb5_sendto_ctx_alloc(context
, &stctx
);
1934 krb5_sendto_ctx_set_func(stctx
, _krb5_kdc_retry
, NULL
);
1938 ret
= krb5_init_creds_step(context
, ctx
, &in
, &out
, hostinfo
, &flags
);
1939 krb5_data_free(&in
);
1943 if ((flags
& 1) == 0)
1946 ret
= krb5_sendto_context (context
, stctx
, &out
,
1947 ctx
->cred
.client
->realm
, &in
);
1955 krb5_sendto_ctx_free(context
, stctx
);
1961 * Get new credentials using password.
1963 * @ingroup krb5_credential
1967 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1968 krb5_get_init_creds_password(krb5_context context
,
1970 krb5_principal client
,
1971 const char *password
,
1972 krb5_prompter_fct prompter
,
1974 krb5_deltat start_time
,
1975 const char *in_tkt_service
,
1976 krb5_get_init_creds_opt
*options
)
1978 krb5_init_creds_context ctx
;
1980 krb5_error_code ret
;
1984 ret
= krb5_init_creds_init(context
, client
, prompter
, data
, start_time
, options
, &ctx
);
1988 ret
= krb5_init_creds_set_service(context
, ctx
, in_tkt_service
);
1992 if (prompter
!= NULL
&& ctx
->password
== NULL
&& password
== NULL
) {
1994 krb5_data password_data
;
1997 krb5_unparse_name (context
, client
, &p
);
1998 asprintf (&q
, "%s's Password: ", p
);
2001 password_data
.data
= buf
;
2002 password_data
.length
= sizeof(buf
);
2004 prompt
.reply
= &password_data
;
2005 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
2007 ret
= (*prompter
) (context
, data
, NULL
, NULL
, 1, &prompt
);
2010 memset (buf
, 0, sizeof(buf
));
2011 ret
= KRB5_LIBOS_PWDINTR
;
2012 krb5_clear_error_message (context
);
2015 password
= password_data
.data
;
2019 ret
= krb5_init_creds_set_password(context
, ctx
, password
);
2024 ret
= krb5_init_creds_get(context
, ctx
);
2027 process_last_request(context
, options
, ctx
);
2030 if (ret
== KRB5KDC_ERR_KEY_EXPIRED
&& chpw
== 0) {
2033 /* try to avoid recursion */
2034 if (in_tkt_service
!= NULL
&& strcmp(in_tkt_service
, "kadmin/changepw") == 0)
2037 /* don't try to change password where then where none */
2038 if (prompter
== NULL
)
2041 ret
= change_password (context
,
2052 krb5_init_creds_free(context
, ctx
);
2058 krb5_init_creds_get_creds(context
, ctx
, creds
);
2061 krb5_init_creds_free(context
, ctx
);
2063 memset(buf
, 0, sizeof(buf
));
2068 * Get new credentials using keyblock.
2070 * @ingroup krb5_credential
2073 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2074 krb5_get_init_creds_keyblock(krb5_context context
,
2076 krb5_principal client
,
2077 krb5_keyblock
*keyblock
,
2078 krb5_deltat start_time
,
2079 const char *in_tkt_service
,
2080 krb5_get_init_creds_opt
*options
)
2082 krb5_init_creds_context ctx
;
2083 krb5_error_code ret
;
2085 memset(creds
, 0, sizeof(*creds
));
2087 ret
= krb5_init_creds_init(context
, client
, NULL
, NULL
, start_time
, options
, &ctx
);
2091 ret
= krb5_init_creds_set_service(context
, ctx
, in_tkt_service
);
2095 ret
= krb5_init_creds_set_keyblock(context
, ctx
, keyblock
);
2099 ret
= krb5_init_creds_get(context
, ctx
);
2102 process_last_request(context
, options
, ctx
);
2106 krb5_init_creds_get_creds(context
, ctx
, creds
);
2109 krb5_init_creds_free(context
, ctx
);
2115 * Get new credentials using keytab.
2117 * @ingroup krb5_credential
2120 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2121 krb5_get_init_creds_keytab(krb5_context context
,
2123 krb5_principal client
,
2125 krb5_deltat start_time
,
2126 const char *in_tkt_service
,
2127 krb5_get_init_creds_opt
*options
)
2129 krb5_init_creds_context ctx
;
2130 krb5_error_code ret
;
2132 memset(creds
, 0, sizeof(*creds
));
2134 ret
= krb5_init_creds_init(context
, client
, NULL
, NULL
, start_time
, options
, &ctx
);
2138 ret
= krb5_init_creds_set_service(context
, ctx
, in_tkt_service
);
2142 ret
= krb5_init_creds_set_keytab(context
, ctx
, keytab
);
2146 ret
= krb5_init_creds_get(context
, ctx
);
2148 process_last_request(context
, options
, ctx
);
2152 krb5_init_creds_get_creds(context
, ctx
, creds
);
2155 krb5_init_creds_free(context
, ctx
);