add newline at end
[heimdal.git] / lib / krb5 / v4_glue.c
blob452fbd59227eae362756a3ad376b5e9ebbf18904
1 /*
2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
35 RCSID("$Id$");
37 #include "krb5-v4compat.h"
43 #define RCHECK(r,func,label) \
44 do { (r) = func ; if (r) goto label; } while(0);
47 /* include this here, to avoid dependencies on libkrb */
49 static const int _tkt_lifetimes[TKTLIFENUMFIXED] = {
50 38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318,
51 65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684,
52 111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720,
53 191077, 204289, 218415, 233517, 249664, 266926, 285383, 305116,
54 326213, 348769, 372885, 398668, 426234, 455705, 487215, 520904,
55 556921, 595430, 636601, 680618, 727680, 777995, 831789, 889303,
56 950794, 1016537, 1086825, 1161973, 1242318, 1328218, 1420057, 1518247,
57 1623226, 1735464, 1855462, 1983758, 2120925, 2267576, 2424367, 2592000
60 int KRB5_LIB_FUNCTION
61 _krb5_krb_time_to_life(time_t start, time_t end)
63 int i;
64 time_t life = end - start;
66 if (life > MAXTKTLIFETIME || life <= 0)
67 return 0;
68 #if 0
69 if (krb_no_long_lifetimes)
70 return (life + 5*60 - 1)/(5*60);
71 #endif
73 if (end >= NEVERDATE)
74 return TKTLIFENOEXPIRE;
75 if (life < _tkt_lifetimes[0])
76 return (life + 5*60 - 1)/(5*60);
77 for (i=0; i<TKTLIFENUMFIXED; i++)
78 if (life <= _tkt_lifetimes[i])
79 return i + TKTLIFEMINFIXED;
80 return 0;
84 time_t KRB5_LIB_FUNCTION
85 _krb5_krb_life_to_time(int start, int life_)
87 unsigned char life = (unsigned char) life_;
89 #if 0
90 if (krb_no_long_lifetimes)
91 return start + life*5*60;
92 #endif
94 if (life == TKTLIFENOEXPIRE)
95 return NEVERDATE;
96 if (life < TKTLIFEMINFIXED)
97 return start + life*5*60;
98 if (life > TKTLIFEMAXFIXED)
99 return start + MAXTKTLIFETIME;
100 return start + _tkt_lifetimes[life - TKTLIFEMINFIXED];
104 * Get the name of the krb4 credentials cache, will use `tkfile' as
105 * the name if that is passed in. `cc' must be free()ed by caller,
108 static krb5_error_code
109 get_krb4_cc_name(const char *tkfile, char **cc)
112 *cc = NULL;
113 if(tkfile == NULL) {
114 char *path;
115 if(!issuid()) {
116 path = getenv("KRBTKFILE");
117 if (path)
118 *cc = strdup(path);
120 if(*cc == NULL)
121 if (asprintf(cc, "%s%u", TKT_ROOT, (unsigned)getuid()) < 0)
122 return errno;
123 } else {
124 *cc = strdup(tkfile);
125 if (*cc == NULL)
126 return ENOMEM;
128 return 0;
132 * Write a Kerberos 4 ticket file
135 #define KRB5_TF_LCK_RETRY_COUNT 50
136 #define KRB5_TF_LCK_RETRY 1
138 static krb5_error_code
139 write_v4_cc(krb5_context context, const char *tkfile,
140 krb5_storage *sp, int append)
142 krb5_error_code ret;
143 struct stat sb;
144 krb5_data data;
145 char *path;
146 int fd, i;
148 ret = get_krb4_cc_name(tkfile, &path);
149 if (ret) {
150 krb5_set_error_string(context,
151 "krb5_krb_tf_setup: failed getting "
152 "the krb4 credentials cache name");
153 return ret;
156 fd = open(path, O_WRONLY|O_CREAT, 0600);
157 if (fd < 0) {
158 ret = errno;
159 krb5_set_error_string(context,
160 "krb5_krb_tf_setup: error opening file %s",
161 path);
162 free(path);
163 return ret;
166 if (fstat(fd, &sb) != 0 || !S_ISREG(sb.st_mode)) {
167 krb5_set_error_string(context,
168 "krb5_krb_tf_setup: tktfile %s is not a file",
169 path);
170 free(path);
171 close(fd);
172 return KRB5_FCC_PERM;
175 for (i = 0; i < KRB5_TF_LCK_RETRY_COUNT; i++) {
176 if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
177 sleep(KRB5_TF_LCK_RETRY);
178 } else
179 break;
181 if (i == KRB5_TF_LCK_RETRY_COUNT) {
182 krb5_set_error_string(context,
183 "krb5_krb_tf_setup: failed to lock %s",
184 path);
185 free(path);
186 close(fd);
187 return KRB5_FCC_PERM;
190 if (!append) {
191 ret = ftruncate(fd, 0);
192 if (ret < 0) {
193 flock(fd, LOCK_UN);
194 krb5_set_error_string(context,
195 "krb5_krb_tf_setup: failed to truncate %s",
196 path);
197 free(path);
198 close(fd);
199 return KRB5_FCC_PERM;
202 ret = lseek(fd, 0L, SEEK_END);
203 if (ret < 0) {
204 ret = errno;
205 flock(fd, LOCK_UN);
206 free(path);
207 close(fd);
208 return ret;
211 krb5_storage_to_data(sp, &data);
213 ret = write(fd, data.data, data.length);
214 if (ret != data.length)
215 ret = KRB5_CC_IO;
217 krb5_free_data_contents(context, &data);
219 flock(fd, LOCK_UN);
220 free(path);
221 close(fd);
223 return 0;
230 krb5_error_code KRB5_LIB_FUNCTION
231 _krb5_krb_tf_setup(krb5_context context,
232 struct credentials *v4creds,
233 const char *tkfile,
234 int append)
236 krb5_error_code ret;
237 krb5_storage *sp;
239 sp = krb5_storage_emem();
240 if (sp == NULL)
241 return ENOMEM;
243 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST);
244 krb5_storage_set_eof_code(sp, KRB5_CC_IO);
246 krb5_clear_error_string(context);
248 if (!append) {
249 RCHECK(ret, krb5_store_stringz(sp, v4creds->pname), error);
250 RCHECK(ret, krb5_store_stringz(sp, v4creds->pinst), error);
253 /* cred */
254 RCHECK(ret, krb5_store_stringz(sp, v4creds->service), error);
255 RCHECK(ret, krb5_store_stringz(sp, v4creds->instance), error);
256 RCHECK(ret, krb5_store_stringz(sp, v4creds->realm), error);
257 ret = krb5_storage_write(sp, v4creds->session, 8);
258 if (ret != 8) {
259 ret = KRB5_CC_IO;
260 goto error;
262 RCHECK(ret, krb5_store_int32(sp, v4creds->lifetime), error);
263 RCHECK(ret, krb5_store_int32(sp, v4creds->kvno), error);
264 RCHECK(ret, krb5_store_int32(sp, v4creds->ticket_st.length), error);
266 ret = krb5_storage_write(sp, v4creds->ticket_st.dat,
267 v4creds->ticket_st.length);
268 if (ret != v4creds->ticket_st.length) {
269 ret = KRB5_CC_IO;
270 goto error;
272 RCHECK(ret, krb5_store_int32(sp, v4creds->issue_date), error);
274 ret = write_v4_cc(context, tkfile, sp, append);
276 error:
277 krb5_storage_free(sp);
279 return ret;
286 krb5_error_code KRB5_LIB_FUNCTION
287 _krb5_krb_dest_tkt(krb5_context context, const char *tkfile)
289 krb5_error_code ret;
290 char *path;
292 ret = get_krb4_cc_name(tkfile, &path);
293 if (ret) {
294 krb5_set_error_string(context,
295 "krb5_krb_tf_setup: failed getting "
296 "the krb4 credentials cache name");
297 return ret;
300 if (unlink(path) < 0) {
301 ret = errno;
302 krb5_set_error_string(context,
303 "krb5_krb_dest_tkt failed removing the cache "
304 "with error %s", strerror(ret));
306 free(path);
308 return ret;
315 static krb5_error_code
316 decrypt_etext(krb5_context context, const krb5_keyblock *key,
317 const krb5_data *cdata, krb5_data *data)
319 krb5_error_code ret;
320 krb5_crypto crypto;
322 ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
323 if (ret)
324 return ret;
326 ret = krb5_decrypt(context, crypto, 0, cdata->data, cdata->length, data);
327 krb5_crypto_destroy(context, crypto);
329 return ret;
337 static const char eightzeros[8] = "\x00\x00\x00\x00\x00\x00\x00\x00";
339 static krb5_error_code
340 storage_to_etext(krb5_context context,
341 krb5_storage *sp,
342 const krb5_keyblock *key,
343 krb5_data *enc_data)
345 krb5_error_code ret;
346 krb5_crypto crypto;
347 krb5_ssize_t size;
348 krb5_data data;
350 /* multiple of eight bytes */
352 size = krb5_storage_seek(sp, 0, SEEK_END);
353 if (size < 0)
354 return KRB4ET_RD_AP_UNDEC;
355 size = 8 - (size & 7);
357 ret = krb5_storage_write(sp, eightzeros, size);
358 if (ret != size)
359 return KRB4ET_RD_AP_UNDEC;
361 ret = krb5_storage_to_data(sp, &data);
362 if (ret)
363 return ret;
365 ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
366 if (ret) {
367 krb5_data_free(&data);
368 return ret;
371 ret = krb5_encrypt(context, crypto, 0, data.data, data.length, enc_data);
373 krb5_data_free(&data);
374 krb5_crypto_destroy(context, crypto);
376 return ret;
383 static krb5_error_code
384 put_nir(krb5_storage *sp, const char *name,
385 const char *instance, const char *realm)
387 krb5_error_code ret;
389 RCHECK(ret, krb5_store_stringz(sp, name), error);
390 RCHECK(ret, krb5_store_stringz(sp, instance), error);
391 if (realm) {
392 RCHECK(ret, krb5_store_stringz(sp, realm), error);
394 error:
395 return ret;
402 krb5_error_code KRB5_LIB_FUNCTION
403 _krb5_krb_create_ticket(krb5_context context,
404 unsigned char flags,
405 const char *pname,
406 const char *pinstance,
407 const char *prealm,
408 int32_t paddress,
409 const krb5_keyblock *session,
410 int16_t life,
411 int32_t life_sec,
412 const char *sname,
413 const char *sinstance,
414 const krb5_keyblock *key,
415 krb5_data *enc_data)
417 krb5_error_code ret;
418 krb5_storage *sp;
420 krb5_data_zero(enc_data);
422 sp = krb5_storage_emem();
423 if (sp == NULL) {
424 krb5_set_error_string(context, "malloc: out of memory");
425 return ENOMEM;
427 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
429 RCHECK(ret, krb5_store_int8(sp, flags), error);
430 RCHECK(ret, put_nir(sp, pname, pinstance, prealm), error);
431 RCHECK(ret, krb5_store_int32(sp, ntohl(paddress)), error);
433 /* session key */
434 ret = krb5_storage_write(sp,
435 session->keyvalue.data,
436 session->keyvalue.length);
437 if (ret != session->keyvalue.length) {
438 ret = KRB4ET_INTK_PROT;
439 goto error;
442 RCHECK(ret, krb5_store_int8(sp, life), error);
443 RCHECK(ret, krb5_store_int32(sp, life_sec), error);
444 RCHECK(ret, put_nir(sp, sname, sinstance, NULL), error);
446 ret = storage_to_etext(context, sp, key, enc_data);
448 error:
449 krb5_storage_free(sp);
450 if (ret)
451 krb5_set_error_string(context, "Failed to encode kerberos 4 ticket");
453 return ret;
460 krb5_error_code KRB5_LIB_FUNCTION
461 _krb5_krb_create_ciph(krb5_context context,
462 const krb5_keyblock *session,
463 const char *service,
464 const char *instance,
465 const char *realm,
466 uint32_t life,
467 unsigned char kvno,
468 const krb5_data *ticket,
469 uint32_t kdc_time,
470 const krb5_keyblock *key,
471 krb5_data *enc_data)
473 krb5_error_code ret;
474 krb5_storage *sp;
476 krb5_data_zero(enc_data);
478 sp = krb5_storage_emem();
479 if (sp == NULL) {
480 krb5_set_error_string(context, "malloc: out of memory");
481 return ENOMEM;
483 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
485 /* session key */
486 ret = krb5_storage_write(sp,
487 session->keyvalue.data,
488 session->keyvalue.length);
489 if (ret != session->keyvalue.length) {
490 ret = KRB4ET_INTK_PROT;
491 goto error;
494 RCHECK(ret, put_nir(sp, service, instance, realm), error);
495 RCHECK(ret, krb5_store_int8(sp, life), error);
496 RCHECK(ret, krb5_store_int8(sp, kvno), error);
497 RCHECK(ret, krb5_store_int8(sp, ticket->length), error);
498 ret = krb5_storage_write(sp, ticket->data, ticket->length);
499 if (ret != ticket->length) {
500 ret = KRB4ET_INTK_PROT;
501 goto error;
503 RCHECK(ret, krb5_store_int32(sp, kdc_time), error);
505 ret = storage_to_etext(context, sp, key, enc_data);
507 error:
508 krb5_storage_free(sp);
509 if (ret)
510 krb5_set_error_string(context, "Failed to encode kerberos 4 ticket");
512 return ret;
519 krb5_error_code KRB5_LIB_FUNCTION
520 _krb5_krb_create_auth_reply(krb5_context context,
521 const char *pname,
522 const char *pinst,
523 const char *prealm,
524 int32_t time_ws,
525 int n,
526 uint32_t x_date,
527 unsigned char kvno,
528 const krb5_data *cipher,
529 krb5_data *data)
531 krb5_error_code ret;
532 krb5_storage *sp;
534 krb5_data_zero(data);
536 sp = krb5_storage_emem();
537 if (sp == NULL) {
538 krb5_set_error_string(context, "malloc: out of memory");
539 return ENOMEM;
541 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
543 RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error);
544 RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_KDC_REPLY), error);
545 RCHECK(ret, put_nir(sp, pname, pinst, prealm), error);
546 RCHECK(ret, krb5_store_int32(sp, time_ws), error);
547 RCHECK(ret, krb5_store_int8(sp, n), error);
548 RCHECK(ret, krb5_store_int32(sp, x_date), error);
549 RCHECK(ret, krb5_store_int8(sp, kvno), error);
550 RCHECK(ret, krb5_store_int16(sp, cipher->length), error);
551 ret = krb5_storage_write(sp, cipher->data, cipher->length);
552 if (ret != cipher->length) {
553 ret = KRB4ET_INTK_PROT;
554 goto error;
557 ret = krb5_storage_to_data(sp, data);
559 error:
560 krb5_storage_free(sp);
561 if (ret)
562 krb5_set_error_string(context, "Failed to encode kerberos 4 ticket");
564 return ret;
571 krb5_error_code KRB5_LIB_FUNCTION
572 _krb5_krb_cr_err_reply(krb5_context context,
573 const char *name,
574 const char *inst,
575 const char *realm,
576 uint32_t time_ws,
577 uint32_t e,
578 const char *e_string,
579 krb5_data *data)
581 krb5_error_code ret;
582 krb5_storage *sp;
584 krb5_data_zero(data);
586 if (name == NULL) name = "";
587 if (inst == NULL) inst = "";
588 if (realm == NULL) realm = "";
589 if (e_string == NULL) e_string = "";
591 sp = krb5_storage_emem();
592 if (sp == NULL) {
593 krb5_set_error_string(context, "malloc: out of memory");
594 return ENOMEM;
596 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
598 RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error);
599 RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_ERR_REPLY), error);
600 RCHECK(ret, put_nir(sp, name, inst, realm), error);
601 RCHECK(ret, krb5_store_int32(sp, time_ws), error);
602 /* If it is a Kerberos 4 error-code, remove the et BASE */
603 if (e >= ERROR_TABLE_BASE_krb && e <= ERROR_TABLE_BASE_krb + 255)
604 e -= ERROR_TABLE_BASE_krb;
605 RCHECK(ret, krb5_store_int32(sp, e), error);
606 RCHECK(ret, krb5_store_stringz(sp, e_string), error);
608 ret = krb5_storage_to_data(sp, data);
610 error:
611 krb5_storage_free(sp);
612 if (ret)
613 krb5_set_error_string(context, "Failed to encode kerberos 4 error");
615 return 0;
618 static krb5_error_code
619 get_v4_stringz(krb5_storage *sp, char **str, size_t max_len)
621 krb5_error_code ret;
623 ret = krb5_ret_stringz(sp, str);
624 if (ret)
625 return ret;
626 if (strlen(*str) > max_len) {
627 free(*str);
628 *str = NULL;
629 return KRB4ET_INTK_PROT;
631 return 0;
638 krb5_error_code KRB5_LIB_FUNCTION
639 _krb5_krb_decomp_ticket(krb5_context context,
640 const krb5_data *enc_ticket,
641 const krb5_keyblock *key,
642 const char *local_realm,
643 char **sname,
644 char **sinstance,
645 struct _krb5_krb_auth_data *ad)
647 krb5_error_code ret;
648 krb5_ssize_t size;
649 krb5_storage *sp = NULL;
650 krb5_data ticket;
651 unsigned char des_key[8];
653 memset(ad, 0, sizeof(*ad));
654 krb5_data_zero(&ticket);
656 *sname = NULL;
657 *sinstance = NULL;
659 RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error);
661 sp = krb5_storage_from_data(&ticket);
662 if (sp == NULL) {
663 krb5_data_free(&ticket);
664 krb5_set_error_string(context, "alloc: out of memory");
665 return ENOMEM;
668 krb5_storage_set_eof_code(sp, KRB4ET_INTK_PROT);
670 RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error);
671 RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error);
672 RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error);
673 RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error);
674 RCHECK(ret, krb5_ret_uint32(sp, &ad->address), error);
676 size = krb5_storage_read(sp, des_key, sizeof(des_key));
677 if (size != sizeof(des_key)) {
678 ret = KRB4ET_INTK_PROT;
679 goto error;
682 RCHECK(ret, krb5_ret_uint8(sp, &ad->life), error);
684 if (ad->k_flags & 1)
685 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
686 else
687 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
689 RCHECK(ret, krb5_ret_uint32(sp, &ad->time_sec), error);
691 RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error);
692 RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error);
694 ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE,
695 des_key, sizeof(des_key), &ad->session);
696 if (ret)
697 goto error;
699 if (strlen(ad->prealm) == 0) {
700 free(ad->prealm);
701 ad->prealm = strdup(local_realm);
702 if (ad->prealm == NULL) {
703 ret = ENOMEM;
704 goto error;
708 error:
709 memset(des_key, 0, sizeof(des_key));
710 if (sp)
711 krb5_storage_free(sp);
712 krb5_data_free(&ticket);
713 if (ret) {
714 if (*sname) {
715 free(*sname);
716 *sname = NULL;
718 if (*sinstance) {
719 free(*sinstance);
720 *sinstance = NULL;
722 _krb5_krb_free_auth_data(context, ad);
723 krb5_set_error_string(context, "Failed to decode v4 ticket");
725 return ret;
732 krb5_error_code KRB5_LIB_FUNCTION
733 _krb5_krb_rd_req(krb5_context context,
734 krb5_data *authent,
735 const char *service,
736 const char *instance,
737 const char *local_realm,
738 int32_t from_addr,
739 const krb5_keyblock *key,
740 struct _krb5_krb_auth_data *ad)
742 krb5_error_code ret;
743 krb5_storage *sp;
744 krb5_data ticket, eaut, aut;
745 krb5_ssize_t size;
746 int little_endian;
747 int8_t pvno;
748 int8_t type;
749 int8_t s_kvno;
750 uint8_t ticket_length;
751 uint8_t eaut_length;
752 uint8_t time_5ms;
753 char *realm = NULL;
754 char *sname = NULL;
755 char *sinstance = NULL;
756 char *r_realm = NULL;
757 char *r_name = NULL;
758 char *r_instance = NULL;
760 uint32_t r_time_sec; /* Coarse time from authenticator */
761 unsigned long delta_t; /* Time in authenticator - local time */
762 long tkt_age; /* Age of ticket */
764 struct timeval tv;
766 krb5_data_zero(&ticket);
767 krb5_data_zero(&eaut);
768 krb5_data_zero(&aut);
770 sp = krb5_storage_from_data(authent);
771 if (sp == NULL) {
772 krb5_set_error_string(context, "alloc: out of memory");
773 return ENOMEM;
776 krb5_storage_set_eof_code(sp, KRB4ET_INTK_PROT);
778 ret = krb5_ret_int8(sp, &pvno);
779 if (ret) {
780 krb5_set_error_string(context, "Failed reading v4 pvno");
781 goto error;
784 if (pvno != KRB_PROT_VERSION) {
785 ret = KRB4ET_RD_AP_VERSION;
786 krb5_set_error_string(context, "Failed v4 pvno not 4");
787 goto error;
790 ret = krb5_ret_int8(sp, &type);
791 if (ret) {
792 krb5_set_error_string(context, "Failed readin v4 type");
793 goto error;
796 little_endian = type & 1;
797 type &= ~1;
799 if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) {
800 ret = KRB4ET_RD_AP_MSG_TYPE;
801 krb5_set_error_string(context, "Not a valid v4 request type");
802 goto error;
805 RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error);
806 RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error);
807 RCHECK(ret, krb5_ret_uint8(sp, &ticket_length), error);
808 RCHECK(ret, krb5_ret_uint8(sp, &eaut_length), error);
809 RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error);
811 size = krb5_storage_read(sp, ticket.data, ticket.length);
812 if (size != ticket.length) {
813 ret = KRB4ET_INTK_PROT;
814 krb5_set_error_string(context, "Failed reading v4 ticket");
815 goto error;
818 /* Decrypt and take apart ticket */
819 ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm,
820 &sname, &sinstance, ad);
821 if (ret)
822 goto error;
824 RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error);
826 size = krb5_storage_read(sp, eaut.data, eaut.length);
827 if (size != eaut.length) {
828 ret = KRB4ET_INTK_PROT;
829 krb5_set_error_string(context, "Failed reading v4 authenticator");
830 goto error;
833 krb5_storage_free(sp);
834 sp = NULL;
836 ret = decrypt_etext(context, &ad->session, &eaut, &aut);
837 if (ret)
838 goto error;
840 sp = krb5_storage_from_data(&aut);
841 if (sp == NULL) {
842 ret = ENOMEM;
843 krb5_set_error_string(context, "alloc: out of memory");
844 goto error;
847 if (little_endian)
848 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
849 else
850 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
852 RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error);
853 RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error);
854 RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error);
856 RCHECK(ret, krb5_ret_uint32(sp, &ad->checksum), error);
857 RCHECK(ret, krb5_ret_uint8(sp, &time_5ms), error);
858 RCHECK(ret, krb5_ret_uint32(sp, &r_time_sec), error);
860 if (strcmp(ad->pname, r_name) != 0 ||
861 strcmp(ad->pinst, r_instance) != 0 ||
862 strcmp(ad->prealm, r_realm) != 0) {
863 krb5_set_error_string(context, "v4 principal mismatch");
864 ret = KRB4ET_RD_AP_INCON;
865 goto error;
868 if (from_addr && ad->address && from_addr != ad->address) {
869 krb5_set_error_string(context, "v4 bad address in ticket");
870 ret = KRB4ET_RD_AP_BADD;
871 goto error;
874 gettimeofday(&tv, NULL);
875 delta_t = abs((int)(tv.tv_sec - r_time_sec));
876 if (delta_t > CLOCK_SKEW) {
877 ret = KRB4ET_RD_AP_TIME;
878 krb5_set_error_string(context, "v4 clock skew");
879 goto error;
882 /* Now check for expiration of ticket */
884 tkt_age = tv.tv_sec - ad->time_sec;
886 if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) {
887 ret = KRB4ET_RD_AP_NYV;
888 krb5_set_error_string(context, "v4 clock skew for expiration");
889 goto error;
892 if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) {
893 ret = KRB4ET_RD_AP_EXP;
894 krb5_set_error_string(context, "v4 ticket expired");
895 goto error;
898 ret = 0;
899 error:
900 krb5_data_free(&ticket);
901 krb5_data_free(&eaut);
902 krb5_data_free(&aut);
903 if (realm)
904 free(realm);
905 if (sname)
906 free(sname);
907 if (sinstance)
908 free(sinstance);
909 if (r_name)
910 free(r_name);
911 if (r_instance)
912 free(r_instance);
913 if (r_realm)
914 free(r_realm);
915 if (sp)
916 krb5_storage_free(sp);
918 if (ret)
919 krb5_clear_error_string(context);
921 return ret;
928 void KRB5_LIB_FUNCTION
929 _krb5_krb_free_auth_data(krb5_context context, struct _krb5_krb_auth_data *ad)
931 if (ad->pname)
932 free(ad->pname);
933 if (ad->pinst)
934 free(ad->pinst);
935 if (ad->prealm)
936 free(ad->prealm);
937 krb5_free_keyblock_contents(context, &ad->session);
938 memset(ad, 0, sizeof(*ad));