Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / crypto / dist / heimdal / kdc / kaserver.c
blob4454e0653f31993120e516945ac6f35c704f95c1
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 __RCSID("$Heimdal: kaserver.c 21654 2007-07-21 17:30:18Z lha $"
37 "$NetBSD$");
39 #include <krb5-v4compat.h>
40 #include <rx.h>
42 #define KA_AUTHENTICATION_SERVICE 731
43 #define KA_TICKET_GRANTING_SERVICE 732
44 #define KA_MAINTENANCE_SERVICE 733
46 #define AUTHENTICATE_OLD 1
47 #define CHANGEPASSWORD 2
48 #define GETTICKET_OLD 3
49 #define SETPASSWORD 4
50 #define SETFIELDS 5
51 #define CREATEUSER 6
52 #define DELETEUSER 7
53 #define GETENTRY 8
54 #define LISTENTRY 9
55 #define GETSTATS 10
56 #define DEBUG 11
57 #define GETPASSWORD 12
58 #define GETRANDOMKEY 13
59 #define AUTHENTICATE 21
60 #define AUTHENTICATE_V2 22
61 #define GETTICKET 23
63 /* XXX - Where do we get these? */
65 #define RXGEN_OPCODE (-455)
67 #define KADATABASEINCONSISTENT (180480L)
68 #define KAEXIST (180481L)
69 #define KAIO (180482L)
70 #define KACREATEFAIL (180483L)
71 #define KANOENT (180484L)
72 #define KAEMPTY (180485L)
73 #define KABADNAME (180486L)
74 #define KABADINDEX (180487L)
75 #define KANOAUTH (180488L)
76 #define KAANSWERTOOLONG (180489L)
77 #define KABADREQUEST (180490L)
78 #define KAOLDINTERFACE (180491L)
79 #define KABADARGUMENT (180492L)
80 #define KABADCMD (180493L)
81 #define KANOKEYS (180494L)
82 #define KAREADPW (180495L)
83 #define KABADKEY (180496L)
84 #define KAUBIKINIT (180497L)
85 #define KAUBIKCALL (180498L)
86 #define KABADPROTOCOL (180499L)
87 #define KANOCELLS (180500L)
88 #define KANOCELL (180501L)
89 #define KATOOMANYUBIKS (180502L)
90 #define KATOOMANYKEYS (180503L)
91 #define KABADTICKET (180504L)
92 #define KAUNKNOWNKEY (180505L)
93 #define KAKEYCACHEINVALID (180506L)
94 #define KABADSERVER (180507L)
95 #define KABADUSER (180508L)
96 #define KABADCPW (180509L)
97 #define KABADCREATE (180510L)
98 #define KANOTICKET (180511L)
99 #define KAASSOCUSER (180512L)
100 #define KANOTSPECIAL (180513L)
101 #define KACLOCKSKEW (180514L)
102 #define KANORECURSE (180515L)
103 #define KARXFAIL (180516L)
104 #define KANULLPASSWORD (180517L)
105 #define KAINTERNALERROR (180518L)
106 #define KAPWEXPIRED (180519L)
107 #define KAREUSED (180520L)
108 #define KATOOSOON (180521L)
109 #define KALOCKED (180522L)
112 static krb5_error_code
113 decode_rx_header (krb5_storage *sp,
114 struct rx_header *h)
116 krb5_error_code ret;
118 ret = krb5_ret_uint32(sp, &h->epoch);
119 if (ret) return ret;
120 ret = krb5_ret_uint32(sp, &h->connid);
121 if (ret) return ret;
122 ret = krb5_ret_uint32(sp, &h->callid);
123 if (ret) return ret;
124 ret = krb5_ret_uint32(sp, &h->seqno);
125 if (ret) return ret;
126 ret = krb5_ret_uint32(sp, &h->serialno);
127 if (ret) return ret;
128 ret = krb5_ret_uint8(sp, &h->type);
129 if (ret) return ret;
130 ret = krb5_ret_uint8(sp, &h->flags);
131 if (ret) return ret;
132 ret = krb5_ret_uint8(sp, &h->status);
133 if (ret) return ret;
134 ret = krb5_ret_uint8(sp, &h->secindex);
135 if (ret) return ret;
136 ret = krb5_ret_uint16(sp, &h->reserved);
137 if (ret) return ret;
138 ret = krb5_ret_uint16(sp, &h->serviceid);
139 if (ret) return ret;
141 return 0;
144 static krb5_error_code
145 encode_rx_header (struct rx_header *h,
146 krb5_storage *sp)
148 krb5_error_code ret;
150 ret = krb5_store_uint32(sp, h->epoch);
151 if (ret) return ret;
152 ret = krb5_store_uint32(sp, h->connid);
153 if (ret) return ret;
154 ret = krb5_store_uint32(sp, h->callid);
155 if (ret) return ret;
156 ret = krb5_store_uint32(sp, h->seqno);
157 if (ret) return ret;
158 ret = krb5_store_uint32(sp, h->serialno);
159 if (ret) return ret;
160 ret = krb5_store_uint8(sp, h->type);
161 if (ret) return ret;
162 ret = krb5_store_uint8(sp, h->flags);
163 if (ret) return ret;
164 ret = krb5_store_uint8(sp, h->status);
165 if (ret) return ret;
166 ret = krb5_store_uint8(sp, h->secindex);
167 if (ret) return ret;
168 ret = krb5_store_uint16(sp, h->reserved);
169 if (ret) return ret;
170 ret = krb5_store_uint16(sp, h->serviceid);
171 if (ret) return ret;
173 return 0;
176 static void
177 init_reply_header (struct rx_header *hdr,
178 struct rx_header *reply_hdr,
179 u_char type,
180 u_char flags)
182 reply_hdr->epoch = hdr->epoch;
183 reply_hdr->connid = hdr->connid;
184 reply_hdr->callid = hdr->callid;
185 reply_hdr->seqno = 1;
186 reply_hdr->serialno = 1;
187 reply_hdr->type = type;
188 reply_hdr->flags = flags;
189 reply_hdr->status = 0;
190 reply_hdr->secindex = 0;
191 reply_hdr->reserved = 0;
192 reply_hdr->serviceid = hdr->serviceid;
196 * Create an error `reply´ using for the packet `hdr' with the error
197 * `error´ code.
199 static void
200 make_error_reply (struct rx_header *hdr,
201 uint32_t error,
202 krb5_data *reply)
205 struct rx_header reply_hdr;
206 krb5_error_code ret;
207 krb5_storage *sp;
209 init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST);
210 sp = krb5_storage_emem();
211 if (sp == NULL)
212 return;
213 ret = encode_rx_header (&reply_hdr, sp);
214 if (ret)
215 return;
216 krb5_store_int32(sp, error);
217 krb5_storage_to_data (sp, reply);
218 krb5_storage_free (sp);
221 static krb5_error_code
222 krb5_ret_xdr_data(krb5_storage *sp,
223 krb5_data *data)
225 int ret;
226 int size;
227 ret = krb5_ret_int32(sp, &size);
228 if(ret)
229 return ret;
230 if(size < 0)
231 return ERANGE;
232 data->length = size;
233 if (size) {
234 u_char foo[4];
235 size_t pad = (4 - size % 4) % 4;
237 data->data = malloc(size);
238 if (data->data == NULL)
239 return ENOMEM;
240 ret = krb5_storage_read(sp, data->data, size);
241 if(ret != size)
242 return (ret < 0)? errno : KRB5_CC_END;
243 if (pad) {
244 ret = krb5_storage_read(sp, foo, pad);
245 if (ret != pad)
246 return (ret < 0)? errno : KRB5_CC_END;
248 } else
249 data->data = NULL;
250 return 0;
253 static krb5_error_code
254 krb5_store_xdr_data(krb5_storage *sp,
255 krb5_data data)
257 u_char zero[4] = {0, 0, 0, 0};
258 int ret;
259 size_t pad;
261 ret = krb5_store_int32(sp, data.length);
262 if(ret < 0)
263 return ret;
264 ret = krb5_storage_write(sp, data.data, data.length);
265 if(ret != data.length){
266 if(ret < 0)
267 return errno;
268 return KRB5_CC_END;
270 pad = (4 - data.length % 4) % 4;
271 if (pad) {
272 ret = krb5_storage_write(sp, zero, pad);
273 if (ret != pad) {
274 if (ret < 0)
275 return errno;
276 return KRB5_CC_END;
279 return 0;
283 static krb5_error_code
284 create_reply_ticket (krb5_context context,
285 struct rx_header *hdr,
286 Key *skey,
287 char *name, char *instance, char *realm,
288 struct sockaddr_in *addr,
289 int life,
290 int kvno,
291 int32_t max_seq_len,
292 const char *sname, const char *sinstance,
293 uint32_t challenge,
294 const char *label,
295 krb5_keyblock *key,
296 krb5_data *reply)
298 krb5_error_code ret;
299 krb5_data ticket;
300 krb5_keyblock session;
301 krb5_storage *sp;
302 krb5_data enc_data;
303 struct rx_header reply_hdr;
304 char zero[8];
305 size_t pad;
306 unsigned fyrtiosjuelva;
308 /* create the ticket */
310 krb5_generate_random_keyblock(context, ETYPE_DES_PCBC_NONE, &session);
312 _krb5_krb_create_ticket(context,
314 name,
315 instance,
316 realm,
317 addr->sin_addr.s_addr,
318 &session,
319 life,
320 kdc_time,
321 sname,
322 sinstance,
323 &skey->key,
324 &ticket);
326 /* create the encrypted part of the reply */
327 sp = krb5_storage_emem ();
328 krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva));
329 fyrtiosjuelva &= 0xffffffff;
330 krb5_store_int32 (sp, fyrtiosjuelva);
331 krb5_store_int32 (sp, challenge);
332 krb5_storage_write (sp, session.keyvalue.data, 8);
333 krb5_free_keyblock_contents(context, &session);
334 krb5_store_int32 (sp, kdc_time);
335 krb5_store_int32 (sp, kdc_time + _krb5_krb_life_to_time (0, life));
336 krb5_store_int32 (sp, kvno);
337 krb5_store_int32 (sp, ticket.length);
338 krb5_store_stringz (sp, name);
339 krb5_store_stringz (sp, instance);
340 #if 1 /* XXX - Why shouldn't the realm go here? */
341 krb5_store_stringz (sp, "");
342 #else
343 krb5_store_stringz (sp, realm);
344 #endif
345 krb5_store_stringz (sp, sname);
346 krb5_store_stringz (sp, sinstance);
347 krb5_storage_write (sp, ticket.data, ticket.length);
348 krb5_storage_write (sp, label, strlen(label));
350 /* pad to DES block */
351 memset (zero, 0, sizeof(zero));
352 pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8;
353 krb5_storage_write (sp, zero, pad);
355 krb5_storage_to_data (sp, &enc_data);
356 krb5_storage_free (sp);
358 if (enc_data.length > max_seq_len) {
359 krb5_data_free (&enc_data);
360 make_error_reply (hdr, KAANSWERTOOLONG, reply);
361 return 0;
364 /* encrypt it */
366 DES_key_schedule schedule;
367 DES_cblock deskey;
369 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
370 DES_set_key (&deskey, &schedule);
371 DES_pcbc_encrypt (enc_data.data,
372 enc_data.data,
373 enc_data.length,
374 &schedule,
375 &deskey,
376 DES_ENCRYPT);
377 memset (&schedule, 0, sizeof(schedule));
378 memset (&deskey, 0, sizeof(deskey));
381 /* create the reply packet */
382 init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST);
383 sp = krb5_storage_emem ();
384 ret = encode_rx_header (&reply_hdr, sp);
385 krb5_store_int32 (sp, max_seq_len);
386 krb5_store_xdr_data (sp, enc_data);
387 krb5_data_free (&enc_data);
388 krb5_storage_to_data (sp, reply);
389 krb5_storage_free (sp);
390 return 0;
393 static krb5_error_code
394 unparse_auth_args (krb5_storage *sp,
395 char **name,
396 char **instance,
397 time_t *start_time,
398 time_t *end_time,
399 krb5_data *request,
400 int32_t *max_seq_len)
402 krb5_data data;
403 int32_t tmp;
405 krb5_ret_xdr_data (sp, &data);
406 *name = malloc(data.length + 1);
407 if (*name == NULL)
408 return ENOMEM;
409 memcpy (*name, data.data, data.length);
410 (*name)[data.length] = '\0';
411 krb5_data_free (&data);
413 krb5_ret_xdr_data (sp, &data);
414 *instance = malloc(data.length + 1);
415 if (*instance == NULL) {
416 free (*name);
417 return ENOMEM;
419 memcpy (*instance, data.data, data.length);
420 (*instance)[data.length] = '\0';
421 krb5_data_free (&data);
423 krb5_ret_int32 (sp, &tmp);
424 *start_time = tmp;
425 krb5_ret_int32 (sp, &tmp);
426 *end_time = tmp;
427 krb5_ret_xdr_data (sp, request);
428 krb5_ret_int32 (sp, max_seq_len);
429 /* ignore the rest */
430 return 0;
433 static void
434 do_authenticate (krb5_context context,
435 krb5_kdc_configuration *config,
436 struct rx_header *hdr,
437 krb5_storage *sp,
438 struct sockaddr_in *addr,
439 const char *from,
440 krb5_data *reply)
442 krb5_error_code ret;
443 char *name = NULL;
444 char *instance = NULL;
445 time_t start_time;
446 time_t end_time;
447 krb5_data request;
448 int32_t max_seq_len;
449 hdb_entry_ex *client_entry = NULL;
450 hdb_entry_ex *server_entry = NULL;
451 Key *ckey = NULL;
452 Key *skey = NULL;
453 krb5_storage *reply_sp;
454 time_t max_life;
455 uint8_t life;
456 int32_t chal;
457 char client_name[256];
458 char server_name[256];
460 krb5_data_zero (&request);
462 ret = unparse_auth_args (sp, &name, &instance, &start_time, &end_time,
463 &request, &max_seq_len);
464 if (ret != 0 || request.length < 8) {
465 make_error_reply (hdr, KABADREQUEST, reply);
466 goto out;
469 snprintf (client_name, sizeof(client_name), "%s.%s@%s",
470 name, instance, config->v4_realm);
471 snprintf (server_name, sizeof(server_name), "%s.%s@%s",
472 "krbtgt", config->v4_realm, config->v4_realm);
474 kdc_log(context, config, 0, "AS-REQ (kaserver) %s from %s for %s",
475 client_name, from, server_name);
477 ret = _kdc_db_fetch4 (context, config, name, instance,
478 config->v4_realm, HDB_F_GET_CLIENT,
479 &client_entry);
480 if (ret) {
481 kdc_log(context, config, 0, "Client not found in database: %s: %s",
482 client_name, krb5_get_err_text(context, ret));
483 make_error_reply (hdr, KANOENT, reply);
484 goto out;
487 ret = _kdc_db_fetch4 (context, config, "krbtgt",
488 config->v4_realm, config->v4_realm,
489 HDB_F_GET_KRBTGT, &server_entry);
490 if (ret) {
491 kdc_log(context, config, 0, "Server not found in database: %s: %s",
492 server_name, krb5_get_err_text(context, ret));
493 make_error_reply (hdr, KANOENT, reply);
494 goto out;
497 ret = _kdc_check_flags (context, config,
498 client_entry, client_name,
499 server_entry, server_name,
500 TRUE);
501 if (ret) {
502 make_error_reply (hdr, KAPWEXPIRED, reply);
503 goto out;
506 /* find a DES key */
507 ret = _kdc_get_des_key(context, client_entry, FALSE, TRUE, &ckey);
508 if(ret){
509 kdc_log(context, config, 0, "no suitable DES key for client");
510 make_error_reply (hdr, KANOKEYS, reply);
511 goto out;
514 /* find a DES key */
515 ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
516 if(ret){
517 kdc_log(context, config, 0, "no suitable DES key for server");
518 make_error_reply (hdr, KANOKEYS, reply);
519 goto out;
523 DES_cblock key;
524 DES_key_schedule schedule;
526 /* try to decode the `request' */
527 memcpy (&key, ckey->key.keyvalue.data, sizeof(key));
528 DES_set_key (&key, &schedule);
529 DES_pcbc_encrypt (request.data,
530 request.data,
531 request.length,
532 &schedule,
533 &key,
534 DES_DECRYPT);
535 memset (&schedule, 0, sizeof(schedule));
536 memset (&key, 0, sizeof(key));
539 /* check for the magic label */
540 if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) {
541 kdc_log(context, config, 0, "preauth failed for %s", client_name);
542 make_error_reply (hdr, KABADREQUEST, reply);
543 goto out;
546 reply_sp = krb5_storage_from_mem (request.data, 4);
547 krb5_ret_int32 (reply_sp, &chal);
548 krb5_storage_free (reply_sp);
550 if (abs(chal - kdc_time) > context->max_skew) {
551 make_error_reply (hdr, KACLOCKSKEW, reply);
552 goto out;
555 /* life */
556 max_life = end_time - kdc_time;
557 /* end_time - kdc_time can sometimes be non-positive due to slight
558 time skew between client and server. Let's make sure it is postive */
559 if(max_life < 1)
560 max_life = 1;
561 if (client_entry->entry.max_life)
562 max_life = min(max_life, *client_entry->entry.max_life);
563 if (server_entry->entry.max_life)
564 max_life = min(max_life, *server_entry->entry.max_life);
566 life = krb_time_to_life(kdc_time, kdc_time + max_life);
568 create_reply_ticket (context,
569 hdr, skey,
570 name, instance, config->v4_realm,
571 addr, life, server_entry->entry.kvno,
572 max_seq_len,
573 "krbtgt", config->v4_realm,
574 chal + 1, "tgsT",
575 &ckey->key, reply);
577 out:
578 if (request.length) {
579 memset (request.data, 0, request.length);
580 krb5_data_free (&request);
582 if (name)
583 free (name);
584 if (instance)
585 free (instance);
586 if (client_entry)
587 _kdc_free_ent (context, client_entry);
588 if (server_entry)
589 _kdc_free_ent (context, server_entry);
592 static krb5_error_code
593 unparse_getticket_args (krb5_storage *sp,
594 int *kvno,
595 char **auth_domain,
596 krb5_data *ticket,
597 char **name,
598 char **instance,
599 krb5_data *times,
600 int32_t *max_seq_len)
602 krb5_data data;
603 int32_t tmp;
605 krb5_ret_int32 (sp, &tmp);
606 *kvno = tmp;
608 krb5_ret_xdr_data (sp, &data);
609 *auth_domain = malloc(data.length + 1);
610 if (*auth_domain == NULL)
611 return ENOMEM;
612 memcpy (*auth_domain, data.data, data.length);
613 (*auth_domain)[data.length] = '\0';
614 krb5_data_free (&data);
616 krb5_ret_xdr_data (sp, ticket);
618 krb5_ret_xdr_data (sp, &data);
619 *name = malloc(data.length + 1);
620 if (*name == NULL) {
621 free (*auth_domain);
622 return ENOMEM;
624 memcpy (*name, data.data, data.length);
625 (*name)[data.length] = '\0';
626 krb5_data_free (&data);
628 krb5_ret_xdr_data (sp, &data);
629 *instance = malloc(data.length + 1);
630 if (*instance == NULL) {
631 free (*auth_domain);
632 free (*name);
633 return ENOMEM;
635 memcpy (*instance, data.data, data.length);
636 (*instance)[data.length] = '\0';
637 krb5_data_free (&data);
639 krb5_ret_xdr_data (sp, times);
641 krb5_ret_int32 (sp, max_seq_len);
642 /* ignore the rest */
643 return 0;
646 static void
647 do_getticket (krb5_context context,
648 krb5_kdc_configuration *config,
649 struct rx_header *hdr,
650 krb5_storage *sp,
651 struct sockaddr_in *addr,
652 const char *from,
653 krb5_data *reply)
655 krb5_error_code ret;
656 int kvno;
657 char *auth_domain = NULL;
658 krb5_data aticket;
659 char *name = NULL;
660 char *instance = NULL;
661 krb5_data times;
662 int32_t max_seq_len;
663 hdb_entry_ex *server_entry = NULL;
664 hdb_entry_ex *client_entry = NULL;
665 hdb_entry_ex *krbtgt_entry = NULL;
666 Key *kkey = NULL;
667 Key *skey = NULL;
668 DES_cblock key;
669 DES_key_schedule schedule;
670 DES_cblock session;
671 time_t max_life;
672 int8_t life;
673 time_t start_time, end_time;
674 char server_name[256];
675 char client_name[256];
676 struct _krb5_krb_auth_data ad;
678 krb5_data_zero (&aticket);
679 krb5_data_zero (&times);
681 memset(&ad, 0, sizeof(ad));
683 unparse_getticket_args (sp, &kvno, &auth_domain, &aticket,
684 &name, &instance, &times, &max_seq_len);
685 if (times.length < 8) {
686 make_error_reply (hdr, KABADREQUEST, reply);
687 goto out;
691 snprintf (server_name, sizeof(server_name),
692 "%s.%s@%s", name, instance, config->v4_realm);
694 ret = _kdc_db_fetch4 (context, config, name, instance,
695 config->v4_realm, HDB_F_GET_SERVER, &server_entry);
696 if (ret) {
697 kdc_log(context, config, 0, "Server not found in database: %s: %s",
698 server_name, krb5_get_err_text(context, ret));
699 make_error_reply (hdr, KANOENT, reply);
700 goto out;
703 ret = _kdc_db_fetch4 (context, config, "krbtgt",
704 config->v4_realm, config->v4_realm, HDB_F_GET_KRBTGT, &krbtgt_entry);
705 if (ret) {
706 kdc_log(context, config, 0,
707 "Server not found in database: %s.%s@%s: %s",
708 "krbtgt", config->v4_realm, config->v4_realm,
709 krb5_get_err_text(context, ret));
710 make_error_reply (hdr, KANOENT, reply);
711 goto out;
714 /* find a DES key */
715 ret = _kdc_get_des_key(context, krbtgt_entry, TRUE, TRUE, &kkey);
716 if(ret){
717 kdc_log(context, config, 0, "no suitable DES key for krbtgt");
718 make_error_reply (hdr, KANOKEYS, reply);
719 goto out;
722 /* find a DES key */
723 ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
724 if(ret){
725 kdc_log(context, config, 0, "no suitable DES key for server");
726 make_error_reply (hdr, KANOKEYS, reply);
727 goto out;
730 /* decrypt the incoming ticket */
731 memcpy (&key, kkey->key.keyvalue.data, sizeof(key));
733 /* unpack the ticket */
735 char *sname = NULL;
736 char *sinstance = NULL;
738 ret = _krb5_krb_decomp_ticket(context, &aticket, &kkey->key,
739 config->v4_realm, &sname,
740 &sinstance, &ad);
741 if (ret) {
742 kdc_log(context, config, 0,
743 "kaserver: decomp failed for %s.%s with %d",
744 sname, sinstance, ret);
745 make_error_reply (hdr, KABADTICKET, reply);
746 goto out;
749 if (strcmp (sname, "krbtgt") != 0
750 || strcmp (sinstance, config->v4_realm) != 0) {
751 kdc_log(context, config, 0, "no TGT: %s.%s for %s.%s@%s",
752 sname, sinstance,
753 ad.pname, ad.pinst, ad.prealm);
754 make_error_reply (hdr, KABADTICKET, reply);
755 free(sname);
756 free(sinstance);
757 goto out;
759 free(sname);
760 free(sinstance);
762 if (kdc_time > _krb5_krb_life_to_time(ad.time_sec, ad.life)) {
763 kdc_log(context, config, 0, "TGT expired: %s.%s@%s",
764 ad.pname, ad.pinst, ad.prealm);
765 make_error_reply (hdr, KABADTICKET, reply);
766 goto out;
770 snprintf (client_name, sizeof(client_name),
771 "%s.%s@%s", ad.pname, ad.pinst, ad.prealm);
773 kdc_log(context, config, 0, "TGS-REQ (kaserver) %s from %s for %s",
774 client_name, from, server_name);
776 ret = _kdc_db_fetch4 (context, config,
777 ad.pname, ad.pinst, ad.prealm, HDB_F_GET_CLIENT,
778 &client_entry);
779 if(ret && ret != HDB_ERR_NOENTRY) {
780 kdc_log(context, config, 0,
781 "Client not found in database: (krb4) %s: %s",
782 client_name, krb5_get_err_text(context, ret));
783 make_error_reply (hdr, KANOENT, reply);
784 goto out;
786 if (client_entry == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
787 kdc_log(context, config, 0,
788 "Local client not found in database: (krb4) "
789 "%s", client_name);
790 make_error_reply (hdr, KANOENT, reply);
791 goto out;
794 ret = _kdc_check_flags (context, config,
795 client_entry, client_name,
796 server_entry, server_name,
797 FALSE);
798 if (ret) {
799 make_error_reply (hdr, KAPWEXPIRED, reply);
800 goto out;
803 /* decrypt the times */
804 memcpy(&session, ad.session.keyvalue.data, sizeof(session));
805 DES_set_key (&session, &schedule);
806 DES_ecb_encrypt (times.data,
807 times.data,
808 &schedule,
809 DES_DECRYPT);
810 memset (&schedule, 0, sizeof(schedule));
811 memset (&session, 0, sizeof(session));
813 /* and extract them */
815 krb5_storage *tsp;
816 int32_t tmp;
818 tsp = krb5_storage_from_mem (times.data, times.length);
819 krb5_ret_int32 (tsp, &tmp);
820 start_time = tmp;
821 krb5_ret_int32 (tsp, &tmp);
822 end_time = tmp;
823 krb5_storage_free (tsp);
826 /* life */
827 max_life = end_time - kdc_time;
828 /* end_time - kdc_time can sometimes be non-positive due to slight
829 time skew between client and server. Let's make sure it is postive */
830 if(max_life < 1)
831 max_life = 1;
832 if (krbtgt_entry->entry.max_life)
833 max_life = min(max_life, *krbtgt_entry->entry.max_life);
834 if (server_entry->entry.max_life)
835 max_life = min(max_life, *server_entry->entry.max_life);
836 /* if this is a cross realm request, the client_entry will likely
837 be NULL */
838 if (client_entry && client_entry->entry.max_life)
839 max_life = min(max_life, *client_entry->entry.max_life);
841 life = _krb5_krb_time_to_life(kdc_time, kdc_time + max_life);
843 create_reply_ticket (context,
844 hdr, skey,
845 ad.pname, ad.pinst, ad.prealm,
846 addr, life, server_entry->entry.kvno,
847 max_seq_len,
848 name, instance,
849 0, "gtkt",
850 &ad.session, reply);
852 out:
853 _krb5_krb_free_auth_data(context, &ad);
854 if (aticket.length) {
855 memset (aticket.data, 0, aticket.length);
856 krb5_data_free (&aticket);
858 if (times.length) {
859 memset (times.data, 0, times.length);
860 krb5_data_free (&times);
862 if (auth_domain)
863 free (auth_domain);
864 if (name)
865 free (name);
866 if (instance)
867 free (instance);
868 if (krbtgt_entry)
869 _kdc_free_ent (context, krbtgt_entry);
870 if (server_entry)
871 _kdc_free_ent (context, server_entry);
874 krb5_error_code
875 _kdc_do_kaserver(krb5_context context,
876 krb5_kdc_configuration *config,
877 unsigned char *buf,
878 size_t len,
879 krb5_data *reply,
880 const char *from,
881 struct sockaddr_in *addr)
883 krb5_error_code ret = 0;
884 struct rx_header hdr;
885 uint32_t op;
886 krb5_storage *sp;
888 if (len < RX_HEADER_SIZE)
889 return -1;
890 sp = krb5_storage_from_mem (buf, len);
892 ret = decode_rx_header (sp, &hdr);
893 if (ret)
894 goto out;
895 buf += RX_HEADER_SIZE;
896 len -= RX_HEADER_SIZE;
898 switch (hdr.type) {
899 case HT_DATA :
900 break;
901 case HT_ACK :
902 case HT_BUSY :
903 case HT_ABORT :
904 case HT_ACKALL :
905 case HT_CHAL :
906 case HT_RESP :
907 case HT_DEBUG :
908 default:
909 /* drop */
910 goto out;
914 if (hdr.serviceid != KA_AUTHENTICATION_SERVICE
915 && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) {
916 ret = -1;
917 goto out;
920 ret = krb5_ret_uint32(sp, &op);
921 if (ret)
922 goto out;
923 switch (op) {
924 case AUTHENTICATE :
925 case AUTHENTICATE_V2 :
926 do_authenticate (context, config, &hdr, sp, addr, from, reply);
927 break;
928 case GETTICKET :
929 do_getticket (context, config, &hdr, sp, addr, from, reply);
930 break;
931 case AUTHENTICATE_OLD :
932 case CHANGEPASSWORD :
933 case GETTICKET_OLD :
934 case SETPASSWORD :
935 case SETFIELDS :
936 case CREATEUSER :
937 case DELETEUSER :
938 case GETENTRY :
939 case LISTENTRY :
940 case GETSTATS :
941 case DEBUG :
942 case GETPASSWORD :
943 case GETRANDOMKEY :
944 default :
945 make_error_reply (&hdr, RXGEN_OPCODE, reply);
946 break;
949 out:
950 krb5_storage_free (sp);
951 return ret;