2 * Copyright (c) 1997 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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 #include "kerberos4.h"
48 #define KA_AUTHENTICATION_SERVICE 731
49 #define KA_TICKET_GRANTING_SERVICE 732
50 #define KA_MAINTENANCE_SERVICE 733
52 #define AUTHENTICATE_OLD 1
53 #define CHANGEPASSWORD 2
54 #define GETTICKET_OLD 3
63 #define GETPASSWORD 12
64 #define GETRANDOMKEY 13
65 #define AUTHENTICATE 21
66 #define AUTHENTICATE_V2 22
69 /* XXX - Where do we get these? */
71 #define RXGEN_OPCODE (-455)
73 #define KADATABASEINCONSISTENT (180480L)
74 #define KAEXIST (180481L)
75 #define KAIO (180482L)
76 #define KACREATEFAIL (180483L)
77 #define KANOENT (180484L)
78 #define KAEMPTY (180485L)
79 #define KABADNAME (180486L)
80 #define KABADINDEX (180487L)
81 #define KANOAUTH (180488L)
82 #define KAANSWERTOOLONG (180489L)
83 #define KABADREQUEST (180490L)
84 #define KAOLDINTERFACE (180491L)
85 #define KABADARGUMENT (180492L)
86 #define KABADCMD (180493L)
87 #define KANOKEYS (180494L)
88 #define KAREADPW (180495L)
89 #define KABADKEY (180496L)
90 #define KAUBIKINIT (180497L)
91 #define KAUBIKCALL (180498L)
92 #define KABADPROTOCOL (180499L)
93 #define KANOCELLS (180500L)
94 #define KANOCELL (180501L)
95 #define KATOOMANYUBIKS (180502L)
96 #define KATOOMANYKEYS (180503L)
97 #define KABADTICKET (180504L)
98 #define KAUNKNOWNKEY (180505L)
99 #define KAKEYCACHEINVALID (180506L)
100 #define KABADSERVER (180507L)
101 #define KABADUSER (180508L)
102 #define KABADCPW (180509L)
103 #define KABADCREATE (180510L)
104 #define KANOTICKET (180511L)
105 #define KAASSOCUSER (180512L)
106 #define KANOTSPECIAL (180513L)
107 #define KACLOCKSKEW (180514L)
108 #define KANORECURSE (180515L)
109 #define KARXFAIL (180516L)
110 #define KANULLPASSWORD (180517L)
111 #define KAINTERNALERROR (180518L)
112 #define KAPWEXPIRED (180519L)
113 #define KAREUSED (180520L)
114 #define KATOOSOON (180521L)
115 #define KALOCKED (180522L)
118 decode_rx_header (krb5_storage
*sp
,
121 krb5_ret_int32(sp
, &h
->epoch
);
122 krb5_ret_int32(sp
, &h
->connid
);
123 krb5_ret_int32(sp
, &h
->callid
);
124 krb5_ret_int32(sp
, &h
->seqno
);
125 krb5_ret_int32(sp
, &h
->serialno
);
126 krb5_ret_int8(sp
, &h
->type
);
127 krb5_ret_int8(sp
, &h
->flags
);
128 krb5_ret_int8(sp
, &h
->status
);
129 krb5_ret_int8(sp
, &h
->secindex
);
130 krb5_ret_int16(sp
, &h
->reserved
);
131 krb5_ret_int16(sp
, &h
->serviceid
);
135 encode_rx_header (struct rx_header
*h
,
138 krb5_store_int32(sp
, h
->epoch
);
139 krb5_store_int32(sp
, h
->connid
);
140 krb5_store_int32(sp
, h
->callid
);
141 krb5_store_int32(sp
, h
->seqno
);
142 krb5_store_int32(sp
, h
->serialno
);
143 krb5_store_int8(sp
, h
->type
);
144 krb5_store_int8(sp
, h
->flags
);
145 krb5_store_int8(sp
, h
->status
);
146 krb5_store_int8(sp
, h
->secindex
);
147 krb5_store_int16(sp
, h
->reserved
);
148 krb5_store_int16(sp
, h
->serviceid
);
152 init_reply_header (struct rx_header
*hdr
,
153 struct rx_header
*reply_hdr
,
157 reply_hdr
->epoch
= hdr
->epoch
;
158 reply_hdr
->connid
= hdr
->connid
;
159 reply_hdr
->callid
= hdr
->callid
;
160 reply_hdr
->seqno
= 1;
161 reply_hdr
->serialno
= 1;
162 reply_hdr
->type
= type
;
163 reply_hdr
->flags
= flags
;
164 reply_hdr
->status
= 0;
165 reply_hdr
->secindex
= 0;
166 reply_hdr
->reserved
= 0;
167 reply_hdr
->serviceid
= hdr
->serviceid
;
171 make_error_reply (struct rx_header
*hdr
,
177 struct rx_header reply_hdr
;
179 init_reply_header (hdr
, &reply_hdr
, HT_ABORT
, HF_LAST
);
180 sp
= krb5_storage_emem();
181 encode_rx_header (&reply_hdr
, sp
);
182 krb5_store_int32(sp
, ret
);
183 krb5_storage_to_data (sp
, reply
);
184 krb5_storage_free (sp
);
187 static krb5_error_code
188 krb5_ret_xdr_data(krb5_storage
*sp
,
193 ret
= krb5_ret_int32(sp
, &size
);
199 size_t pad
= (4 - size
% 4) % 4;
201 data
->data
= malloc(size
);
202 ret
= sp
->fetch(sp
, data
->data
, size
);
204 return (ret
< 0)? errno
: KRB5_CC_END
;
206 ret
= sp
->fetch(sp
, foo
, pad
);
208 return (ret
< 0)? errno
: KRB5_CC_END
;
215 static krb5_error_code
216 krb5_store_xdr_data(krb5_storage
*sp
,
219 u_char zero
[4] = {0, 0, 0, 0};
223 ret
= krb5_store_int32(sp
, data
.length
);
226 ret
= sp
->store(sp
, data
.data
, data
.length
);
227 if(ret
!= data
.length
){
232 pad
= (4 - data
.length
% 4) % 4;
234 ret
= sp
->store(sp
, zero
, pad
);
245 static krb5_error_code
246 create_reply_ticket (struct rx_header
*hdr
,
248 char *name
, char *instance
, char *realm
,
249 struct sockaddr_in
*addr
,
253 char *sname
, char *sinstance
,
263 des_key_schedule schedule
;
264 struct rx_header reply_hdr
;
267 unsigned fyrtiosjuelva
;
269 /* create the ticket */
271 des_new_random_key(&session
);
273 krb_create_ticket (&ticket
, 0, name
, instance
, realm
,
274 addr
->sin_addr
.s_addr
,
275 &session
, life
, kdc_time
,
276 sname
, sinstance
, skey
->key
.keyvalue
.data
);
278 /* create the encrypted part of the reply */
279 sp
= krb5_storage_emem ();
280 krb5_generate_random_block(&fyrtiosjuelva
, sizeof(fyrtiosjuelva
));
281 fyrtiosjuelva
&= 0xffffffff;
282 krb5_store_int32 (sp
, fyrtiosjuelva
);
284 krb5_store_int32 (sp
, 4711); /* XXX */
286 krb5_store_int32 (sp
, challenge
);
287 sp
->store (sp
, session
, 8);
288 memset (&session
, 0, sizeof(session
));
289 krb5_store_int32 (sp
, kdc_time
);
290 krb5_store_int32 (sp
, kdc_time
+ krb_life_to_time (0, life
));
291 krb5_store_int32 (sp
, kvno
);
292 krb5_store_int32 (sp
, ticket
.length
);
293 krb5_store_stringz (sp
, name
);
294 krb5_store_stringz (sp
, instance
);
295 #if 1 /* XXX - Why shouldn't the realm go here? */
296 krb5_store_stringz (sp
, "");
298 krb5_store_stringz (sp
, realm
);
300 krb5_store_stringz (sp
, sname
);
301 krb5_store_stringz (sp
, sinstance
);
302 sp
->store (sp
, ticket
.dat
, ticket
.length
);
303 sp
->store (sp
, label
, strlen(label
));
305 /* pad to DES block */
306 memset (zero
, 0, sizeof(zero
));
307 pad
= (8 - sp
->seek (sp
, 0, SEEK_CUR
) % 8) % 8;
308 sp
->store (sp
, zero
, pad
);
310 krb5_storage_to_data (sp
, &enc_data
);
311 krb5_storage_free (sp
);
313 if (enc_data
.length
> max_seq_len
) {
314 krb5_data_free (&enc_data
);
315 make_error_reply (hdr
, KAANSWERTOOLONG
, reply
);
320 des_set_key (key
, schedule
);
321 des_pcbc_encrypt ((des_cblock
*)enc_data
.data
,
322 (des_cblock
*)enc_data
.data
,
327 memset (&schedule
, 0, sizeof(schedule
));
329 /* create the reply packet */
330 init_reply_header (hdr
, &reply_hdr
, HT_DATA
, HF_LAST
);
331 sp
= krb5_storage_emem ();
332 encode_rx_header (&reply_hdr
, sp
);
333 krb5_store_int32 (sp
, max_seq_len
);
334 krb5_store_xdr_data (sp
, enc_data
);
335 krb5_data_free (&enc_data
);
336 krb5_storage_to_data (sp
, reply
);
337 krb5_storage_free (sp
);
341 static krb5_error_code
342 unparse_auth_args (krb5_storage
*sp
,
348 int32_t *max_seq_len
)
353 krb5_ret_xdr_data (sp
, &data
);
354 *name
= malloc(data
.length
+ 1);
357 memcpy (*name
, data
.data
, data
.length
);
358 (*name
)[data
.length
] = '\0';
359 krb5_data_free (&data
);
361 krb5_ret_xdr_data (sp
, &data
);
362 *instance
= malloc(data
.length
+ 1);
363 if (*instance
== NULL
)
365 memcpy (*instance
, data
.data
, data
.length
);
366 (*instance
)[data
.length
] = '\0';
367 krb5_data_free (&data
);
369 krb5_ret_int32 (sp
, &tmp
);
371 krb5_ret_int32 (sp
, &tmp
);
373 krb5_ret_xdr_data (sp
, request
);
374 krb5_ret_int32 (sp
, max_seq_len
);
375 /* ignore the rest */
380 do_authenticate (struct rx_header
*hdr
,
382 struct sockaddr_in
*addr
,
387 char *instance
= NULL
;
392 hdb_entry
*client_entry
= NULL
;
393 hdb_entry
*server_entry
= NULL
;
397 des_key_schedule schedule
;
398 krb5_storage
*reply_sp
;
403 krb5_data_zero (&request
);
405 unparse_auth_args (sp
, &name
, &instance
, &start_time
, &end_time
,
406 &request
, &max_seq_len
);
408 client_entry
= db_fetch4 (name
, instance
, v4_realm
);
409 if (client_entry
== NULL
) {
410 kdc_log(0, "Client not found in database: %s.%s@%s",
411 name
, instance
, v4_realm
);
412 make_error_reply (hdr
, KANOENT
, reply
);
416 server_entry
= db_fetch4 ("krbtgt", v4_realm
, v4_realm
);
417 if (server_entry
== NULL
) {
418 kdc_log(0, "Server not found in database: %s.%s@%s",
419 "krbtgt", v4_realm
, v4_realm
);
420 make_error_reply (hdr
, KANOENT
, reply
);
425 ret
= hdb_keytype2key(context
, client_entry
, KEYTYPE_DES
, &ckey
);
427 kdc_log(0, "%s", krb5_get_err_text(context
, ret
));
428 make_error_reply (hdr
, KANOKEYS
, reply
);
433 ret
= hdb_keytype2key(context
, server_entry
, KEYTYPE_DES
, &skey
);
435 kdc_log(0, "%s", krb5_get_err_text(context
, ret
));
436 make_error_reply (hdr
, KANOKEYS
, reply
);
440 /* try to decode the `request' */
441 memcpy (&key
, ckey
->key
.keyvalue
.data
, sizeof(key
));
442 des_set_key (&key
, schedule
);
443 des_pcbc_encrypt ((des_cblock
*)request
.data
,
444 (des_cblock
*)request
.data
,
449 memset (&schedule
, 0, sizeof(schedule
));
451 /* check for the magic label */
452 if (memcmp ((char *)request
.data
+ 4, "gTGS", 4) != 0) {
453 make_error_reply (hdr
, KABADREQUEST
, reply
);
457 reply_sp
= krb5_storage_from_mem (request
.data
, 4);
458 krb5_ret_int32 (reply_sp
, &chal
);
459 krb5_storage_free (reply_sp
);
462 max_life
= end_time
- kdc_time
;
463 if (client_entry
->max_life
)
464 max_life
= min(max_life
, *client_entry
->max_life
);
465 if (server_entry
->max_life
)
466 max_life
= min(max_life
, *server_entry
->max_life
);
468 life
= krb_time_to_life(kdc_time
, kdc_time
+ max_life
);
470 create_reply_ticket (hdr
, skey
,
471 name
, instance
, v4_realm
,
472 addr
, life
, client_entry
->kvno
,
477 memset (&key
, 0, sizeof(key
));
480 if (request
.length
) {
481 memset (request
.data
, 0, request
.length
);
482 krb5_data_free (&request
);
489 hdb_free_entry (context
, client_entry
);
493 hdb_free_entry (context
, server_entry
);
498 static krb5_error_code
499 unparse_getticket_args (krb5_storage
*sp
,
506 int32_t *max_seq_len
)
511 krb5_ret_int32 (sp
, &tmp
);
514 krb5_ret_xdr_data (sp
, &data
);
515 *auth_domain
= malloc(data
.length
+ 1);
516 if (*auth_domain
== NULL
)
518 memcpy (*auth_domain
, data
.data
, data
.length
);
519 (*auth_domain
)[data
.length
] = '\0';
520 krb5_data_free (&data
);
522 krb5_ret_xdr_data (sp
, ticket
);
524 krb5_ret_xdr_data (sp
, &data
);
525 *name
= malloc(data
.length
+ 1);
528 memcpy (*name
, data
.data
, data
.length
);
529 (*name
)[data
.length
] = '\0';
530 krb5_data_free (&data
);
532 krb5_ret_xdr_data (sp
, &data
);
533 *instance
= malloc(data
.length
+ 1);
534 if (*instance
== NULL
)
536 memcpy (*instance
, data
.data
, data
.length
);
537 (*instance
)[data
.length
] = '\0';
538 krb5_data_free (&data
);
540 krb5_ret_xdr_data (sp
, times
);
542 krb5_ret_int32 (sp
, max_seq_len
);
543 /* ignore the rest */
548 do_getticket (struct rx_header
*hdr
,
550 struct sockaddr_in
*addr
,
555 char *auth_domain
= NULL
;
558 char *instance
= NULL
;
561 hdb_entry
*server_entry
= NULL
;
562 hdb_entry
*krbtgt_entry
= NULL
;
566 des_key_schedule schedule
;
570 time_t start_time
, end_time
;
571 char pname
[ANAME_SZ
];
573 char prealm
[REALM_SZ
];
575 krb5_data_zero (&aticket
);
576 krb5_data_zero (×
);
578 unparse_getticket_args (sp
, &kvno
, &auth_domain
, &aticket
,
579 &name
, &instance
, ×
, &max_seq_len
);
581 server_entry
= db_fetch4 (name
, instance
, v4_realm
);
582 if (server_entry
== NULL
) {
583 kdc_log(0, "Server not found in database: %s.%s@%s",
584 name
, instance
, v4_realm
);
585 make_error_reply (hdr
, KANOENT
, reply
);
589 krbtgt_entry
= db_fetch4 ("krbtgt", v4_realm
, v4_realm
);
590 if (krbtgt_entry
== NULL
) {
591 kdc_log(0, "Server not found in database: %s.%s@%s",
592 "krbtgt", v4_realm
, v4_realm
);
593 make_error_reply (hdr
, KANOENT
, reply
);
598 ret
= hdb_keytype2key(context
, krbtgt_entry
, KEYTYPE_DES
, &kkey
);
600 kdc_log(0, "%s", krb5_get_err_text(context
, ret
));
601 make_error_reply (hdr
, KANOKEYS
, reply
);
606 ret
= hdb_keytype2key(context
, server_entry
, KEYTYPE_DES
, &skey
);
608 kdc_log(0, "%s", krb5_get_err_text(context
, ret
));
609 make_error_reply (hdr
, KANOKEYS
, reply
);
613 /* decrypt the incoming ticket */
614 memcpy (&key
, kkey
->key
.keyvalue
.data
, sizeof(key
));
616 /* unpack the ticket */
622 char sname
[ANAME_SZ
];
623 char sinstance
[SNAME_SZ
];
626 ticket
.length
= aticket
.length
;
627 memcpy (ticket
.dat
, aticket
.data
, ticket
.length
);
629 des_set_key (&key
, schedule
);
630 decomp_ticket (&ticket
, &flags
, pname
, pinst
, prealm
,
631 &paddress
, session
, &life
, &time_sec
,
635 if (strcmp (sname
, "krbtgt") != 0
636 || strcmp (sinstance
, v4_realm
) != 0) {
637 kdc_log(0, "no TGT: %s.%s for %s.%s@%s",
639 pname
, pinst
, prealm
);
640 make_error_reply (hdr
, KABADTICKET
, reply
);
644 if (kdc_time
> krb_life_to_time(time_sec
, life
)) {
645 kdc_log(0, "TGT expired: %s.%s@%s",
646 pname
, pinst
, prealm
);
647 make_error_reply (hdr
, KABADTICKET
, reply
);
652 /* decrypt the times */
653 des_set_key (&session
, schedule
);
654 des_ecb_encrypt (times
.data
,
658 memset (&schedule
, 0, sizeof(schedule
));
660 /* and extract them */
665 sp
= krb5_storage_from_mem (times
.data
, times
.length
);
666 krb5_ret_int32 (sp
, &tmp
);
668 krb5_ret_int32 (sp
, &tmp
);
670 krb5_storage_free (sp
);
674 max_life
= end_time
- kdc_time
;
675 if (krbtgt_entry
->max_life
)
676 max_life
= min(max_life
, *krbtgt_entry
->max_life
);
677 if (server_entry
->max_life
)
678 max_life
= min(max_life
, *server_entry
->max_life
);
680 life
= krb_time_to_life(kdc_time
, kdc_time
+ max_life
);
682 create_reply_ticket (hdr
, skey
,
683 pname
, pinst
, prealm
,
684 addr
, life
, server_entry
->kvno
,
689 memset (&session
, 0, sizeof(session
));
692 if (aticket
.length
) {
693 memset (aticket
.data
, 0, aticket
.length
);
694 krb5_data_free (&aticket
);
697 memset (times
.data
, 0, times
.length
);
698 krb5_data_free (×
);
707 hdb_free_entry (context
, krbtgt_entry
);
711 hdb_free_entry (context
, server_entry
);
717 do_kaserver(unsigned char *buf
,
721 struct sockaddr_in
*addr
)
723 krb5_error_code ret
= 0;
724 struct rx_header hdr
;
728 if (len
< RX_HEADER_SIZE
)
730 sp
= krb5_storage_from_mem (buf
, len
);
732 decode_rx_header (sp
, &hdr
);
733 buf
+= RX_HEADER_SIZE
;
734 len
-= RX_HEADER_SIZE
;
752 if (hdr
.serviceid
!= KA_AUTHENTICATION_SERVICE
753 && hdr
.serviceid
!= KA_TICKET_GRANTING_SERVICE
) {
758 krb5_ret_int32(sp
, &op
);
761 do_authenticate (&hdr
, sp
, addr
, reply
);
764 do_getticket (&hdr
, sp
, addr
, reply
);
766 case AUTHENTICATE_OLD
:
767 case CHANGEPASSWORD
:
779 case AUTHENTICATE_V2
:
781 make_error_reply (&hdr
, RXGEN_OPCODE
, reply
);
786 krb5_storage_free (sp
);
790 #endif /* KASERVER */