Anton Lundin
[heimdal.git] / kdc / kaserver.c
blob69b5bb1d6e9cfc7f030d48f63a3b3290276f7ce0
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 "kdc_locl.h"
36 #ifdef KRB4
38 #include <krb5-v4compat.h>
39 #include <rx.h>
41 #define KA_AUTHENTICATION_SERVICE 731
42 #define KA_TICKET_GRANTING_SERVICE 732
43 #define KA_MAINTENANCE_SERVICE 733
45 #define AUTHENTICATE_OLD 1
46 #define CHANGEPASSWORD 2
47 #define GETTICKET_OLD 3
48 #define SETPASSWORD 4
49 #define SETFIELDS 5
50 #define CREATEUSER 6
51 #define DELETEUSER 7
52 #define GETENTRY 8
53 #define LISTENTRY 9
54 #define GETSTATS 10
55 #define DEBUG 11
56 #define GETPASSWORD 12
57 #define GETRANDOMKEY 13
58 #define AUTHENTICATE 21
59 #define AUTHENTICATE_V2 22
60 #define GETTICKET 23
62 /* XXX - Where do we get these? */
64 #define RXGEN_OPCODE (-455)
66 #define KADATABASEINCONSISTENT (180480L)
67 #define KAEXIST (180481L)
68 #define KAIO (180482L)
69 #define KACREATEFAIL (180483L)
70 #define KANOENT (180484L)
71 #define KAEMPTY (180485L)
72 #define KABADNAME (180486L)
73 #define KABADINDEX (180487L)
74 #define KANOAUTH (180488L)
75 #define KAANSWERTOOLONG (180489L)
76 #define KABADREQUEST (180490L)
77 #define KAOLDINTERFACE (180491L)
78 #define KABADARGUMENT (180492L)
79 #define KABADCMD (180493L)
80 #define KANOKEYS (180494L)
81 #define KAREADPW (180495L)
82 #define KABADKEY (180496L)
83 #define KAUBIKINIT (180497L)
84 #define KAUBIKCALL (180498L)
85 #define KABADPROTOCOL (180499L)
86 #define KANOCELLS (180500L)
87 #define KANOCELL (180501L)
88 #define KATOOMANYUBIKS (180502L)
89 #define KATOOMANYKEYS (180503L)
90 #define KABADTICKET (180504L)
91 #define KAUNKNOWNKEY (180505L)
92 #define KAKEYCACHEINVALID (180506L)
93 #define KABADSERVER (180507L)
94 #define KABADUSER (180508L)
95 #define KABADCPW (180509L)
96 #define KABADCREATE (180510L)
97 #define KANOTICKET (180511L)
98 #define KAASSOCUSER (180512L)
99 #define KANOTSPECIAL (180513L)
100 #define KACLOCKSKEW (180514L)
101 #define KANORECURSE (180515L)
102 #define KARXFAIL (180516L)
103 #define KANULLPASSWORD (180517L)
104 #define KAINTERNALERROR (180518L)
105 #define KAPWEXPIRED (180519L)
106 #define KAREUSED (180520L)
107 #define KATOOSOON (180521L)
108 #define KALOCKED (180522L)
111 static krb5_error_code
112 decode_rx_header (krb5_storage *sp,
113 struct rx_header *h)
115 krb5_error_code ret;
117 ret = krb5_ret_uint32(sp, &h->epoch);
118 if (ret) return ret;
119 ret = krb5_ret_uint32(sp, &h->connid);
120 if (ret) return ret;
121 ret = krb5_ret_uint32(sp, &h->callid);
122 if (ret) return ret;
123 ret = krb5_ret_uint32(sp, &h->seqno);
124 if (ret) return ret;
125 ret = krb5_ret_uint32(sp, &h->serialno);
126 if (ret) return ret;
127 ret = krb5_ret_uint8(sp, &h->type);
128 if (ret) return ret;
129 ret = krb5_ret_uint8(sp, &h->flags);
130 if (ret) return ret;
131 ret = krb5_ret_uint8(sp, &h->status);
132 if (ret) return ret;
133 ret = krb5_ret_uint8(sp, &h->secindex);
134 if (ret) return ret;
135 ret = krb5_ret_uint16(sp, &h->reserved);
136 if (ret) return ret;
137 ret = krb5_ret_uint16(sp, &h->serviceid);
138 if (ret) return ret;
140 return 0;
143 static krb5_error_code
144 encode_rx_header (struct rx_header *h,
145 krb5_storage *sp)
147 krb5_error_code ret;
149 ret = krb5_store_uint32(sp, h->epoch);
150 if (ret) return ret;
151 ret = krb5_store_uint32(sp, h->connid);
152 if (ret) return ret;
153 ret = krb5_store_uint32(sp, h->callid);
154 if (ret) return ret;
155 ret = krb5_store_uint32(sp, h->seqno);
156 if (ret) return ret;
157 ret = krb5_store_uint32(sp, h->serialno);
158 if (ret) return ret;
159 ret = krb5_store_uint8(sp, h->type);
160 if (ret) return ret;
161 ret = krb5_store_uint8(sp, h->flags);
162 if (ret) return ret;
163 ret = krb5_store_uint8(sp, h->status);
164 if (ret) return ret;
165 ret = krb5_store_uint8(sp, h->secindex);
166 if (ret) return ret;
167 ret = krb5_store_uint16(sp, h->reserved);
168 if (ret) return ret;
169 ret = krb5_store_uint16(sp, h->serviceid);
170 if (ret) return ret;
172 return 0;
175 static void
176 init_reply_header (struct rx_header *hdr,
177 struct rx_header *reply_hdr,
178 u_char type,
179 u_char flags)
181 reply_hdr->epoch = hdr->epoch;
182 reply_hdr->connid = hdr->connid;
183 reply_hdr->callid = hdr->callid;
184 reply_hdr->seqno = 1;
185 reply_hdr->serialno = 1;
186 reply_hdr->type = type;
187 reply_hdr->flags = flags;
188 reply_hdr->status = 0;
189 reply_hdr->secindex = 0;
190 reply_hdr->reserved = 0;
191 reply_hdr->serviceid = hdr->serviceid;
195 * Create an error `reply´ using for the packet `hdr' with the error
196 * `error´ code.
198 static void
199 make_error_reply (struct rx_header *hdr,
200 uint32_t error,
201 krb5_data *reply)
204 struct rx_header reply_hdr;
205 krb5_error_code ret;
206 krb5_storage *sp;
208 init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST);
209 sp = krb5_storage_emem();
210 if (sp == NULL)
211 return;
212 ret = encode_rx_header (&reply_hdr, sp);
213 if (ret)
214 return;
215 krb5_store_int32(sp, error);
216 krb5_storage_to_data (sp, reply);
217 krb5_storage_free (sp);
220 static krb5_error_code
221 krb5_ret_xdr_data(krb5_storage *sp,
222 krb5_data *data)
224 int ret;
225 int size;
226 ret = krb5_ret_int32(sp, &size);
227 if(ret)
228 return ret;
229 if(size < 0)
230 return ERANGE;
231 data->length = size;
232 if (size) {
233 u_char foo[4];
234 size_t pad = (4 - size % 4) % 4;
236 data->data = malloc(size);
237 if (data->data == NULL)
238 return ENOMEM;
239 ret = krb5_storage_read(sp, data->data, size);
240 if(ret != size)
241 return (ret < 0)? errno : KRB5_CC_END;
242 if (pad) {
243 ret = krb5_storage_read(sp, foo, pad);
244 if (ret != pad)
245 return (ret < 0)? errno : KRB5_CC_END;
247 } else
248 data->data = NULL;
249 return 0;
252 static krb5_error_code
253 krb5_store_xdr_data(krb5_storage *sp,
254 krb5_data data)
256 u_char zero[4] = {0, 0, 0, 0};
257 int ret;
258 size_t pad;
260 ret = krb5_store_int32(sp, data.length);
261 if(ret < 0)
262 return ret;
263 ret = krb5_storage_write(sp, data.data, data.length);
264 if(ret != data.length){
265 if(ret < 0)
266 return errno;
267 return KRB5_CC_END;
269 pad = (4 - data.length % 4) % 4;
270 if (pad) {
271 ret = krb5_storage_write(sp, zero, pad);
272 if (ret != pad) {
273 if (ret < 0)
274 return errno;
275 return KRB5_CC_END;
278 return 0;
282 static krb5_error_code
283 create_reply_ticket (krb5_context context,
284 struct rx_header *hdr,
285 Key *skey,
286 char *name, char *instance, char *realm,
287 struct sockaddr_in *addr,
288 int life,
289 int kvno,
290 int32_t max_seq_len,
291 const char *sname, const char *sinstance,
292 uint32_t challenge,
293 const char *label,
294 krb5_keyblock *key,
295 krb5_data *reply)
297 krb5_error_code ret;
298 krb5_data ticket;
299 krb5_keyblock session;
300 krb5_storage *sp;
301 krb5_data enc_data;
302 struct rx_header reply_hdr;
303 char zero[8];
304 size_t pad;
305 unsigned fyrtiosjuelva;
307 /* create the ticket */
309 krb5_generate_random_keyblock(context, ETYPE_DES_PCBC_NONE, &session);
311 _krb5_krb_create_ticket(context,
313 name,
314 instance,
315 realm,
316 addr->sin_addr.s_addr,
317 &session,
318 life,
319 kdc_time,
320 sname,
321 sinstance,
322 &skey->key,
323 &ticket);
325 /* create the encrypted part of the reply */
326 sp = krb5_storage_emem ();
327 krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva));
328 fyrtiosjuelva &= 0xffffffff;
329 krb5_store_int32 (sp, fyrtiosjuelva);
330 krb5_store_int32 (sp, challenge);
331 krb5_storage_write (sp, session.keyvalue.data, 8);
332 krb5_free_keyblock_contents(context, &session);
333 krb5_store_int32 (sp, kdc_time);
334 krb5_store_int32 (sp, kdc_time + _krb5_krb_life_to_time (0, life));
335 krb5_store_int32 (sp, kvno);
336 krb5_store_int32 (sp, ticket.length);
337 krb5_store_stringz (sp, name);
338 krb5_store_stringz (sp, instance);
339 #if 1 /* XXX - Why shouldn't the realm go here? */
340 krb5_store_stringz (sp, "");
341 #else
342 krb5_store_stringz (sp, realm);
343 #endif
344 krb5_store_stringz (sp, sname);
345 krb5_store_stringz (sp, sinstance);
346 krb5_storage_write (sp, ticket.data, ticket.length);
347 krb5_storage_write (sp, label, strlen(label));
349 /* pad to DES block */
350 memset (zero, 0, sizeof(zero));
351 pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8;
352 krb5_storage_write (sp, zero, pad);
354 krb5_storage_to_data (sp, &enc_data);
355 krb5_storage_free (sp);
357 if (enc_data.length > max_seq_len) {
358 krb5_data_free (&enc_data);
359 make_error_reply (hdr, KAANSWERTOOLONG, reply);
360 return 0;
363 /* encrypt it */
365 DES_key_schedule schedule;
366 DES_cblock deskey;
368 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
369 DES_set_key_unchecked (&deskey, &schedule);
370 DES_pcbc_encrypt (enc_data.data,
371 enc_data.data,
372 enc_data.length,
373 &schedule,
374 &deskey,
375 DES_ENCRYPT);
376 memset (&schedule, 0, sizeof(schedule));
377 memset (&deskey, 0, sizeof(deskey));
380 /* create the reply packet */
381 init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST);
382 sp = krb5_storage_emem ();
383 ret = encode_rx_header (&reply_hdr, sp);
384 krb5_store_int32 (sp, max_seq_len);
385 krb5_store_xdr_data (sp, enc_data);
386 krb5_data_free (&enc_data);
387 krb5_storage_to_data (sp, reply);
388 krb5_storage_free (sp);
389 return 0;
392 static krb5_error_code
393 unparse_auth_args (krb5_storage *sp,
394 char **name,
395 char **instance,
396 time_t *start_time,
397 time_t *end_time,
398 krb5_data *request,
399 int32_t *max_seq_len)
401 krb5_data data;
402 int32_t tmp;
404 krb5_ret_xdr_data (sp, &data);
405 *name = malloc(data.length + 1);
406 if (*name == NULL)
407 return ENOMEM;
408 memcpy (*name, data.data, data.length);
409 (*name)[data.length] = '\0';
410 krb5_data_free (&data);
412 krb5_ret_xdr_data (sp, &data);
413 *instance = malloc(data.length + 1);
414 if (*instance == NULL) {
415 free (*name);
416 return ENOMEM;
418 memcpy (*instance, data.data, data.length);
419 (*instance)[data.length] = '\0';
420 krb5_data_free (&data);
422 krb5_ret_int32 (sp, &tmp);
423 *start_time = tmp;
424 krb5_ret_int32 (sp, &tmp);
425 *end_time = tmp;
426 krb5_ret_xdr_data (sp, request);
427 krb5_ret_int32 (sp, max_seq_len);
428 /* ignore the rest */
429 return 0;
432 static void
433 do_authenticate (krb5_context context,
434 krb5_kdc_configuration *config,
435 struct rx_header *hdr,
436 krb5_storage *sp,
437 struct sockaddr_in *addr,
438 const char *from,
439 krb5_data *reply)
441 krb5_error_code ret;
442 char *name = NULL;
443 char *instance = NULL;
444 time_t start_time;
445 time_t end_time;
446 krb5_data request;
447 int32_t max_seq_len;
448 hdb_entry_ex *client_entry = NULL;
449 hdb_entry_ex *server_entry = NULL;
450 Key *ckey = NULL;
451 Key *skey = NULL;
452 krb5_storage *reply_sp;
453 time_t max_life;
454 uint8_t life;
455 int32_t chal;
456 char client_name[256];
457 char server_name[256];
459 krb5_data_zero (&request);
461 ret = unparse_auth_args (sp, &name, &instance, &start_time, &end_time,
462 &request, &max_seq_len);
463 if (ret != 0 || request.length < 8) {
464 make_error_reply (hdr, KABADREQUEST, reply);
465 goto out;
468 snprintf (client_name, sizeof(client_name), "%s.%s@%s",
469 name, instance, config->v4_realm);
470 snprintf (server_name, sizeof(server_name), "%s.%s@%s",
471 "krbtgt", config->v4_realm, config->v4_realm);
473 kdc_log(context, config, 0, "AS-REQ (kaserver) %s from %s for %s",
474 client_name, from, server_name);
476 ret = _kdc_db_fetch4 (context, config, name, instance,
477 config->v4_realm, HDB_F_GET_CLIENT,
478 &client_entry);
479 if (ret) {
480 kdc_log(context, config, 0, "Client not found in database: %s: %s",
481 client_name, krb5_get_err_text(context, ret));
482 make_error_reply (hdr, KANOENT, reply);
483 goto out;
486 ret = _kdc_db_fetch4 (context, config, "krbtgt",
487 config->v4_realm, config->v4_realm,
488 HDB_F_GET_KRBTGT, &server_entry);
489 if (ret) {
490 kdc_log(context, config, 0, "Server not found in database: %s: %s",
491 server_name, krb5_get_err_text(context, ret));
492 make_error_reply (hdr, KANOENT, reply);
493 goto out;
496 ret = kdc_check_flags (context, config,
497 client_entry, client_name,
498 server_entry, server_name,
499 TRUE);
500 if (ret) {
501 make_error_reply (hdr, KAPWEXPIRED, reply);
502 goto out;
505 /* find a DES key */
506 ret = _kdc_get_des_key(context, client_entry, FALSE, TRUE, &ckey);
507 if(ret){
508 kdc_log(context, config, 0, "no suitable DES key for client");
509 make_error_reply (hdr, KANOKEYS, reply);
510 goto out;
513 /* find a DES key */
514 ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
515 if(ret){
516 kdc_log(context, config, 0, "no suitable DES key for server");
517 make_error_reply (hdr, KANOKEYS, reply);
518 goto out;
522 DES_cblock key;
523 DES_key_schedule schedule;
525 /* try to decode the `request' */
526 memcpy (&key, ckey->key.keyvalue.data, sizeof(key));
527 DES_set_key_unchecked (&key, &schedule);
528 DES_pcbc_encrypt (request.data,
529 request.data,
530 request.length,
531 &schedule,
532 &key,
533 DES_DECRYPT);
534 memset (&schedule, 0, sizeof(schedule));
535 memset (&key, 0, sizeof(key));
538 /* check for the magic label */
539 if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) {
540 kdc_log(context, config, 0, "preauth failed for %s", client_name);
541 make_error_reply (hdr, KABADREQUEST, reply);
542 goto out;
545 reply_sp = krb5_storage_from_mem (request.data, 4);
546 krb5_ret_int32 (reply_sp, &chal);
547 krb5_storage_free (reply_sp);
549 if (abs(chal - kdc_time) > context->max_skew) {
550 make_error_reply (hdr, KACLOCKSKEW, reply);
551 goto out;
554 /* life */
555 max_life = end_time - kdc_time;
556 /* end_time - kdc_time can sometimes be non-positive due to slight
557 time skew between client and server. Let's make sure it is postive */
558 if(max_life < 1)
559 max_life = 1;
560 if (client_entry->entry.max_life)
561 max_life = min(max_life, *client_entry->entry.max_life);
562 if (server_entry->entry.max_life)
563 max_life = min(max_life, *server_entry->entry.max_life);
565 life = krb_time_to_life(kdc_time, kdc_time + max_life);
567 create_reply_ticket (context,
568 hdr, skey,
569 name, instance, config->v4_realm,
570 addr, life, server_entry->entry.kvno,
571 max_seq_len,
572 "krbtgt", config->v4_realm,
573 chal + 1, "tgsT",
574 &ckey->key, reply);
576 out:
577 if (request.length) {
578 memset (request.data, 0, request.length);
579 krb5_data_free (&request);
581 if (name)
582 free (name);
583 if (instance)
584 free (instance);
585 if (client_entry)
586 _kdc_free_ent (context, client_entry);
587 if (server_entry)
588 _kdc_free_ent (context, server_entry);
591 static krb5_error_code
592 unparse_getticket_args (krb5_storage *sp,
593 int *kvno,
594 char **auth_domain,
595 krb5_data *ticket,
596 char **name,
597 char **instance,
598 krb5_data *times,
599 int32_t *max_seq_len)
601 krb5_data data;
602 int32_t tmp;
604 krb5_ret_int32 (sp, &tmp);
605 *kvno = tmp;
607 krb5_ret_xdr_data (sp, &data);
608 *auth_domain = malloc(data.length + 1);
609 if (*auth_domain == NULL)
610 return ENOMEM;
611 memcpy (*auth_domain, data.data, data.length);
612 (*auth_domain)[data.length] = '\0';
613 krb5_data_free (&data);
615 krb5_ret_xdr_data (sp, ticket);
617 krb5_ret_xdr_data (sp, &data);
618 *name = malloc(data.length + 1);
619 if (*name == NULL) {
620 free (*auth_domain);
621 return ENOMEM;
623 memcpy (*name, data.data, data.length);
624 (*name)[data.length] = '\0';
625 krb5_data_free (&data);
627 krb5_ret_xdr_data (sp, &data);
628 *instance = malloc(data.length + 1);
629 if (*instance == NULL) {
630 free (*auth_domain);
631 free (*name);
632 return ENOMEM;
634 memcpy (*instance, data.data, data.length);
635 (*instance)[data.length] = '\0';
636 krb5_data_free (&data);
638 krb5_ret_xdr_data (sp, times);
640 krb5_ret_int32 (sp, max_seq_len);
641 /* ignore the rest */
642 return 0;
645 static void
646 do_getticket (krb5_context context,
647 krb5_kdc_configuration *config,
648 struct rx_header *hdr,
649 krb5_storage *sp,
650 struct sockaddr_in *addr,
651 const char *from,
652 krb5_data *reply)
654 krb5_error_code ret;
655 int kvno;
656 char *auth_domain = NULL;
657 krb5_data aticket;
658 char *name = NULL;
659 char *instance = NULL;
660 krb5_data times;
661 int32_t max_seq_len;
662 hdb_entry_ex *server_entry = NULL;
663 hdb_entry_ex *client_entry = NULL;
664 hdb_entry_ex *krbtgt_entry = NULL;
665 Key *kkey = NULL;
666 Key *skey = NULL;
667 DES_cblock key;
668 DES_key_schedule schedule;
669 DES_cblock session;
670 time_t max_life;
671 int8_t life;
672 time_t start_time, end_time;
673 char server_name[256];
674 char client_name[256];
675 struct _krb5_krb_auth_data ad;
677 krb5_data_zero (&aticket);
678 krb5_data_zero (&times);
680 memset(&ad, 0, sizeof(ad));
682 unparse_getticket_args (sp, &kvno, &auth_domain, &aticket,
683 &name, &instance, &times, &max_seq_len);
684 if (times.length < 8) {
685 make_error_reply (hdr, KABADREQUEST, reply);
686 goto out;
690 snprintf (server_name, sizeof(server_name),
691 "%s.%s@%s", name, instance, config->v4_realm);
693 ret = _kdc_db_fetch4 (context, config, name, instance,
694 config->v4_realm, HDB_F_GET_SERVER, &server_entry);
695 if (ret) {
696 kdc_log(context, config, 0, "Server not found in database: %s: %s",
697 server_name, krb5_get_err_text(context, ret));
698 make_error_reply (hdr, KANOENT, reply);
699 goto out;
702 ret = _kdc_db_fetch4 (context, config, "krbtgt",
703 config->v4_realm, config->v4_realm, HDB_F_GET_KRBTGT, &krbtgt_entry);
704 if (ret) {
705 kdc_log(context, config, 0,
706 "Server not found in database: %s.%s@%s: %s",
707 "krbtgt", config->v4_realm, config->v4_realm,
708 krb5_get_err_text(context, ret));
709 make_error_reply (hdr, KANOENT, reply);
710 goto out;
713 /* find a DES key */
714 ret = _kdc_get_des_key(context, krbtgt_entry, TRUE, TRUE, &kkey);
715 if(ret){
716 kdc_log(context, config, 0, "no suitable DES key for krbtgt");
717 make_error_reply (hdr, KANOKEYS, reply);
718 goto out;
721 /* find a DES key */
722 ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
723 if(ret){
724 kdc_log(context, config, 0, "no suitable DES key for server");
725 make_error_reply (hdr, KANOKEYS, reply);
726 goto out;
729 /* decrypt the incoming ticket */
730 memcpy (&key, kkey->key.keyvalue.data, sizeof(key));
732 /* unpack the ticket */
734 char *sname = NULL;
735 char *sinstance = NULL;
737 ret = _krb5_krb_decomp_ticket(context, &aticket, &kkey->key,
738 config->v4_realm, &sname,
739 &sinstance, &ad);
740 if (ret) {
741 kdc_log(context, config, 0,
742 "kaserver: decomp failed for %s.%s with %d",
743 sname, sinstance, ret);
744 make_error_reply (hdr, KABADTICKET, reply);
745 goto out;
748 if (strcmp (sname, "krbtgt") != 0
749 || strcmp (sinstance, config->v4_realm) != 0) {
750 kdc_log(context, config, 0, "no TGT: %s.%s for %s.%s@%s",
751 sname, sinstance,
752 ad.pname, ad.pinst, ad.prealm);
753 make_error_reply (hdr, KABADTICKET, reply);
754 free(sname);
755 free(sinstance);
756 goto out;
758 free(sname);
759 free(sinstance);
761 if (kdc_time > _krb5_krb_life_to_time(ad.time_sec, ad.life)) {
762 kdc_log(context, config, 0, "TGT expired: %s.%s@%s",
763 ad.pname, ad.pinst, ad.prealm);
764 make_error_reply (hdr, KABADTICKET, reply);
765 goto out;
769 snprintf (client_name, sizeof(client_name),
770 "%s.%s@%s", ad.pname, ad.pinst, ad.prealm);
772 kdc_log(context, config, 0, "TGS-REQ (kaserver) %s from %s for %s",
773 client_name, from, server_name);
775 ret = _kdc_db_fetch4 (context, config,
776 ad.pname, ad.pinst, ad.prealm, HDB_F_GET_CLIENT,
777 &client_entry);
778 if(ret && ret != HDB_ERR_NOENTRY) {
779 kdc_log(context, config, 0,
780 "Client not found in database: (krb4) %s: %s",
781 client_name, krb5_get_err_text(context, ret));
782 make_error_reply (hdr, KANOENT, reply);
783 goto out;
785 if (client_entry == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
786 kdc_log(context, config, 0,
787 "Local client not found in database: (krb4) "
788 "%s", client_name);
789 make_error_reply (hdr, KANOENT, reply);
790 goto out;
793 ret = kdc_check_flags (context, config,
794 client_entry, client_name,
795 server_entry, server_name,
796 FALSE);
797 if (ret) {
798 make_error_reply (hdr, KAPWEXPIRED, reply);
799 goto out;
802 /* decrypt the times */
803 memcpy(&session, ad.session.keyvalue.data, sizeof(session));
804 DES_set_key_unchecked (&session, &schedule);
805 DES_ecb_encrypt (times.data,
806 times.data,
807 &schedule,
808 DES_DECRYPT);
809 memset (&schedule, 0, sizeof(schedule));
810 memset (&session, 0, sizeof(session));
812 /* and extract them */
814 krb5_storage *tsp;
815 int32_t tmp;
817 tsp = krb5_storage_from_mem (times.data, times.length);
818 krb5_ret_int32 (tsp, &tmp);
819 start_time = tmp;
820 krb5_ret_int32 (tsp, &tmp);
821 end_time = tmp;
822 krb5_storage_free (tsp);
825 /* life */
826 max_life = end_time - kdc_time;
827 /* end_time - kdc_time can sometimes be non-positive due to slight
828 time skew between client and server. Let's make sure it is postive */
829 if(max_life < 1)
830 max_life = 1;
831 if (krbtgt_entry->entry.max_life)
832 max_life = min(max_life, *krbtgt_entry->entry.max_life);
833 if (server_entry->entry.max_life)
834 max_life = min(max_life, *server_entry->entry.max_life);
835 /* if this is a cross realm request, the client_entry will likely
836 be NULL */
837 if (client_entry && client_entry->entry.max_life)
838 max_life = min(max_life, *client_entry->entry.max_life);
840 life = _krb5_krb_time_to_life(kdc_time, kdc_time + max_life);
842 create_reply_ticket (context,
843 hdr, skey,
844 ad.pname, ad.pinst, ad.prealm,
845 addr, life, server_entry->entry.kvno,
846 max_seq_len,
847 name, instance,
848 0, "gtkt",
849 &ad.session, reply);
851 out:
852 _krb5_krb_free_auth_data(context, &ad);
853 if (aticket.length) {
854 memset (aticket.data, 0, aticket.length);
855 krb5_data_free (&aticket);
857 if (times.length) {
858 memset (times.data, 0, times.length);
859 krb5_data_free (&times);
861 if (auth_domain)
862 free (auth_domain);
863 if (name)
864 free (name);
865 if (instance)
866 free (instance);
867 if (krbtgt_entry)
868 _kdc_free_ent (context, krbtgt_entry);
869 if (server_entry)
870 _kdc_free_ent (context, server_entry);
873 krb5_error_code
874 _kdc_do_kaserver(krb5_context context,
875 krb5_kdc_configuration *config,
876 unsigned char *buf,
877 size_t len,
878 krb5_data *reply,
879 const char *from,
880 struct sockaddr_in *addr)
882 krb5_error_code ret = 0;
883 struct rx_header hdr;
884 uint32_t op;
885 krb5_storage *sp;
887 if (len < RX_HEADER_SIZE)
888 return -1;
889 sp = krb5_storage_from_mem (buf, len);
891 ret = decode_rx_header (sp, &hdr);
892 if (ret)
893 goto out;
894 buf += RX_HEADER_SIZE;
895 len -= RX_HEADER_SIZE;
897 switch (hdr.type) {
898 case HT_DATA :
899 break;
900 case HT_ACK :
901 case HT_BUSY :
902 case HT_ABORT :
903 case HT_ACKALL :
904 case HT_CHAL :
905 case HT_RESP :
906 case HT_DEBUG :
907 default:
908 /* drop */
909 goto out;
913 if (hdr.serviceid != KA_AUTHENTICATION_SERVICE
914 && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) {
915 ret = -1;
916 goto out;
919 ret = krb5_ret_uint32(sp, &op);
920 if (ret)
921 goto out;
922 switch (op) {
923 case AUTHENTICATE :
924 case AUTHENTICATE_V2 :
925 do_authenticate (context, config, &hdr, sp, addr, from, reply);
926 break;
927 case GETTICKET :
928 do_getticket (context, config, &hdr, sp, addr, from, reply);
929 break;
930 case AUTHENTICATE_OLD :
931 case CHANGEPASSWORD :
932 case GETTICKET_OLD :
933 case SETPASSWORD :
934 case SETFIELDS :
935 case CREATEUSER :
936 case DELETEUSER :
937 case GETENTRY :
938 case LISTENTRY :
939 case GETSTATS :
940 case DEBUG :
941 case GETPASSWORD :
942 case GETRANDOMKEY :
943 default :
944 make_error_reply (&hdr, RXGEN_OPCODE, reply);
945 break;
948 out:
949 krb5_storage_free (sp);
950 return ret;
953 #endif /* KRB4 */