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"
41 typedef struct krb5_get_init_creds_ctx
{
44 krb5_addresses
*addrs
;
46 krb5_preauthtype
*pre_auth_types
;
55 /* password and keytab_data is freed on completion */
57 krb5_keytab_key_proc_args
*keytab_data
;
59 krb5_pointer
*keyseed
;
60 krb5_s2k_proc keyproc
;
62 krb5_get_init_creds_tristate req_pac
;
64 krb5_pk_init_ctx pk_init_ctx
;
68 unsigned change_password
:1;
73 #define USED_PKINIT_W2K 2
74 #define USED_ENC_TS_GUESS 4
75 #define USED_ENC_TS_INFO 8
80 EncKDCRepPart enc_part
;
82 krb5_prompter_fct prompter
;
85 struct pa_info_data
*ppaid
;
87 enum PA_FX_FAST_REQUEST_enum type
;
89 #define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 1
90 #define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 2
91 #define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4
92 #define KRB5_FAST_REPLY_REPLY_VERIFED 8
93 #define KRB5_FAST_STRONG 16
94 #define KRB5_FAST_EXPECTED 32 /* in exchange with KDC, fast was discovered */
95 #define KRB5_FAST_REQUIRED 64 /* fast required by action of caller */
96 #define KRB5_FAST_DISABLED 128
97 #define KRB5_FAST_AP_ARMOR_SERVICE 256
98 krb5_keyblock
*reply_key
;
99 krb5_ccache armor_ccache
;
100 krb5_principal armor_service
;
101 krb5_crypto armor_crypto
;
102 krb5_keyblock armor_key
;
103 krb5_keyblock
*strengthen_key
;
105 } krb5_get_init_creds_ctx
;
108 struct pa_info_data
{
111 krb5_data
*s2kparams
;
115 free_paid(krb5_context context
, struct pa_info_data
*ppaid
)
117 krb5_free_salt(context
, ppaid
->salt
);
118 if (ppaid
->s2kparams
)
119 krb5_free_data(context
, ppaid
->s2kparams
);
122 static krb5_error_code KRB5_CALLCONV
123 default_s2k_func(krb5_context context
, krb5_enctype type
,
124 krb5_const_pointer keyseed
,
125 krb5_salt salt
, krb5_data
*s2kparms
,
132 _krb5_debug(context
, 5, "krb5_get_init_creds: using default_s2k_func");
134 password
.data
= rk_UNCONST(keyseed
);
135 password
.length
= strlen(keyseed
);
139 krb5_data_zero(&opaque
);
141 *key
= malloc(sizeof(**key
));
144 ret
= krb5_string_to_key_data_salt_opaque(context
, type
, password
,
154 free_init_creds_ctx(krb5_context context
, krb5_init_creds_context ctx
)
158 if (ctx
->pre_auth_types
)
159 free (ctx
->pre_auth_types
);
160 if (ctx
->in_tkt_service
)
161 free(ctx
->in_tkt_service
);
162 if (ctx
->keytab_data
)
163 free(ctx
->keytab_data
);
165 memset(ctx
->password
, 0, strlen(ctx
->password
));
169 * FAST state (we don't close the armor_ccache because we might have
170 * to destroy it, and how would we know? also, the caller should
171 * take care of cleaning up the armor_ccache).
173 if (ctx
->fast_state
.armor_service
)
174 krb5_free_principal(context
, ctx
->fast_state
.armor_service
);
175 if (ctx
->fast_state
.armor_crypto
)
176 krb5_crypto_destroy(context
, ctx
->fast_state
.armor_crypto
);
177 if (ctx
->fast_state
.strengthen_key
)
178 krb5_free_keyblock(context
, ctx
->fast_state
.strengthen_key
);
179 krb5_free_keyblock_contents(context
, &ctx
->fast_state
.armor_key
);
181 krb5_data_free(&ctx
->req_buffer
);
182 krb5_free_cred_contents(context
, &ctx
->cred
);
183 free_METHOD_DATA(&ctx
->md
);
184 free_AS_REP(&ctx
->as_rep
);
185 free_EncKDCRepPart(&ctx
->enc_part
);
186 free_KRB_ERROR(&ctx
->error
);
187 free_AS_REQ(&ctx
->as_req
);
189 free_paid(context
, ctx
->ppaid
);
192 memset(ctx
, 0, sizeof(*ctx
));
196 get_config_time (krb5_context context
,
203 ret
= krb5_config_get_time (context
, NULL
,
210 ret
= krb5_config_get_time (context
, NULL
,
219 static krb5_error_code
220 init_cred (krb5_context context
,
222 krb5_principal client
,
223 krb5_deltat start_time
,
224 krb5_get_init_creds_opt
*options
)
230 krb5_timeofday (context
, &now
);
232 memset (cred
, 0, sizeof(*cred
));
235 krb5_copy_principal(context
, client
, &cred
->client
);
237 ret
= krb5_get_default_principal (context
,
244 cred
->times
.starttime
= now
+ start_time
;
246 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_TKT_LIFE
)
247 tmp
= options
->tkt_life
;
249 tmp
= KRB5_TKT_LIFETIME_DEFAULT
;
250 cred
->times
.endtime
= now
+ tmp
;
252 if ((options
->flags
& KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE
) &&
253 options
->renew_life
> 0) {
254 cred
->times
.renew_till
= now
+ options
->renew_life
;
260 krb5_free_cred_contents (context
, cred
);
265 * Print a message (str) to the user about the expiration in `lr'
269 report_expiration (krb5_context context
,
270 krb5_prompter_fct prompter
,
277 if (asprintf(&p
, "%s%s", str
, ctime(&now
)) < 0 || p
== NULL
)
279 (*prompter
)(context
, data
, NULL
, p
, 0, NULL
);
284 * Check the context, and in the case there is a expiration warning,
285 * use the prompter to print the warning.
287 * @param context A Kerberos 5 context.
288 * @param options An GIC options structure
289 * @param ctx The krb5_init_creds_context check for expiration.
293 krb5_process_last_request(krb5_context context
,
294 krb5_get_init_creds_opt
*options
,
295 krb5_init_creds_context ctx
)
297 krb5_const_realm realm
;
299 krb5_boolean reported
= FALSE
;
305 * First check if there is a API consumer.
308 realm
= krb5_principal_get_realm (context
, ctx
->cred
.client
);
309 lr
= &ctx
->enc_part
.last_req
;
311 if (options
&& options
->opt_private
&& options
->opt_private
->lr
.func
) {
312 krb5_last_req_entry
**lre
;
314 lre
= calloc(lr
->len
+ 1, sizeof(*lre
));
316 return krb5_enomem(context
);
317 for (i
= 0; i
< lr
->len
; i
++) {
318 lre
[i
] = calloc(1, sizeof(*lre
[i
]));
321 lre
[i
]->lr_type
= lr
->val
[i
].lr_type
;
322 lre
[i
]->value
= lr
->val
[i
].lr_value
;
325 (*options
->opt_private
->lr
.func
)(context
, lre
,
326 options
->opt_private
->lr
.ctx
);
328 for (i
= 0; i
< lr
->len
; i
++)
334 * Now check if we should prompt the user
337 if (ctx
->prompter
== NULL
)
340 krb5_timeofday (context
, &sec
);
342 t
= sec
+ get_config_time (context
,
347 for (i
= 0; i
< lr
->len
; ++i
) {
348 if (lr
->val
[i
].lr_value
<= t
) {
349 switch (lr
->val
[i
].lr_type
) {
351 report_expiration(context
, ctx
->prompter
,
353 "Your password will expire at ",
354 lr
->val
[i
].lr_value
);
357 case LR_ACCT_EXPTIME
:
358 report_expiration(context
, ctx
->prompter
,
360 "Your account will expire at ",
361 lr
->val
[i
].lr_value
);
371 && ctx
->enc_part
.key_expiration
372 && *ctx
->enc_part
.key_expiration
<= t
) {
373 report_expiration(context
, ctx
->prompter
,
375 "Your password/account will expire at ",
376 *ctx
->enc_part
.key_expiration
);
381 static krb5_addresses no_addrs
= { 0, NULL
};
383 static krb5_error_code
384 get_init_creds_common(krb5_context context
,
385 krb5_principal client
,
386 krb5_deltat start_time
,
387 krb5_get_init_creds_opt
*options
,
388 krb5_init_creds_context ctx
)
390 krb5_get_init_creds_opt
*default_opt
= NULL
;
392 krb5_enctype
*etypes
;
393 krb5_preauthtype
*pre_auth_types
;
395 memset(ctx
, 0, sizeof(*ctx
));
397 if (options
== NULL
) {
398 const char *realm
= krb5_principal_get_realm(context
, client
);
400 krb5_get_init_creds_opt_alloc (context
, &default_opt
);
401 options
= default_opt
;
402 krb5_get_init_creds_opt_set_default_flags(context
, NULL
, realm
, options
);
405 if (options
->opt_private
) {
406 if (options
->opt_private
->password
) {
407 ret
= krb5_init_creds_set_password(context
, ctx
,
408 options
->opt_private
->password
);
413 ctx
->keyproc
= options
->opt_private
->key_proc
;
414 ctx
->req_pac
= options
->opt_private
->req_pac
;
415 ctx
->pk_init_ctx
= options
->opt_private
->pk_init_ctx
;
416 ctx
->ic_flags
= options
->opt_private
->flags
;
418 ctx
->req_pac
= KRB5_INIT_CREDS_TRISTATE_UNSET
;
420 if (ctx
->keyproc
== NULL
)
421 ctx
->keyproc
= default_s2k_func
;
423 /* Enterprise name implicitly turns on canonicalize */
424 if ((ctx
->ic_flags
& KRB5_INIT_CREDS_CANONICALIZE
) ||
425 krb5_principal_get_type(context
, client
) == KRB5_NT_ENTERPRISE_PRINCIPAL
)
426 ctx
->flags
.canonicalize
= 1;
428 ctx
->pre_auth_types
= NULL
;
431 ctx
->pre_auth_types
= NULL
;
433 ret
= init_cred(context
, &ctx
->cred
, client
, start_time
, options
);
436 krb5_get_init_creds_opt_free(context
, default_opt
);
440 ret
= krb5_init_creds_set_service(context
, ctx
, NULL
);
444 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_FORWARDABLE
)
445 ctx
->flags
.forwardable
= options
->forwardable
;
447 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_PROXIABLE
)
448 ctx
->flags
.proxiable
= options
->proxiable
;
451 ctx
->flags
.postdated
= 1;
452 if (ctx
->cred
.times
.renew_till
)
453 ctx
->flags
.renewable
= 1;
454 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST
) {
455 ctx
->addrs
= options
->address_list
;
456 } else if (options
->opt_private
) {
457 switch (options
->opt_private
->addressless
) {
458 case KRB5_INIT_CREDS_TRISTATE_UNSET
:
459 #if KRB5_ADDRESSLESS_DEFAULT == TRUE
460 ctx
->addrs
= &no_addrs
;
465 case KRB5_INIT_CREDS_TRISTATE_FALSE
:
468 case KRB5_INIT_CREDS_TRISTATE_TRUE
:
469 ctx
->addrs
= &no_addrs
;
473 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST
) {
477 etypes
= malloc((options
->etype_list_length
+ 1)
478 * sizeof(krb5_enctype
));
479 if (etypes
== NULL
) {
480 ret
= krb5_enomem(context
);
483 memcpy (etypes
, options
->etype_list
,
484 options
->etype_list_length
* sizeof(krb5_enctype
));
485 etypes
[options
->etype_list_length
] = ETYPE_NULL
;
486 ctx
->etypes
= etypes
;
488 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST
) {
489 pre_auth_types
= malloc((options
->preauth_list_length
+ 1)
490 * sizeof(krb5_preauthtype
));
491 if (pre_auth_types
== NULL
) {
492 ret
= krb5_enomem(context
);
495 memcpy (pre_auth_types
, options
->preauth_list
,
496 options
->preauth_list_length
* sizeof(krb5_preauthtype
));
497 pre_auth_types
[options
->preauth_list_length
] = KRB5_PADATA_NONE
;
498 ctx
->pre_auth_types
= pre_auth_types
;
500 if (options
->flags
& KRB5_GET_INIT_CREDS_OPT_ANONYMOUS
)
501 ctx
->flags
.request_anonymous
= options
->anonymous
;
503 krb5_get_init_creds_opt_free(context
, default_opt
);
507 krb5_get_init_creds_opt_free(context
, default_opt
);
511 static krb5_error_code
512 change_password (krb5_context context
,
513 krb5_principal client
,
514 const char *password
,
517 krb5_prompter_fct prompter
,
519 krb5_get_init_creds_opt
*old_options
)
521 krb5_prompt prompts
[2];
524 char buf1
[BUFSIZ
], buf2
[BUFSIZ
];
525 krb5_data password_data
[2];
527 krb5_data result_code_string
;
528 krb5_data result_string
;
530 krb5_get_init_creds_opt
*options
;
532 memset (&cpw_cred
, 0, sizeof(cpw_cred
));
534 ret
= krb5_get_init_creds_opt_alloc(context
, &options
);
537 krb5_get_init_creds_opt_set_tkt_life (options
, 60);
538 krb5_get_init_creds_opt_set_forwardable (options
, FALSE
);
539 krb5_get_init_creds_opt_set_proxiable (options
, FALSE
);
540 if (old_options
&& old_options
->flags
& KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST
)
541 krb5_get_init_creds_opt_set_preauth_list (options
,
542 old_options
->preauth_list
,
543 old_options
->preauth_list_length
);
545 krb5_data_zero (&result_code_string
);
546 krb5_data_zero (&result_string
);
548 ret
= krb5_get_init_creds_password (context
,
557 krb5_get_init_creds_opt_free(context
, options
);
562 password_data
[0].data
= buf1
;
563 password_data
[0].length
= sizeof(buf1
);
565 prompts
[0].hidden
= 1;
566 prompts
[0].prompt
= "New password: ";
567 prompts
[0].reply
= &password_data
[0];
568 prompts
[0].type
= KRB5_PROMPT_TYPE_NEW_PASSWORD
;
570 password_data
[1].data
= buf2
;
571 password_data
[1].length
= sizeof(buf2
);
573 prompts
[1].hidden
= 1;
574 prompts
[1].prompt
= "Repeat new password: ";
575 prompts
[1].reply
= &password_data
[1];
576 prompts
[1].type
= KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN
;
578 ret
= (*prompter
) (context
, data
, NULL
, "Changing password",
581 memset (buf1
, 0, sizeof(buf1
));
582 memset (buf2
, 0, sizeof(buf2
));
586 if (strcmp (buf1
, buf2
) == 0)
588 memset (buf1
, 0, sizeof(buf1
));
589 memset (buf2
, 0, sizeof(buf2
));
592 ret
= krb5_set_password (context
,
601 if (asprintf(&p
, "%s: %.*s\n",
602 result_code
? "Error" : "Success",
603 (int)result_string
.length
,
604 result_string
.length
> 0 ? (char*)result_string
.data
: "") < 0)
610 /* return the result */
611 (*prompter
) (context
, data
, NULL
, p
, 0, NULL
);
614 if (result_code
== 0) {
615 strlcpy (newpw
, buf1
, newpw_sz
);
619 krb5_set_error_message(context
, ret
,
620 N_("failed changing password", ""));
624 memset (buf1
, 0, sizeof(buf1
));
625 memset (buf2
, 0, sizeof(buf2
));
626 krb5_data_free (&result_string
);
627 krb5_data_free (&result_code_string
);
628 krb5_free_cred_contents (context
, &cpw_cred
);
633 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
634 krb5_keyblock_key_proc (krb5_context context
,
637 krb5_const_pointer keyseed
,
640 return krb5_copy_keyblock (context
, keyseed
, key
);
647 static krb5_error_code
648 init_as_req (krb5_context context
,
650 const krb5_creds
*creds
,
651 const krb5_addresses
*addrs
,
652 const krb5_enctype
*etypes
,
657 memset(a
, 0, sizeof(*a
));
660 a
->msg_type
= krb_as_req
;
661 a
->req_body
.kdc_options
= opts
;
662 a
->req_body
.cname
= malloc(sizeof(*a
->req_body
.cname
));
663 if (a
->req_body
.cname
== NULL
) {
664 ret
= krb5_enomem(context
);
667 a
->req_body
.sname
= malloc(sizeof(*a
->req_body
.sname
));
668 if (a
->req_body
.sname
== NULL
) {
669 ret
= krb5_enomem(context
);
673 ret
= _krb5_principal2principalname (a
->req_body
.cname
, creds
->client
);
676 ret
= copy_Realm(&creds
->client
->realm
, &a
->req_body
.realm
);
680 ret
= _krb5_principal2principalname (a
->req_body
.sname
, creds
->server
);
684 if(creds
->times
.starttime
) {
685 a
->req_body
.from
= malloc(sizeof(*a
->req_body
.from
));
686 if (a
->req_body
.from
== NULL
) {
687 ret
= krb5_enomem(context
);
690 *a
->req_body
.from
= creds
->times
.starttime
;
692 if(creds
->times
.endtime
){
693 ALLOC(a
->req_body
.till
, 1);
694 *a
->req_body
.till
= creds
->times
.endtime
;
696 if(creds
->times
.renew_till
){
697 a
->req_body
.rtime
= malloc(sizeof(*a
->req_body
.rtime
));
698 if (a
->req_body
.rtime
== NULL
) {
699 ret
= krb5_enomem(context
);
702 *a
->req_body
.rtime
= creds
->times
.renew_till
;
704 a
->req_body
.nonce
= 0;
705 ret
= _krb5_init_etype(context
,
707 &a
->req_body
.etype
.len
,
708 &a
->req_body
.etype
.val
,
714 * This means no addresses
717 if (addrs
&& addrs
->len
== 0) {
718 a
->req_body
.addresses
= NULL
;
720 a
->req_body
.addresses
= malloc(sizeof(*a
->req_body
.addresses
));
721 if (a
->req_body
.addresses
== NULL
) {
722 ret
= krb5_enomem(context
);
727 ret
= krb5_copy_addresses(context
, addrs
, a
->req_body
.addresses
);
729 ret
= krb5_get_all_client_addrs (context
, a
->req_body
.addresses
);
730 if(ret
== 0 && a
->req_body
.addresses
->len
== 0) {
731 free(a
->req_body
.addresses
);
732 a
->req_body
.addresses
= NULL
;
739 a
->req_body
.enc_authorization_data
= NULL
;
740 a
->req_body
.additional_tickets
= NULL
;
747 memset(a
, 0, sizeof(*a
));
752 static krb5_error_code
753 set_paid(struct pa_info_data
*paid
, krb5_context context
,
755 krb5_salttype salttype
, void *salt_string
, size_t salt_len
,
756 krb5_data
*s2kparams
)
759 paid
->salt
.salttype
= salttype
;
760 paid
->salt
.saltvalue
.data
= malloc(salt_len
+ 1);
761 if (paid
->salt
.saltvalue
.data
== NULL
) {
762 krb5_clear_error_message(context
);
765 memcpy(paid
->salt
.saltvalue
.data
, salt_string
, salt_len
);
766 ((char *)paid
->salt
.saltvalue
.data
)[salt_len
] = '\0';
767 paid
->salt
.saltvalue
.length
= salt_len
;
771 ret
= krb5_copy_data(context
, s2kparams
, &paid
->s2kparams
);
773 krb5_clear_error_message(context
);
774 krb5_free_salt(context
, paid
->salt
);
778 paid
->s2kparams
= NULL
;
783 static struct pa_info_data
*
784 pa_etype_info2(krb5_context context
,
785 const krb5_principal client
,
787 struct pa_info_data
*paid
,
788 heim_octet_string
*data
)
795 memset(&e
, 0, sizeof(e
));
796 ret
= decode_ETYPE_INFO2(data
->data
, data
->length
, &e
, &sz
);
801 for (j
= 0; j
< asreq
->req_body
.etype
.len
; j
++) {
802 for (i
= 0; i
< e
.len
; i
++) {
803 if (asreq
->req_body
.etype
.val
[j
] == e
.val
[i
].etype
) {
805 if (e
.val
[i
].salt
== NULL
)
806 ret
= krb5_get_pw_salt(context
, client
, &salt
);
808 salt
.saltvalue
.data
= *e
.val
[i
].salt
;
809 salt
.saltvalue
.length
= strlen(*e
.val
[i
].salt
);
813 ret
= set_paid(paid
, context
, e
.val
[i
].etype
,
816 salt
.saltvalue
.length
,
818 if (e
.val
[i
].salt
== NULL
)
819 krb5_free_salt(context
, salt
);
821 free_ETYPE_INFO2(&e
);
828 free_ETYPE_INFO2(&e
);
832 static struct pa_info_data
*
833 pa_etype_info(krb5_context context
,
834 const krb5_principal client
,
836 struct pa_info_data
*paid
,
837 heim_octet_string
*data
)
844 memset(&e
, 0, sizeof(e
));
845 ret
= decode_ETYPE_INFO(data
->data
, data
->length
, &e
, &sz
);
850 for (j
= 0; j
< asreq
->req_body
.etype
.len
; j
++) {
851 for (i
= 0; i
< e
.len
; i
++) {
852 if (asreq
->req_body
.etype
.val
[j
] == e
.val
[i
].etype
) {
854 salt
.salttype
= KRB5_PW_SALT
;
855 if (e
.val
[i
].salt
== NULL
)
856 ret
= krb5_get_pw_salt(context
, client
, &salt
);
858 salt
.saltvalue
= *e
.val
[i
].salt
;
861 if (e
.val
[i
].salttype
)
862 salt
.salttype
= *e
.val
[i
].salttype
;
864 ret
= set_paid(paid
, context
, e
.val
[i
].etype
,
867 salt
.saltvalue
.length
,
869 if (e
.val
[i
].salt
== NULL
)
870 krb5_free_salt(context
, salt
);
884 static struct pa_info_data
*
885 pa_pw_or_afs3_salt(krb5_context context
,
886 const krb5_principal client
,
888 struct pa_info_data
*paid
,
889 heim_octet_string
*data
)
892 if (paid
->etype
== KRB5_ENCTYPE_NULL
)
894 ret
= set_paid(paid
, context
,
907 krb5_preauthtype type
;
908 struct pa_info_data
*(*salt_info
)(krb5_context
,
909 const krb5_principal
,
911 struct pa_info_data
*,
912 heim_octet_string
*);
915 static struct pa_info pa_prefs
[] = {
916 { KRB5_PADATA_ETYPE_INFO2
, pa_etype_info2
},
917 { KRB5_PADATA_ETYPE_INFO
, pa_etype_info
},
918 { KRB5_PADATA_PW_SALT
, pa_pw_or_afs3_salt
},
919 { KRB5_PADATA_AFS3_SALT
, pa_pw_or_afs3_salt
}
923 find_pa_data(const METHOD_DATA
*md
, unsigned type
)
928 for (i
= 0; i
< md
->len
; i
++)
929 if (md
->val
[i
].padata_type
== type
)
934 static struct pa_info_data
*
935 process_pa_info(krb5_context context
,
936 const krb5_principal client
,
938 struct pa_info_data
*paid
,
941 struct pa_info_data
*p
= NULL
;
944 for (i
= 0; p
== NULL
&& i
< sizeof(pa_prefs
)/sizeof(pa_prefs
[0]); i
++) {
945 PA_DATA
*pa
= find_pa_data(md
, pa_prefs
[i
].type
);
948 paid
->salt
.salttype
= (krb5_salttype
)pa_prefs
[i
].type
;
949 p
= (*pa_prefs
[i
].salt_info
)(context
, client
, asreq
,
950 paid
, &pa
->padata_value
);
955 static krb5_error_code
956 make_pa_enc_timestamp(krb5_context context
, METHOD_DATA
*md
,
957 krb5_enctype etype
, krb5_keyblock
*key
)
963 EncryptedData encdata
;
969 krb5_us_timeofday (context
, &p
.patimestamp
, &usec
);
973 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC
, buf
, buf_size
, &p
, &len
, ret
);
977 krb5_abortx(context
, "internal error in ASN.1 encoder");
979 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
984 ret
= krb5_encrypt_EncryptedData(context
,
986 KRB5_KU_PA_ENC_TIMESTAMP
,
992 krb5_crypto_destroy(context
, crypto
);
996 ASN1_MALLOC_ENCODE(EncryptedData
, buf
, buf_size
, &encdata
, &len
, ret
);
997 free_EncryptedData(&encdata
);
1001 krb5_abortx(context
, "internal error in ASN.1 encoder");
1003 ret
= krb5_padata_add(context
, md
, KRB5_PADATA_ENC_TIMESTAMP
, buf
, len
);
1009 static krb5_error_code
1010 add_enc_ts_padata(krb5_context context
,
1012 krb5_principal client
,
1013 krb5_s2k_proc keyproc
,
1014 krb5_const_pointer keyseed
,
1015 krb5_enctype
*enctypes
,
1018 krb5_data
*s2kparams
)
1020 krb5_error_code ret
;
1026 /* default to standard salt */
1027 ret
= krb5_get_pw_salt (context
, client
, &salt2
);
1033 enctypes
= context
->etypes
;
1035 for (ep
= enctypes
; *ep
!= (krb5_enctype
)ETYPE_NULL
; ep
++)
1039 for (i
= 0; i
< netypes
; ++i
) {
1042 _krb5_debug(context
, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes
[i
]);
1044 ret
= (*keyproc
)(context
, enctypes
[i
], keyseed
,
1045 *salt
, s2kparams
, &key
);
1048 ret
= make_pa_enc_timestamp (context
, md
, enctypes
[i
], key
);
1049 krb5_free_keyblock (context
, key
);
1054 krb5_free_salt(context
, salt2
);
1058 static krb5_error_code
1059 pa_data_to_md_ts_enc(krb5_context context
,
1061 const krb5_principal client
,
1062 krb5_get_init_creds_ctx
*ctx
,
1063 struct pa_info_data
*ppaid
,
1066 if (ctx
->keyproc
== NULL
|| ctx
->keyseed
== NULL
)
1070 add_enc_ts_padata(context
, md
, client
,
1071 ctx
->keyproc
, ctx
->keyseed
,
1073 &ppaid
->salt
, ppaid
->s2kparams
);
1077 _krb5_debug(context
, 5, "krb5_get_init_creds: pa-info not found, guessing salt");
1079 /* make a v5 salted pa-data */
1080 add_enc_ts_padata(context
, md
, client
,
1081 ctx
->keyproc
, ctx
->keyseed
,
1082 a
->req_body
.etype
.val
, a
->req_body
.etype
.len
,
1085 /* make a v4 salted pa-data */
1086 salt
.salttype
= KRB5_PW_SALT
;
1087 krb5_data_zero(&salt
.saltvalue
);
1088 add_enc_ts_padata(context
, md
, client
,
1089 ctx
->keyproc
, ctx
->keyseed
,
1090 a
->req_body
.etype
.val
, a
->req_body
.etype
.len
,
1096 static krb5_error_code
1097 pa_data_to_key_plain(krb5_context context
,
1098 const krb5_principal client
,
1099 krb5_get_init_creds_ctx
*ctx
,
1101 krb5_data
*s2kparams
,
1103 krb5_keyblock
**key
)
1105 krb5_error_code ret
;
1107 ret
= (*ctx
->keyproc
)(context
, etype
, ctx
->keyseed
,
1108 salt
, s2kparams
, key
);
1113 static krb5_error_code
1114 pa_data_to_md_pkinit(krb5_context context
,
1116 const krb5_principal client
,
1118 krb5_get_init_creds_ctx
*ctx
,
1121 if (ctx
->pk_init_ctx
== NULL
)
1124 return _krb5_pk_mk_padata(context
,
1132 krb5_set_error_message(context
, EINVAL
,
1133 N_("no support for PKINIT compiled in", ""));
1138 static krb5_error_code
1139 pa_data_add_pac_request(krb5_context context
,
1140 krb5_get_init_creds_ctx
*ctx
,
1143 size_t len
= 0, length
;
1144 krb5_error_code ret
;
1148 switch (ctx
->req_pac
) {
1149 case KRB5_INIT_CREDS_TRISTATE_UNSET
:
1150 return 0; /* don't bother */
1151 case KRB5_INIT_CREDS_TRISTATE_TRUE
:
1152 req
.include_pac
= 1;
1154 case KRB5_INIT_CREDS_TRISTATE_FALSE
:
1155 req
.include_pac
= 0;
1158 ASN1_MALLOC_ENCODE(PA_PAC_REQUEST
, buf
, length
,
1163 krb5_abortx(context
, "internal error in ASN.1 encoder");
1165 ret
= krb5_padata_add(context
, md
, KRB5_PADATA_PA_PAC_REQUEST
, buf
, len
);
1173 * Assumes caller always will free `out_md', even on error.
1176 static krb5_error_code
1177 process_pa_data_to_md(krb5_context context
,
1178 const krb5_creds
*creds
,
1180 krb5_get_init_creds_ctx
*ctx
,
1182 METHOD_DATA
**out_md
,
1183 krb5_prompter_fct prompter
,
1184 void *prompter_data
)
1186 krb5_error_code ret
;
1189 if (*out_md
== NULL
)
1190 return krb5_enomem(context
);
1193 (*out_md
)->val
= NULL
;
1195 if (_krb5_have_debug(context
, 5)) {
1197 _krb5_debug(context
, 5, "KDC send %d patypes", in_md
->len
);
1198 for (i
= 0; i
< in_md
->len
; i
++)
1199 _krb5_debug(context
, 5, "KDC send PA-DATA type: %d", in_md
->val
[i
].padata_type
);
1203 * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
1204 * need to expose our password protecting our PKCS12 key.
1207 if (ctx
->pk_init_ctx
) {
1209 _krb5_debug(context
, 5, "krb5_get_init_creds: "
1210 "prepareing PKINIT padata (%s)",
1211 (ctx
->used_pa_types
& USED_PKINIT_W2K
) ? "win2k" : "ietf");
1213 if (ctx
->used_pa_types
& USED_PKINIT_W2K
) {
1214 krb5_set_error_message(context
, KRB5_GET_IN_TKT_LOOP
,
1215 "Already tried pkinit, looping");
1216 return KRB5_GET_IN_TKT_LOOP
;
1219 ret
= pa_data_to_md_pkinit(context
, a
, creds
->client
,
1220 (ctx
->used_pa_types
& USED_PKINIT
),
1225 if (ctx
->used_pa_types
& USED_PKINIT
)
1226 ctx
->used_pa_types
|= USED_PKINIT_W2K
;
1228 ctx
->used_pa_types
|= USED_PKINIT
;
1230 } else if (in_md
->len
!= 0) {
1231 struct pa_info_data
*paid
, *ppaid
;
1234 paid
= calloc(1, sizeof(*paid
));
1236 return krb5_enomem(context
);
1238 paid
->etype
= KRB5_ENCTYPE_NULL
;
1239 ppaid
= process_pa_info(context
, creds
->client
, a
, paid
, in_md
);
1242 flag
= USED_ENC_TS_INFO
;
1244 flag
= USED_ENC_TS_GUESS
;
1246 if (ctx
->used_pa_types
& flag
) {
1248 free_paid(context
, ppaid
);
1250 krb5_set_error_message(context
, KRB5_GET_IN_TKT_LOOP
,
1251 "Already tried ENC-TS-%s, looping",
1252 flag
== USED_ENC_TS_INFO
? "info" : "guess");
1253 return KRB5_GET_IN_TKT_LOOP
;
1256 pa_data_to_md_ts_enc(context
, a
, creds
->client
, ctx
, ppaid
, *out_md
);
1258 ctx
->used_pa_types
|= flag
;
1262 free_paid(context
, ctx
->ppaid
);
1270 pa_data_add_pac_request(context
, ctx
, *out_md
);
1272 if ((ctx
->fast_state
.flags
& KRB5_FAST_DISABLED
) == 0) {
1273 ret
= krb5_padata_add(context
, *out_md
, KRB5_PADATA_REQ_ENC_PA_REP
, NULL
, 0);
1278 if ((*out_md
)->len
== 0) {
1286 static krb5_error_code
1287 process_pa_data_to_key(krb5_context context
,
1288 krb5_get_init_creds_ctx
*ctx
,
1292 const krb5_krbhst_info
*hi
,
1293 krb5_keyblock
**key
)
1295 struct pa_info_data paid
, *ppaid
= NULL
;
1296 krb5_error_code ret
;
1300 memset(&paid
, 0, sizeof(paid
));
1302 etype
= rep
->enc_part
.etype
;
1306 ppaid
= process_pa_info(context
, creds
->client
, a
, &paid
,
1311 if (ppaid
== NULL
) {
1312 ret
= krb5_get_pw_salt (context
, creds
->client
, &paid
.salt
);
1316 paid
.s2kparams
= NULL
;
1323 pa
= krb5_find_padata(rep
->padata
->val
,
1325 KRB5_PADATA_PK_AS_REP
,
1329 pa
= krb5_find_padata(rep
->padata
->val
,
1331 KRB5_PADATA_PK_AS_REP_19
,
1335 if (pa
&& ctx
->pk_init_ctx
) {
1337 _krb5_debug(context
, 5, "krb5_get_init_creds: using PKINIT");
1339 ret
= _krb5_pk_rd_pa_reply(context
,
1350 krb5_set_error_message(context
, ret
, N_("no support for PKINIT compiled in", ""));
1352 } else if (ctx
->keyseed
) {
1353 _krb5_debug(context
, 5, "krb5_get_init_creds: using keyproc");
1354 ret
= pa_data_to_key_plain(context
, creds
->client
, ctx
,
1355 ppaid
->salt
, ppaid
->s2kparams
, etype
, key
);
1358 krb5_set_error_message(context
, ret
, N_("No usable pa data type", ""));
1361 free_paid(context
, &paid
);
1366 * Start a new context to get a new initial credential.
1368 * @param context A Kerberos 5 context.
1369 * @param client The Kerberos principal to get the credential for, if
1370 * NULL is given, the default principal is used as determined by
1371 * krb5_get_default_principal().
1373 * @param prompter_data
1374 * @param start_time the time the ticket should start to be valid or 0 for now.
1375 * @param options a options structure, can be NULL for default options.
1376 * @param rctx A new allocated free with krb5_init_creds_free().
1378 * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message().
1380 * @ingroup krb5_credential
1383 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1384 krb5_init_creds_init(krb5_context context
,
1385 krb5_principal client
,
1386 krb5_prompter_fct prompter
,
1387 void *prompter_data
,
1388 krb5_deltat start_time
,
1389 krb5_get_init_creds_opt
*options
,
1390 krb5_init_creds_context
*rctx
)
1392 krb5_init_creds_context ctx
;
1393 krb5_error_code ret
;
1397 ctx
= calloc(1, sizeof(*ctx
));
1399 return krb5_enomem(context
);
1401 ret
= get_init_creds_common(context
, client
, start_time
, options
, ctx
);
1407 /* Set a new nonce. */
1408 krb5_generate_random_block (&ctx
->nonce
, sizeof(ctx
->nonce
));
1409 ctx
->nonce
&= 0x7fffffff;
1410 /* XXX these just needs to be the same when using Windows PK-INIT */
1411 ctx
->pk_nonce
= ctx
->nonce
;
1413 ctx
->prompter
= prompter
;
1414 ctx
->prompter_data
= prompter_data
;
1422 * Sets the service that the is requested. This call is only neede for
1423 * special initial tickets, by default the a krbtgt is fetched in the default realm.
1425 * @param context a Kerberos 5 context.
1426 * @param ctx a krb5_init_creds_context context.
1427 * @param service the service given as a string, for example
1428 * "kadmind/admin". If NULL, the default krbtgt in the clients
1431 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1432 * @ingroup krb5_credential
1435 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1436 krb5_init_creds_set_service(krb5_context context
,
1437 krb5_init_creds_context ctx
,
1438 const char *service
)
1440 krb5_const_realm client_realm
;
1441 krb5_principal principal
;
1442 krb5_error_code ret
;
1444 client_realm
= krb5_principal_get_realm (context
, ctx
->cred
.client
);
1447 ret
= krb5_parse_name (context
, service
, &principal
);
1450 krb5_principal_set_realm (context
, principal
, client_realm
);
1452 ret
= krb5_make_principal(context
, &principal
,
1453 client_realm
, KRB5_TGS_NAME
, client_realm
,
1460 * This is for Windows RODC that are picky about what name type
1461 * the server principal have, and the really strange part is that
1462 * they are picky about the AS-REQ name type and not the TGS-REQ
1466 if (krb5_principal_is_krbtgt(context
, principal
))
1467 krb5_principal_set_type(context
, principal
, KRB5_NT_SRV_INST
);
1469 krb5_free_principal(context
, ctx
->cred
.server
);
1470 ctx
->cred
.server
= principal
;
1476 * Sets the password that will use for the request.
1478 * @param context a Kerberos 5 context.
1479 * @param ctx ctx krb5_init_creds_context context.
1480 * @param password the password to use.
1482 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1483 * @ingroup krb5_credential
1486 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1487 krb5_init_creds_set_password(krb5_context context
,
1488 krb5_init_creds_context ctx
,
1489 const char *password
)
1491 if (ctx
->password
) {
1492 memset(ctx
->password
, 0, strlen(ctx
->password
));
1493 free(ctx
->password
);
1496 ctx
->password
= strdup(password
);
1497 if (ctx
->password
== NULL
)
1498 return krb5_enomem(context
);
1499 ctx
->keyseed
= (void *) ctx
->password
;
1501 ctx
->keyseed
= NULL
;
1502 ctx
->password
= NULL
;
1508 static krb5_error_code KRB5_CALLCONV
1509 keytab_key_proc(krb5_context context
, krb5_enctype enctype
,
1510 krb5_const_pointer keyseed
,
1511 krb5_salt salt
, krb5_data
*s2kparms
,
1512 krb5_keyblock
**key
)
1514 krb5_keytab_key_proc_args
*args
= rk_UNCONST(keyseed
);
1515 krb5_keytab keytab
= args
->keytab
;
1516 krb5_principal principal
= args
->principal
;
1517 krb5_error_code ret
;
1518 krb5_keytab real_keytab
;
1519 krb5_keytab_entry entry
;
1522 krb5_kt_default(context
, &real_keytab
);
1524 real_keytab
= keytab
;
1526 ret
= krb5_kt_get_entry (context
, real_keytab
, principal
,
1527 0, enctype
, &entry
);
1530 krb5_kt_close (context
, real_keytab
);
1535 ret
= krb5_copy_keyblock (context
, &entry
.keyblock
, key
);
1536 krb5_kt_free_entry(context
, &entry
);
1542 * Set the keytab to use for authentication.
1544 * @param context a Kerberos 5 context.
1545 * @param ctx ctx krb5_init_creds_context context.
1546 * @param keytab the keytab to read the key from.
1548 * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1549 * @ingroup krb5_credential
1552 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1553 krb5_init_creds_set_keytab(krb5_context context
,
1554 krb5_init_creds_context ctx
,
1557 krb5_keytab_key_proc_args
*a
;
1558 krb5_keytab_entry entry
;
1559 krb5_kt_cursor cursor
;
1560 krb5_enctype
*etypes
= NULL
;
1561 krb5_error_code ret
;
1563 int kvno
= 0, found
= 0;
1565 a
= malloc(sizeof(*a
));
1567 return krb5_enomem(context
);
1569 a
->principal
= ctx
->cred
.client
;
1572 ctx
->keytab_data
= a
;
1573 ctx
->keyseed
= (void *)a
;
1574 ctx
->keyproc
= keytab_key_proc
;
1577 * We need to the KDC what enctypes we support for this keytab,
1578 * esp if the keytab is really a password based entry, then the
1579 * KDC might have more enctypes in the database then what we have
1583 ret
= krb5_kt_start_seq_get(context
, keytab
, &cursor
);
1587 while(krb5_kt_next_entry(context
, keytab
, &entry
, &cursor
) == 0){
1590 if (!krb5_principal_compare(context
, entry
.principal
, ctx
->cred
.client
))
1595 /* check if we ahve this kvno already */
1596 if (entry
.vno
> kvno
) {
1597 /* remove old list of etype */
1603 } else if (entry
.vno
!= kvno
)
1606 /* check if enctype is supported */
1607 if (krb5_enctype_valid(context
, entry
.keyblock
.keytype
) != 0)
1610 /* add enctype to supported list */
1611 ptr
= realloc(etypes
, sizeof(etypes
[0]) * (netypes
+ 2));
1614 ret
= krb5_enomem(context
);
1619 etypes
[netypes
] = entry
.keyblock
.keytype
;
1620 etypes
[netypes
+ 1] = ETYPE_NULL
;
1623 krb5_kt_free_entry(context
, &entry
);
1625 krb5_kt_end_seq_get(context
, keytab
, &cursor
);
1630 ctx
->etypes
= etypes
;
1636 ret
= KRB5_KT_NOTFOUND
;
1637 _krb5_kt_principal_not_found(context
, ret
, keytab
, ctx
->cred
.client
, 0, 0);
1643 static krb5_error_code KRB5_CALLCONV
1644 keyblock_key_proc(krb5_context context
, krb5_enctype enctype
,
1645 krb5_const_pointer keyseed
,
1646 krb5_salt salt
, krb5_data
*s2kparms
,
1647 krb5_keyblock
**key
)
1649 return krb5_copy_keyblock (context
, keyseed
, key
);
1652 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1653 krb5_init_creds_set_keyblock(krb5_context context
,
1654 krb5_init_creds_context ctx
,
1655 krb5_keyblock
*keyblock
)
1657 ctx
->keyseed
= (void *)keyblock
;
1658 ctx
->keyproc
= keyblock_key_proc
;
1663 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1664 krb5_init_creds_set_fast_ccache(krb5_context context
,
1665 krb5_init_creds_context ctx
,
1666 krb5_ccache fast_ccache
)
1668 ctx
->fast_state
.armor_ccache
= fast_ccache
;
1669 ctx
->fast_state
.flags
|= KRB5_FAST_REQUIRED
;
1673 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1674 krb5_init_creds_set_fast_ap_armor_service(krb5_context context
,
1675 krb5_init_creds_context ctx
,
1676 krb5_const_principal armor_service
)
1678 krb5_error_code ret
;
1680 if (ctx
->fast_state
.armor_service
)
1681 krb5_free_principal(context
, ctx
->fast_state
.armor_service
);
1682 if (armor_service
) {
1683 ret
= krb5_copy_principal(context
, armor_service
, &ctx
->fast_state
.armor_service
);
1687 ctx
->fast_state
.armor_service
= NULL
;
1689 ctx
->fast_state
.flags
|= KRB5_FAST_REQUIRED
| KRB5_FAST_AP_ARMOR_SERVICE
;
1697 static krb5_error_code
1698 check_fast(krb5_context context
, struct fast_state
*state
)
1700 if (state
->flags
& KRB5_FAST_EXPECTED
) {
1701 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
1702 "Expected FAST, but no FAST "
1703 "was in the response from the KDC");
1704 return KRB5KRB_AP_ERR_MODIFIED
;
1710 static krb5_error_code
1711 fast_unwrap_as_rep(krb5_context context
, int32_t nonce
,
1712 krb5_data
*chksumdata
,
1713 struct fast_state
*state
, AS_REP
*rep
)
1715 PA_FX_FAST_REPLY fxfastrep
;
1716 KrbFastResponse fastrep
;
1717 krb5_error_code ret
;
1721 if (state
->armor_crypto
== NULL
|| rep
->padata
== NULL
)
1722 return check_fast(context
, state
);
1724 /* find PA_FX_FAST_REPLY */
1726 pa
= krb5_find_padata(rep
->padata
->val
, rep
->padata
->len
,
1727 KRB5_PADATA_FX_FAST
, &idx
);
1729 return check_fast(context
, state
);
1731 memset(&fxfastrep
, 0, sizeof(fxfastrep
));
1732 memset(&fastrep
, 0, sizeof(fastrep
));
1734 ret
= decode_PA_FX_FAST_REPLY(pa
->padata_value
.data
, pa
->padata_value
.length
, &fxfastrep
, NULL
);
1738 if (fxfastrep
.element
== choice_PA_FX_FAST_REPLY_armored_data
) {
1740 ret
= krb5_decrypt_EncryptedData(context
,
1741 state
->armor_crypto
,
1743 &fxfastrep
.u
.armored_data
.enc_fast_rep
,
1748 ret
= decode_KrbFastResponse(data
.data
, data
.length
, &fastrep
, NULL
);
1749 krb5_data_free(&data
);
1754 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
1758 free_METHOD_DATA(rep
->padata
);
1759 ret
= copy_METHOD_DATA(&fastrep
.padata
, rep
->padata
);
1763 if (fastrep
.strengthen_key
) {
1764 if (state
->strengthen_key
)
1765 krb5_free_keyblock(context
, state
->strengthen_key
);
1767 ret
= krb5_copy_keyblock(context
, fastrep
.strengthen_key
, &state
->strengthen_key
);
1772 if (nonce
!= fastrep
.nonce
) {
1773 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
1776 if (fastrep
.finished
) {
1777 PrincipalName cname
;
1778 krb5_realm crealm
= NULL
;
1780 if (chksumdata
== NULL
) {
1781 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
1785 ret
= krb5_verify_checksum(context
, state
->armor_crypto
,
1786 KRB5_KU_FAST_FINISHED
,
1787 chksumdata
->data
, chksumdata
->length
,
1788 &fastrep
.finished
->ticket_checksum
);
1793 ret
= copy_Realm(&fastrep
.finished
->crealm
, &crealm
);
1796 free_Realm(&rep
->crealm
);
1797 rep
->crealm
= crealm
;
1799 ret
= copy_PrincipalName(&fastrep
.finished
->cname
, &cname
);
1802 free_PrincipalName(&rep
->cname
);
1805 #if 0 /* store authenticated checksum as kdc-offset */
1806 fastrep
->finished
.timestamp
;
1807 fastrep
->finished
.usec
= 0;
1810 } else if (chksumdata
) {
1811 /* expected fastrep.finish but didn't get it */
1812 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
1816 free_PA_FX_FAST_REPLY(&fxfastrep
);
1821 static krb5_error_code
1822 fast_unwrap_error(krb5_context context
, struct fast_state
*state
, KRB_ERROR
*error
)
1824 if (state
->armor_crypto
== NULL
)
1825 return check_fast(context
, state
);
1831 _krb5_make_fast_ap_fxarmor(krb5_context context
,
1832 krb5_ccache armor_ccache
,
1833 krb5_data
*armor_value
,
1834 krb5_keyblock
*armor_key
,
1835 krb5_crypto
*armor_crypto
)
1837 krb5_auth_context auth_context
= NULL
;
1838 krb5_creds cred
, *credp
= NULL
;
1839 krb5_error_code ret
;
1842 krb5_data_zero(&empty
);
1844 memset(&cred
, 0, sizeof(cred
));
1846 ret
= krb5_auth_con_init (context
, &auth_context
);
1850 ret
= krb5_cc_get_principal(context
, armor_ccache
, &cred
.client
);
1854 ret
= krb5_make_principal(context
, &cred
.server
,
1860 krb5_free_principal(context
, cred
.client
);
1864 ret
= krb5_get_credentials(context
, 0, armor_ccache
, &cred
, &credp
);
1865 krb5_free_principal(context
, cred
.server
);
1866 krb5_free_principal(context
, cred
.client
);
1870 ret
= krb5_auth_con_add_AuthorizationData(context
, auth_context
, KRB5_PADATA_FX_FAST_ARMOR
, &empty
);
1874 ret
= krb5_mk_req_extended(context
,
1880 krb5_free_creds(context
, credp
);
1884 ret
= _krb5_fast_armor_key(context
,
1885 auth_context
->local_subkey
,
1886 auth_context
->keyblock
,
1897 static heim_base_once_t armor_service_once
= HEIM_BASE_ONCE_INIT
;
1898 static heim_ipc armor_service
= NULL
;
1901 fast_armor_init_ipc(void *ctx
)
1903 heim_ipc
*ipc
= ctx
;
1904 heim_ipc_init_context("ANY:org.h5l.armor-service", ipc
);
1909 static krb5_error_code
1910 make_fast_ap_fxarmor(krb5_context context
,
1911 struct fast_state
*state
,
1913 KrbFastArmor
**armor
)
1915 KrbFastArmor
*fxarmor
= NULL
;
1916 krb5_error_code ret
;
1918 if (state
->armor_crypto
)
1919 krb5_crypto_destroy(context
, state
->armor_crypto
);
1920 krb5_free_keyblock_contents(context
, &state
->armor_key
);
1924 if (fxarmor
== NULL
) {
1929 if (state
->flags
& KRB5_FAST_AP_ARMOR_SERVICE
) {
1931 krb5_set_error_message(context
, ENOTSUP
, "Fast armor IPC service not supportted yet on Windows");
1934 KERB_ARMOR_SERVICE_REPLY msg
;
1935 krb5_data request
, reply
;
1937 heim_base_once_f(&armor_service_once
, &armor_service
, fast_armor_init_ipc
);
1938 if (armor_service
== NULL
) {
1939 krb5_set_error_message(context
, ENOENT
, "Failed to open fast armor service");
1943 krb5_data_zero(&reply
);
1945 request
.data
= rk_UNCONST(realm
);
1946 request
.length
= strlen(realm
);
1948 ret
= heim_ipc_call(armor_service
, &request
, &reply
, NULL
);
1951 krb5_set_error_message(context
, ret
, "Failed to get armor service credential");
1955 ret
= decode_KERB_ARMOR_SERVICE_REPLY(reply
.data
, reply
.length
, &msg
, NULL
);
1956 krb5_data_free(&reply
);
1960 ret
= copy_KrbFastArmor(fxarmor
, &msg
.armor
);
1962 free_KERB_ARMOR_SERVICE_REPLY(&msg
);
1966 ret
= krb5_copy_keyblock_contents(context
, &msg
.armor_key
, &state
->armor_key
);
1967 free_KERB_ARMOR_SERVICE_REPLY(&msg
);
1971 ret
= krb5_crypto_init(context
, &state
->armor_key
, 0, &state
->armor_crypto
);
1977 fxarmor
->armor_type
= 1;
1979 ret
= _krb5_make_fast_ap_fxarmor(context
,
1980 state
->armor_ccache
,
1981 &fxarmor
->armor_value
,
1983 &state
->armor_crypto
);
1993 free_KrbFastArmor(fxarmor
);
1999 static krb5_error_code
2000 fast_wrap_req(krb5_context context
, struct fast_state
*state
, KDC_REQ
*req
)
2002 KrbFastArmor
*fxarmor
= NULL
;
2003 PA_FX_FAST_REQUEST fxreq
;
2004 krb5_error_code ret
;
2009 if (state
->flags
& KRB5_FAST_DISABLED
) {
2010 _krb5_debug(context
, 10, "fast disabled, not doing any fast wrapping");
2014 memset(&fxreq
, 0, sizeof(fxreq
));
2015 memset(&fastreq
, 0, sizeof(fastreq
));
2016 krb5_data_zero(&data
);
2018 if (state
->armor_crypto
== NULL
) {
2019 if (state
->armor_ccache
) {
2021 * Instead of keeping state in FX_COOKIE in the KDC, we
2022 * rebuild a new armor key for every request, because this
2023 * is what the MIT KDC expect and RFC6113 is vage about
2024 * what the behavior should be.
2026 state
->type
= choice_PA_FX_FAST_REQUEST_armored_data
;
2028 return check_fast(context
, state
);
2032 state
->flags
|= KRB5_FAST_EXPECTED
;
2034 fastreq
.fast_options
.hide_client_names
= 1;
2036 ret
= copy_KDC_REQ_BODY(&req
->req_body
, &fastreq
.req_body
);
2037 free_KDC_REQ_BODY(&req
->req_body
);
2039 req
->req_body
.realm
= strdup(KRB5_ANON_REALM
);
2040 ALLOC(req
->req_body
.cname
, 1);
2041 req
->req_body
.cname
->name_type
= KRB5_NT_PRINCIPAL
;
2042 ALLOC(req
->req_body
.cname
->name_string
.val
, 2);
2043 req
->req_body
.cname
->name_string
.len
= 2;
2044 req
->req_body
.cname
->name_string
.val
[0] = strdup(KRB5_WELLKNOWN_NAME
);
2045 req
->req_body
.cname
->name_string
.val
[1] = strdup(KRB5_ANON_NAME
);
2046 ALLOC(req
->req_body
.till
, 1);
2047 *req
->req_body
.till
= 0;
2050 ret
= copy_METHOD_DATA(req
->padata
, &fastreq
.padata
);
2051 free_METHOD_DATA(req
->padata
);
2053 ALLOC(req
->padata
, 1);
2057 ASN1_MALLOC_ENCODE(KrbFastReq
, data
.data
, data
.length
, &fastreq
, &size
, ret
);
2060 heim_assert(data
.length
== size
, "ASN.1 internal error");
2062 fxreq
.element
= state
->type
;
2064 if (state
->type
== choice_PA_FX_FAST_REQUEST_armored_data
) {
2068 ret
= make_fast_ap_fxarmor(context
, state
, fastreq
.req_body
.realm
, &fxreq
.u
.armored_data
.armor
);
2072 heim_assert(state
->armor_crypto
!= NULL
, "FAST armor key missing when FAST started");
2074 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, len
, &req
->req_body
, &size
, ret
);
2077 heim_assert(len
== size
, "ASN.1 internal error");
2079 ret
= krb5_create_checksum(context
, state
->armor_crypto
,
2080 KRB5_KU_FAST_REQ_CHKSUM
, 0,
2082 &fxreq
.u
.armored_data
.req_checksum
);
2087 ret
= krb5_encrypt_EncryptedData(context
, state
->armor_crypto
,
2092 &fxreq
.u
.armored_data
.enc_fast_req
);
2093 krb5_data_free(&data
);
2096 krb5_data_free(&data
);
2097 heim_assert(false, "unknown FAST type, internal error");
2100 ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST
, data
.data
, data
.length
, &fxreq
, &size
, ret
);
2103 heim_assert(data
.length
== size
, "ASN.1 internal error");
2106 ret
= krb5_padata_add(context
, req
->padata
, KRB5_PADATA_FX_FAST
, data
.data
, data
.length
);
2109 krb5_data_zero(&data
);
2112 free_PA_FX_FAST_REQUEST(&fxreq
);
2114 free_KrbFastArmor(fxarmor
);
2117 krb5_data_free(&data
);
2124 * The core loop if krb5_get_init_creds() function family. Create the
2125 * packets and have the caller send them off to the KDC.
2127 * If the caller want all work been done for them, use
2128 * krb5_init_creds_get() instead.
2130 * @param context a Kerberos 5 context.
2131 * @param ctx ctx krb5_init_creds_context context.
2132 * @param in input data from KDC, first round it should be reset by krb5_data_zer().
2133 * @param out reply to KDC.
2134 * @param hostinfo KDC address info, first round it can be NULL.
2135 * @param flags status of the round, if
2136 * KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round.
2138 * @return 0 for success, or an Kerberos 5 error code, see
2139 * krb5_get_error_message().
2141 * @ingroup krb5_credential
2144 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2145 krb5_init_creds_step(krb5_context context
,
2146 krb5_init_creds_context ctx
,
2149 krb5_krbhst_info
*hostinfo
,
2150 unsigned int *flags
)
2152 krb5_error_code ret
;
2157 krb5_data_zero(out
);
2159 if (ctx
->as_req
.req_body
.cname
== NULL
) {
2160 ret
= init_as_req(context
, ctx
->flags
, &ctx
->cred
,
2161 ctx
->addrs
, ctx
->etypes
, &ctx
->as_req
);
2163 free_init_creds_ctx(context
, ctx
);
2168 #define MAX_PA_COUNTER 10
2169 if (ctx
->pa_counter
> MAX_PA_COUNTER
) {
2170 krb5_set_error_message(context
, KRB5_GET_IN_TKT_LOOP
,
2171 N_("Looping %d times while getting "
2172 "initial credentials", ""),
2174 return KRB5_GET_IN_TKT_LOOP
;
2178 _krb5_debug(context
, 5, "krb5_get_init_creds: loop %d", ctx
->pa_counter
);
2180 /* Lets process the input packet */
2181 if (in
&& in
->length
) {
2184 memset(&rep
, 0, sizeof(rep
));
2186 _krb5_debug(context
, 5, "krb5_get_init_creds: processing input");
2188 ret
= decode_AS_REP(in
->data
, in
->length
, &rep
.kdc_rep
, &size
);
2190 unsigned eflags
= EXTRACT_TICKET_AS_REQ
| EXTRACT_TICKET_TIMESYNC
;
2196 ASN1_MALLOC_ENCODE(Ticket
, data
.data
, data
.length
,
2197 &rep
.kdc_rep
.ticket
, &size
, ret
);
2200 heim_assert(data
.length
== size
, "ASN.1 internal error");
2202 ret
= fast_unwrap_as_rep(context
, ctx
->nonce
, &data
,
2203 &ctx
->fast_state
, &rep
.kdc_rep
);
2204 krb5_data_free(&data
);
2209 * Now check and extract the ticket
2212 if (ctx
->flags
.canonicalize
) {
2213 eflags
|= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH
;
2214 eflags
|= EXTRACT_TICKET_MATCH_REALM
;
2216 if (ctx
->ic_flags
& KRB5_INIT_CREDS_NO_C_CANON_CHECK
)
2217 eflags
|= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH
;
2219 ret
= process_pa_data_to_key(context
, ctx
, &ctx
->cred
,
2220 &ctx
->as_req
, &rep
.kdc_rep
,
2221 hostinfo
, &ctx
->fast_state
.reply_key
);
2223 free_AS_REP(&rep
.kdc_rep
);
2227 _krb5_debug(context
, 5, "krb5_get_init_creds: extracting ticket");
2229 ret
= _krb5_extract_ticket(context
,
2232 ctx
->fast_state
.reply_key
,
2234 KRB5_KU_AS_REP_ENC_PART
,
2242 ret
= copy_EncKDCRepPart(&rep
.enc_part
, &ctx
->enc_part
);
2244 krb5_free_keyblock(context
, ctx
->fast_state
.reply_key
);
2245 ctx
->fast_state
.reply_key
= NULL
;
2248 free_AS_REP(&rep
.kdc_rep
);
2249 free_EncASRepPart(&rep
.enc_part
);
2254 /* let's try to parse it as a KRB-ERROR */
2256 _krb5_debug(context
, 5, "krb5_get_init_creds: got an error");
2258 free_KRB_ERROR(&ctx
->error
);
2260 ret
= krb5_rd_error(context
, in
, &ctx
->error
);
2261 if(ret
&& in
->length
&& ((char*)in
->data
)[0] == 4)
2262 ret
= KRB5KRB_AP_ERR_V4_REPLY
;
2264 _krb5_debug(context
, 5, "krb5_get_init_creds: failed to read error");
2271 ret
= fast_unwrap_error(context
, &ctx
->fast_state
, &ctx
->error
);
2279 ret
= krb5_error_from_rd_error(context
, &ctx
->error
, &ctx
->cred
);
2281 _krb5_debug(context
, 5, "krb5_get_init_creds: KRB-ERROR %d", ret
);
2284 * If no preauth was set and KDC requires it, give it one
2288 if (ret
== KRB5KDC_ERR_PREAUTH_REQUIRED
) {
2290 free_METHOD_DATA(&ctx
->md
);
2291 memset(&ctx
->md
, 0, sizeof(ctx
->md
));
2293 if (ctx
->error
.e_data
) {
2294 ret
= decode_METHOD_DATA(ctx
->error
.e_data
->data
,
2295 ctx
->error
.e_data
->length
,
2299 krb5_set_error_message(context
, ret
,
2300 N_("Failed to decode METHOD-DATA", ""));
2302 krb5_set_error_message(context
, ret
,
2303 N_("Preauth required but no preauth "
2304 "options send by KDC", ""));
2306 } else if (ret
== KRB5KRB_AP_ERR_SKEW
&& context
->kdc_sec_offset
== 0) {
2308 * Try adapt to timeskrew when we are using pre-auth, and
2309 * if there was a time skew, try again.
2311 krb5_set_real_time(context
, ctx
->error
.stime
, -1);
2312 if (context
->kdc_sec_offset
)
2315 _krb5_debug(context
, 10, "init_creds: err skew updateing kdc offset to %d",
2316 context
->kdc_sec_offset
);
2318 ctx
->used_pa_types
= 0;
2320 } else if (ret
== KRB5_KDC_ERR_WRONG_REALM
&& ctx
->flags
.canonicalize
) {
2321 /* client referal to a new realm */
2323 if (ctx
->error
.crealm
== NULL
) {
2324 krb5_set_error_message(context
, ret
,
2325 N_("Got a client referral, not but no realm", ""));
2328 _krb5_debug(context
, 5,
2329 "krb5_get_init_creds: got referal to realm %s",
2330 *ctx
->error
.crealm
);
2332 ret
= krb5_principal_set_realm(context
,
2334 *ctx
->error
.crealm
);
2338 if (krb5_principal_is_krbtgt(context
, ctx
->cred
.server
)) {
2339 ret
= krb5_init_creds_set_service(context
, ctx
, NULL
);
2344 free_AS_REQ(&ctx
->as_req
);
2345 memset(&ctx
->as_req
, 0, sizeof(ctx
->as_req
));
2347 ctx
->used_pa_types
= 0;
2348 } else if (ret
== KRB5KDC_ERR_KEY_EXP
&& ctx
->runflags
.change_password
== 0 && ctx
->prompter
) {
2351 ctx
->runflags
.change_password
= 1;
2353 ctx
->prompter(context
, ctx
->prompter_data
, NULL
, N_("Password has expired", ""), 0, NULL
);
2356 /* try to avoid recursion */
2357 if (ctx
->in_tkt_service
!= NULL
&& strcmp(ctx
->in_tkt_service
, "kadmin/changepw") == 0)
2360 ret
= change_password(context
,
2371 krb5_init_creds_set_password(context
, ctx
, buf2
);
2373 ctx
->used_pa_types
= 0;
2376 } else if (ret
== KRB5KDC_ERR_PREAUTH_FAILED
) {
2378 if (ctx
->fast_state
.flags
& KRB5_FAST_DISABLED
)
2380 if (ctx
->fast_state
.flags
& (KRB5_FAST_REQUIRED
| KRB5_FAST_EXPECTED
))
2383 _krb5_debug(context
, 10, "preauth failed with FAST, "
2384 "and told by KD or user, trying w/o FAST");
2386 ctx
->fast_state
.flags
|= KRB5_FAST_DISABLED
;
2387 ctx
->used_pa_types
= 0;
2395 if (ctx
->as_req
.req_body
.cname
== NULL
) {
2396 ret
= init_as_req(context
, ctx
->flags
, &ctx
->cred
,
2397 ctx
->addrs
, ctx
->etypes
, &ctx
->as_req
);
2399 free_init_creds_ctx(context
, ctx
);
2404 if (ctx
->as_req
.padata
) {
2405 free_METHOD_DATA(ctx
->as_req
.padata
);
2406 free(ctx
->as_req
.padata
);
2407 ctx
->as_req
.padata
= NULL
;
2410 /* Set a new nonce. */
2411 ctx
->as_req
.req_body
.nonce
= ctx
->nonce
;
2413 /* fill_in_md_data */
2414 ret
= process_pa_data_to_md(context
, &ctx
->cred
, &ctx
->as_req
, ctx
,
2415 &ctx
->md
, &ctx
->as_req
.padata
,
2416 ctx
->prompter
, ctx
->prompter_data
);
2423 copy_AS_REQ(&ctx
->as_req
, &req2
);
2425 ret
= fast_wrap_req(context
, &ctx
->fast_state
, &req2
);
2431 krb5_data_free(&ctx
->req_buffer
);
2433 ASN1_MALLOC_ENCODE(AS_REQ
,
2434 ctx
->req_buffer
.data
, ctx
->req_buffer
.length
,
2439 if(len
!= ctx
->req_buffer
.length
)
2440 krb5_abortx(context
, "internal error in ASN.1 encoder");
2442 out
->data
= ctx
->req_buffer
.data
;
2443 out
->length
= ctx
->req_buffer
.length
;
2445 *flags
= KRB5_INIT_CREDS_STEP_FLAG_CONTINUE
;
2453 * Extract the newly acquired credentials from krb5_init_creds_context
2456 * @param context A Kerberos 5 context.
2458 * @param cred credentials, free with krb5_free_cred_contents().
2460 * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
2463 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2464 krb5_init_creds_get_creds(krb5_context context
,
2465 krb5_init_creds_context ctx
,
2468 return krb5_copy_creds_contents(context
, &ctx
->cred
, cred
);
2472 * Get the last error from the transaction.
2474 * @return Returns 0 or an error code
2476 * @ingroup krb5_credential
2479 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2480 krb5_init_creds_get_error(krb5_context context
,
2481 krb5_init_creds_context ctx
,
2484 krb5_error_code ret
;
2486 ret
= copy_KRB_ERROR(&ctx
->error
, error
);
2488 krb5_enomem(context
);
2495 * @ingroup krb5_credential
2499 krb5_init_creds_store(krb5_context context
,
2500 krb5_init_creds_context ctx
,
2503 krb5_error_code ret
;
2505 if (ctx
->cred
.client
== NULL
) {
2506 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
;
2507 krb5_set_error_message(context
, ret
, "init creds not completed yet");
2511 ret
= krb5_cc_initialize(context
, id
, ctx
->cred
.client
);
2515 ret
= krb5_cc_store_cred(context
, id
, &ctx
->cred
);
2519 if (ctx
->cred
.flags
.b
.enc_pa_rep
) {
2520 krb5_data data
= { 3, rk_UNCONST("yes") };
2521 ret
= krb5_cc_set_config(context
, id
, ctx
->cred
.server
,
2522 "fast_avail", &data
);
2531 * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
2533 * @param context A Kerberos 5 context.
2534 * @param ctx The krb5_init_creds_context to free.
2536 * @ingroup krb5_credential
2539 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
2540 krb5_init_creds_free(krb5_context context
,
2541 krb5_init_creds_context ctx
)
2543 free_init_creds_ctx(context
, ctx
);
2548 * Get new credentials as setup by the krb5_init_creds_context.
2550 * @param context A Kerberos 5 context.
2551 * @param ctx The krb5_init_creds_context to process.
2553 * @ingroup krb5_credential
2556 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2557 krb5_init_creds_get(krb5_context context
, krb5_init_creds_context ctx
)
2559 krb5_sendto_ctx stctx
= NULL
;
2560 krb5_krbhst_info
*hostinfo
= NULL
;
2561 krb5_error_code ret
;
2563 unsigned int flags
= 0;
2565 krb5_data_zero(&in
);
2566 krb5_data_zero(&out
);
2568 ret
= krb5_sendto_ctx_alloc(context
, &stctx
);
2571 krb5_sendto_ctx_set_func(stctx
, _krb5_kdc_retry
, NULL
);
2575 ret
= krb5_init_creds_step(context
, ctx
, &in
, &out
, hostinfo
, &flags
);
2576 krb5_data_free(&in
);
2580 if ((flags
& 1) == 0)
2583 ret
= krb5_sendto_context (context
, stctx
, &out
,
2584 ctx
->cred
.client
->realm
, &in
);
2592 krb5_sendto_ctx_free(context
, stctx
);
2598 * Get new credentials using password.
2600 * @ingroup krb5_credential
2604 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2605 krb5_get_init_creds_password(krb5_context context
,
2607 krb5_principal client
,
2608 const char *password
,
2609 krb5_prompter_fct prompter
,
2611 krb5_deltat start_time
,
2612 const char *in_tkt_service
,
2613 krb5_get_init_creds_opt
*options
)
2615 krb5_init_creds_context ctx
;
2616 char buf
[BUFSIZ
], buf2
[BUFSIZ
];
2617 krb5_error_code ret
;
2621 ret
= krb5_init_creds_init(context
, client
, prompter
, data
, start_time
, options
, &ctx
);
2625 ret
= krb5_init_creds_set_service(context
, ctx
, in_tkt_service
);
2629 if (prompter
!= NULL
&& ctx
->password
== NULL
&& password
== NULL
) {
2631 krb5_data password_data
;
2635 ret
= krb5_unparse_name(context
, client
, &p
);
2639 aret
= asprintf(&q
, "%s's Password: ", p
);
2641 if (aret
== -1 || q
== NULL
) {
2642 ret
= krb5_enomem(context
);
2646 password_data
.data
= buf
;
2647 password_data
.length
= sizeof(buf
);
2649 prompt
.reply
= &password_data
;
2650 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
2652 ret
= (*prompter
) (context
, data
, NULL
, NULL
, 1, &prompt
);
2655 memset (buf
, 0, sizeof(buf
));
2656 ret
= KRB5_LIBOS_PWDINTR
;
2657 krb5_clear_error_message (context
);
2660 password
= password_data
.data
;
2664 ret
= krb5_init_creds_set_password(context
, ctx
, password
);
2669 ret
= krb5_init_creds_get(context
, ctx
);
2672 krb5_process_last_request(context
, options
, ctx
);
2675 if (ret
== KRB5KDC_ERR_KEY_EXPIRED
&& chpw
== 0) {
2676 /* try to avoid recursion */
2677 if (in_tkt_service
!= NULL
&& strcmp(in_tkt_service
, "kadmin/changepw") == 0)
2680 /* don't try to change password where then where none */
2681 if (prompter
== NULL
)
2684 ret
= change_password (context
,
2696 krb5_init_creds_free(context
, ctx
);
2702 krb5_init_creds_get_creds(context
, ctx
, creds
);
2705 krb5_init_creds_free(context
, ctx
);
2707 memset(buf
, 0, sizeof(buf
));
2708 memset(buf2
, 0, sizeof(buf2
));
2713 * Get new credentials using keyblock.
2715 * @ingroup krb5_credential
2718 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2719 krb5_get_init_creds_keyblock(krb5_context context
,
2721 krb5_principal client
,
2722 krb5_keyblock
*keyblock
,
2723 krb5_deltat start_time
,
2724 const char *in_tkt_service
,
2725 krb5_get_init_creds_opt
*options
)
2727 krb5_init_creds_context ctx
;
2728 krb5_error_code ret
;
2730 memset(creds
, 0, sizeof(*creds
));
2732 ret
= krb5_init_creds_init(context
, client
, NULL
, NULL
, start_time
, options
, &ctx
);
2736 ret
= krb5_init_creds_set_service(context
, ctx
, in_tkt_service
);
2740 ret
= krb5_init_creds_set_keyblock(context
, ctx
, keyblock
);
2744 ret
= krb5_init_creds_get(context
, ctx
);
2747 krb5_process_last_request(context
, options
, ctx
);
2751 krb5_init_creds_get_creds(context
, ctx
, creds
);
2754 krb5_init_creds_free(context
, ctx
);
2760 * Get new credentials using keytab.
2762 * @ingroup krb5_credential
2765 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2766 krb5_get_init_creds_keytab(krb5_context context
,
2768 krb5_principal client
,
2770 krb5_deltat start_time
,
2771 const char *in_tkt_service
,
2772 krb5_get_init_creds_opt
*options
)
2774 krb5_init_creds_context ctx
;
2775 krb5_keytab_entry ktent
;
2776 krb5_error_code ret
;
2778 memset(&ktent
, 0, sizeof(ktent
));
2779 memset(creds
, 0, sizeof(*creds
));
2781 if (strcmp(client
->realm
, "") == 0) {
2783 * Referral realm. We have a keytab, so pick a realm by
2784 * matching in the keytab.
2786 ret
= krb5_kt_get_entry(context
, keytab
, client
, 0, 0, &ktent
);
2788 client
= ktent
.principal
;
2791 ret
= krb5_init_creds_init(context
, client
, NULL
, NULL
, start_time
, options
, &ctx
);
2795 ret
= krb5_init_creds_set_service(context
, ctx
, in_tkt_service
);
2799 ret
= krb5_init_creds_set_keytab(context
, ctx
, keytab
);
2803 ret
= krb5_init_creds_get(context
, ctx
);
2805 krb5_process_last_request(context
, options
, ctx
);
2808 krb5_kt_free_entry(context
, &ktent
);
2810 krb5_init_creds_get_creds(context
, ctx
, creds
);
2813 krb5_init_creds_free(context
, ctx
);