2 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: get_in_tkt.c 20226 2007-02-16 03:31:50Z lha $"
39 krb5_error_code KRB5_LIB_FUNCTION
40 krb5_init_etype (krb5_context context
,
43 const krb5_enctype
*etypes
)
47 krb5_enctype
*tmp
= NULL
;
51 ret
= krb5_get_default_in_tkt_etypes(context
,
58 for (i
= 0; etypes
[i
]; ++i
)
61 *val
= malloc(i
* sizeof(**val
));
62 if (i
!= 0 && *val
== NULL
) {
64 krb5_set_error_string(context
, "malloc: out of memory");
77 static krb5_error_code
78 decrypt_tkt (krb5_context context
,
81 krb5_const_pointer decrypt_arg
,
82 krb5_kdc_rep
*dec_rep
)
89 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
93 ret
= krb5_decrypt_EncryptedData (context
,
96 &dec_rep
->kdc_rep
.enc_part
,
98 krb5_crypto_destroy(context
, crypto
);
103 ret
= krb5_decode_EncASRepPart(context
,
109 ret
= krb5_decode_EncTGSRepPart(context
,
114 krb5_data_free (&data
);
121 _krb5_extract_ticket(krb5_context context
,
125 krb5_const_pointer keyseed
,
126 krb5_key_usage key_usage
,
127 krb5_addresses
*addrs
,
130 krb5_decrypt_proc decrypt_proc
,
131 krb5_const_pointer decryptarg
)
134 krb5_principal tmp_principal
;
138 krb5_timestamp sec_now
;
140 ret
= _krb5_principalname2krb5_principal (context
,
143 rep
->kdc_rep
.crealm
);
149 if((flags
& EXTRACT_TICKET_ALLOW_CNAME_MISMATCH
) == 0){
150 tmp
= krb5_principal_compare (context
, tmp_principal
, creds
->client
);
152 krb5_free_principal (context
, tmp_principal
);
153 krb5_clear_error_string (context
);
154 ret
= KRB5KRB_AP_ERR_MODIFIED
;
159 krb5_free_principal (context
, creds
->client
);
160 creds
->client
= tmp_principal
;
163 ASN1_MALLOC_ENCODE(Ticket
, creds
->ticket
.data
, creds
->ticket
.length
,
164 &rep
->kdc_rep
.ticket
, &len
, ret
);
167 if (creds
->ticket
.length
!= len
)
168 krb5_abortx(context
, "internal error in ASN.1 encoder");
169 creds
->second_ticket
.length
= 0;
170 creds
->second_ticket
.data
= NULL
;
174 ret
= _krb5_principalname2krb5_principal (context
,
176 rep
->kdc_rep
.ticket
.sname
,
177 rep
->kdc_rep
.ticket
.realm
);
180 if(flags
& EXTRACT_TICKET_ALLOW_SERVER_MISMATCH
){
181 krb5_free_principal(context
, creds
->server
);
182 creds
->server
= tmp_principal
;
183 tmp_principal
= NULL
;
185 tmp
= krb5_principal_compare (context
, tmp_principal
,
187 krb5_free_principal (context
, tmp_principal
);
189 ret
= KRB5KRB_AP_ERR_MODIFIED
;
190 krb5_clear_error_string (context
);
197 if (decrypt_proc
== NULL
)
198 decrypt_proc
= decrypt_tkt
;
200 ret
= (*decrypt_proc
)(context
, key
, key_usage
, decryptarg
, rep
);
205 if(flags
& EXTRACT_TICKET_MATCH_REALM
){
206 const char *srealm
= krb5_principal_get_realm(context
, creds
->server
);
207 const char *crealm
= krb5_principal_get_realm(context
, creds
->client
);
209 if (strcmp(rep
->enc_part
.srealm
, srealm
) != 0 ||
210 strcmp(rep
->enc_part
.srealm
, crealm
) != 0)
212 ret
= KRB5KRB_AP_ERR_MODIFIED
;
213 krb5_clear_error_string(context
);
220 if (nonce
!= rep
->enc_part
.nonce
) {
221 ret
= KRB5KRB_AP_ERR_MODIFIED
;
222 krb5_set_error_string(context
, "malloc: out of memory");
228 krb5_timeofday (context
, &sec_now
);
229 if (rep
->enc_part
.flags
.initial
230 && context
->kdc_sec_offset
== 0
231 && krb5_config_get_bool (context
, NULL
,
235 context
->kdc_sec_offset
= rep
->enc_part
.authtime
- sec_now
;
236 krb5_timeofday (context
, &sec_now
);
239 /* check all times */
241 if (rep
->enc_part
.starttime
) {
242 tmp_time
= *rep
->enc_part
.starttime
;
244 tmp_time
= rep
->enc_part
.authtime
;
246 if (creds
->times
.starttime
== 0
247 && abs(tmp_time
- sec_now
) > context
->max_skew
) {
248 ret
= KRB5KRB_AP_ERR_SKEW
;
249 krb5_set_error_string (context
,
250 "time skew (%d) larger than max (%d)",
251 abs(tmp_time
- sec_now
),
252 (int)context
->max_skew
);
256 if (creds
->times
.starttime
!= 0
257 && tmp_time
!= creds
->times
.starttime
) {
258 krb5_clear_error_string (context
);
259 ret
= KRB5KRB_AP_ERR_MODIFIED
;
263 creds
->times
.starttime
= tmp_time
;
265 if (rep
->enc_part
.renew_till
) {
266 tmp_time
= *rep
->enc_part
.renew_till
;
270 if (creds
->times
.renew_till
!= 0
271 && tmp_time
> creds
->times
.renew_till
) {
272 krb5_clear_error_string (context
);
273 ret
= KRB5KRB_AP_ERR_MODIFIED
;
277 creds
->times
.renew_till
= tmp_time
;
279 creds
->times
.authtime
= rep
->enc_part
.authtime
;
281 if (creds
->times
.endtime
!= 0
282 && rep
->enc_part
.endtime
> creds
->times
.endtime
) {
283 krb5_clear_error_string (context
);
284 ret
= KRB5KRB_AP_ERR_MODIFIED
;
288 creds
->times
.endtime
= rep
->enc_part
.endtime
;
290 if(rep
->enc_part
.caddr
)
291 krb5_copy_addresses (context
, rep
->enc_part
.caddr
, &creds
->addresses
);
293 krb5_copy_addresses (context
, addrs
, &creds
->addresses
);
295 creds
->addresses
.len
= 0;
296 creds
->addresses
.val
= NULL
;
298 creds
->flags
.b
= rep
->enc_part
.flags
;
300 creds
->authdata
.len
= 0;
301 creds
->authdata
.val
= NULL
;
302 creds
->session
.keyvalue
.length
= 0;
303 creds
->session
.keyvalue
.data
= NULL
;
304 creds
->session
.keytype
= rep
->enc_part
.key
.keytype
;
305 ret
= krb5_data_copy (&creds
->session
.keyvalue
,
306 rep
->enc_part
.key
.keyvalue
.data
,
307 rep
->enc_part
.key
.keyvalue
.length
);
310 memset (rep
->enc_part
.key
.keyvalue
.data
, 0,
311 rep
->enc_part
.key
.keyvalue
.length
);
316 static krb5_error_code
317 make_pa_enc_timestamp(krb5_context context
, PA_DATA
*pa
,
318 krb5_enctype etype
, krb5_keyblock
*key
)
324 EncryptedData encdata
;
330 krb5_us_timeofday (context
, &p
.patimestamp
, &usec
);
334 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC
, buf
, buf_size
, &p
, &len
, ret
);
338 krb5_abortx(context
, "internal error in ASN.1 encoder");
339 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
344 ret
= krb5_encrypt_EncryptedData(context
,
346 KRB5_KU_PA_ENC_TIMESTAMP
,
352 krb5_crypto_destroy(context
, crypto
);
356 ASN1_MALLOC_ENCODE(EncryptedData
, buf
, buf_size
, &encdata
, &len
, ret
);
357 free_EncryptedData(&encdata
);
361 krb5_abortx(context
, "internal error in ASN.1 encoder");
362 pa
->padata_type
= KRB5_PADATA_ENC_TIMESTAMP
;
363 pa
->padata_value
.length
= len
;
364 pa
->padata_value
.data
= buf
;
368 static krb5_error_code
369 add_padata(krb5_context context
,
371 krb5_principal client
,
372 krb5_key_proc key_proc
,
373 krb5_const_pointer keyseed
,
374 krb5_enctype
*enctypes
,
385 /* default to standard salt */
386 ret
= krb5_get_pw_salt (context
, client
, &salt2
);
390 enctypes
= context
->etypes
;
392 for (ep
= enctypes
; *ep
!= ETYPE_NULL
; ep
++)
395 pa2
= realloc (md
->val
, (md
->len
+ netypes
) * sizeof(*md
->val
));
397 krb5_set_error_string(context
, "malloc: out of memory");
402 for (i
= 0; i
< netypes
; ++i
) {
405 ret
= (*key_proc
)(context
, enctypes
[i
], *salt
, keyseed
, &key
);
408 ret
= make_pa_enc_timestamp (context
, &md
->val
[md
->len
],
410 krb5_free_keyblock (context
, key
);
416 krb5_free_salt(context
, salt2
);
420 static krb5_error_code
421 init_as_req (krb5_context context
,
424 const krb5_addresses
*addrs
,
425 const krb5_enctype
*etypes
,
426 const krb5_preauthtype
*ptypes
,
427 const krb5_preauthdata
*preauth
,
428 krb5_key_proc key_proc
,
429 krb5_const_pointer keyseed
,
436 memset(a
, 0, sizeof(*a
));
439 a
->msg_type
= krb_as_req
;
440 a
->req_body
.kdc_options
= opts
;
441 a
->req_body
.cname
= malloc(sizeof(*a
->req_body
.cname
));
442 if (a
->req_body
.cname
== NULL
) {
444 krb5_set_error_string(context
, "malloc: out of memory");
447 a
->req_body
.sname
= malloc(sizeof(*a
->req_body
.sname
));
448 if (a
->req_body
.sname
== NULL
) {
450 krb5_set_error_string(context
, "malloc: out of memory");
453 ret
= _krb5_principal2principalname (a
->req_body
.cname
, creds
->client
);
456 ret
= _krb5_principal2principalname (a
->req_body
.sname
, creds
->server
);
459 ret
= copy_Realm(&creds
->client
->realm
, &a
->req_body
.realm
);
463 if(creds
->times
.starttime
) {
464 a
->req_body
.from
= malloc(sizeof(*a
->req_body
.from
));
465 if (a
->req_body
.from
== NULL
) {
467 krb5_set_error_string(context
, "malloc: out of memory");
470 *a
->req_body
.from
= creds
->times
.starttime
;
472 if(creds
->times
.endtime
){
473 ALLOC(a
->req_body
.till
, 1);
474 *a
->req_body
.till
= creds
->times
.endtime
;
476 if(creds
->times
.renew_till
){
477 a
->req_body
.rtime
= malloc(sizeof(*a
->req_body
.rtime
));
478 if (a
->req_body
.rtime
== NULL
) {
480 krb5_set_error_string(context
, "malloc: out of memory");
483 *a
->req_body
.rtime
= creds
->times
.renew_till
;
485 a
->req_body
.nonce
= nonce
;
486 ret
= krb5_init_etype (context
,
487 &a
->req_body
.etype
.len
,
488 &a
->req_body
.etype
.val
,
494 * This means no addresses
497 if (addrs
&& addrs
->len
== 0) {
498 a
->req_body
.addresses
= NULL
;
500 a
->req_body
.addresses
= malloc(sizeof(*a
->req_body
.addresses
));
501 if (a
->req_body
.addresses
== NULL
) {
503 krb5_set_error_string(context
, "malloc: out of memory");
508 ret
= krb5_copy_addresses(context
, addrs
, a
->req_body
.addresses
);
510 ret
= krb5_get_all_client_addrs (context
, a
->req_body
.addresses
);
511 if(ret
== 0 && a
->req_body
.addresses
->len
== 0) {
512 free(a
->req_body
.addresses
);
513 a
->req_body
.addresses
= NULL
;
520 a
->req_body
.enc_authorization_data
= NULL
;
521 a
->req_body
.additional_tickets
= NULL
;
523 if(preauth
!= NULL
) {
526 if(a
->padata
== NULL
) {
528 krb5_set_error_string(context
, "malloc: out of memory");
531 a
->padata
->val
= NULL
;
533 for(i
= 0; i
< preauth
->len
; i
++) {
534 if(preauth
->val
[i
].type
== KRB5_PADATA_ENC_TIMESTAMP
){
537 for(j
= 0; j
< preauth
->val
[i
].info
.len
; j
++) {
538 krb5_salt
*sp
= &salt
;
539 if(preauth
->val
[i
].info
.val
[j
].salttype
)
540 salt
.salttype
= *preauth
->val
[i
].info
.val
[j
].salttype
;
542 salt
.salttype
= KRB5_PW_SALT
;
543 if(preauth
->val
[i
].info
.val
[j
].salt
)
544 salt
.saltvalue
= *preauth
->val
[i
].info
.val
[j
].salt
;
546 if(salt
.salttype
== KRB5_PW_SALT
)
549 krb5_data_zero(&salt
.saltvalue
);
550 ret
= add_padata(context
, a
->padata
, creds
->client
,
552 &preauth
->val
[i
].info
.val
[j
].etype
, 1,
560 /* not sure this is the way to use `ptypes' */
561 if (ptypes
== NULL
|| *ptypes
== KRB5_PADATA_NONE
)
563 else if (*ptypes
== KRB5_PADATA_ENC_TIMESTAMP
) {
565 if (a
->padata
== NULL
) {
567 krb5_set_error_string(context
, "malloc: out of memory");
571 a
->padata
->val
= NULL
;
573 /* make a v5 salted pa-data */
574 add_padata(context
, a
->padata
, creds
->client
,
575 key_proc
, keyseed
, a
->req_body
.etype
.val
,
576 a
->req_body
.etype
.len
, NULL
);
578 /* make a v4 salted pa-data */
579 salt
.salttype
= KRB5_PW_SALT
;
580 krb5_data_zero(&salt
.saltvalue
);
581 add_padata(context
, a
->padata
, creds
->client
,
582 key_proc
, keyseed
, a
->req_body
.etype
.val
,
583 a
->req_body
.etype
.len
, &salt
);
585 krb5_set_error_string (context
, "pre-auth type %d not supported",
587 ret
= KRB5_PREAUTH_BAD_TYPE
;
597 set_ptypes(krb5_context context
,
599 const krb5_preauthtype
**ptypes
,
600 krb5_preauthdata
**preauth
)
602 static krb5_preauthdata preauth2
;
603 static krb5_preauthtype ptypes2
[] = { KRB5_PADATA_ENC_TIMESTAMP
, KRB5_PADATA_NONE
};
608 decode_METHOD_DATA(error
->e_data
->data
,
609 error
->e_data
->length
,
612 for(i
= 0; i
< md
.len
; i
++){
613 switch(md
.val
[i
].padata_type
){
614 case KRB5_PADATA_ENC_TIMESTAMP
:
617 case KRB5_PADATA_ETYPE_INFO
:
618 *preauth
= &preauth2
;
619 ALLOC_SEQ(*preauth
, 1);
620 (*preauth
)->val
[0].type
= KRB5_PADATA_ENC_TIMESTAMP
;
621 krb5_decode_ETYPE_INFO(context
,
622 md
.val
[i
].padata_value
.data
,
623 md
.val
[i
].padata_value
.length
,
624 &(*preauth
)->val
[0].info
,
631 free_METHOD_DATA(&md
);
638 krb5_error_code KRB5_LIB_FUNCTION
639 krb5_get_in_cred(krb5_context context
,
641 const krb5_addresses
*addrs
,
642 const krb5_enctype
*etypes
,
643 const krb5_preauthtype
*ptypes
,
644 const krb5_preauthdata
*preauth
,
645 krb5_key_proc key_proc
,
646 krb5_const_pointer keyseed
,
647 krb5_decrypt_proc decrypt_proc
,
648 krb5_const_pointer decryptarg
,
650 krb5_kdc_rep
*ret_as_reply
)
663 krb5_preauthdata
*my_preauth
= NULL
;
667 opts
= int2KDCOptions(options
);
669 krb5_generate_random_block (&nonce
, sizeof(nonce
));
674 ret
= init_as_req (context
,
686 free_ETYPE_INFO(&my_preauth
->val
[0].info
);
687 free (my_preauth
->val
);
693 ASN1_MALLOC_ENCODE(AS_REQ
, req
.data
, req
.length
, &a
, &len
, ret
);
697 if(len
!= req
.length
)
698 krb5_abortx(context
, "internal error in ASN.1 encoder");
700 ret
= krb5_sendto_kdc (context
, &req
, &creds
->client
->realm
, &resp
);
701 krb5_data_free(&req
);
705 memset (&rep
, 0, sizeof(rep
));
706 ret
= decode_AS_REP(resp
.data
, resp
.length
, &rep
.kdc_rep
, &size
);
708 /* let's try to parse it as a KRB-ERROR */
712 ret2
= krb5_rd_error(context
, &resp
, &error
);
713 if(ret2
&& resp
.data
&& ((char*)resp
.data
)[0] == 4)
714 ret
= KRB5KRB_AP_ERR_V4_REPLY
;
715 krb5_data_free(&resp
);
717 ret
= krb5_error_from_rd_error(context
, &error
, creds
);
718 /* if no preauth was set and KDC requires it, give it
720 if (!ptypes
&& !preauth
721 && ret
== KRB5KDC_ERR_PREAUTH_REQUIRED
723 || ret
== KRB5KDC_ERR_BADOPTION
725 && set_ptypes(context
, &error
, &ptypes
, &my_preauth
)) {
727 preauth
= my_preauth
;
728 krb5_free_error_contents(context
, &error
);
729 krb5_clear_error_string(context
);
733 ret_as_reply
->error
= error
;
735 free_KRB_ERROR (&error
);
740 krb5_data_free(&resp
);
744 etype
= rep
.kdc_rep
.enc_part
.etype
;
745 if(rep
.kdc_rep
.padata
){
747 pa
= krb5_find_padata(rep
.kdc_rep
.padata
->val
, rep
.kdc_rep
.padata
->len
,
748 KRB5_PADATA_PW_SALT
, &i
);
751 pa
= krb5_find_padata(rep
.kdc_rep
.padata
->val
,
752 rep
.kdc_rep
.padata
->len
,
753 KRB5_PADATA_AFS3_SALT
, &i
);
757 salt
.salttype
= pa
->padata_type
;
758 salt
.saltvalue
= pa
->padata_value
;
760 ret
= (*key_proc
)(context
, etype
, salt
, keyseed
, &key
);
762 /* make a v5 salted pa-data */
763 ret
= krb5_get_pw_salt (context
, creds
->client
, &salt
);
767 ret
= (*key_proc
)(context
, etype
, salt
, keyseed
, &key
);
768 krb5_free_salt(context
, salt
);
775 if (opts
.request_anonymous
)
776 flags
|= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH
;
778 ret
= _krb5_extract_ticket(context
,
783 KRB5_KU_AS_REP_ENC_PART
,
790 memset (key
->keyvalue
.data
, 0, key
->keyvalue
.length
);
791 krb5_free_keyblock_contents (context
, key
);
795 if (ret
== 0 && ret_as_reply
)
798 krb5_free_kdc_rep (context
, &rep
);
802 krb5_error_code KRB5_LIB_FUNCTION
803 krb5_get_in_tkt(krb5_context context
,
805 const krb5_addresses
*addrs
,
806 const krb5_enctype
*etypes
,
807 const krb5_preauthtype
*ptypes
,
808 krb5_key_proc key_proc
,
809 krb5_const_pointer keyseed
,
810 krb5_decrypt_proc decrypt_proc
,
811 krb5_const_pointer decryptarg
,
814 krb5_kdc_rep
*ret_as_reply
)
818 ret
= krb5_get_in_cred (context
,
833 ret
= krb5_cc_store_cred (context
, ccache
, creds
);