Merge from vendor branch BSDTAR:
[dragonfly.git] / crypto / heimdal-0.6.3 / kdc / kaserver.c
1 /*
2  * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
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. 
16  *
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. 
20  *
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. 
32  */
33
34 #include "kdc_locl.h"
35
36 RCSID("$Id: kaserver.c,v 1.21.2.1 2003/10/06 21:02:35 lha Exp $");
37
38
39 #include <rx.h>
40
41 #define KA_AUTHENTICATION_SERVICE 731
42 #define KA_TICKET_GRANTING_SERVICE 732
43 #define KA_MAINTENANCE_SERVICE 733
44
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
61
62 /* XXX - Where do we get these? */
63
64 #define RXGEN_OPCODE (-455)
65
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)
109
110 static void
111 decode_rx_header (krb5_storage *sp,
112                   struct rx_header *h)
113 {
114     krb5_ret_int32(sp, &h->epoch);
115     krb5_ret_int32(sp, &h->connid);
116     krb5_ret_int32(sp, &h->callid);
117     krb5_ret_int32(sp, &h->seqno);
118     krb5_ret_int32(sp, &h->serialno);
119     krb5_ret_int8(sp,  &h->type);
120     krb5_ret_int8(sp,  &h->flags);
121     krb5_ret_int8(sp,  &h->status);
122     krb5_ret_int8(sp,  &h->secindex);
123     krb5_ret_int16(sp, &h->reserved);
124     krb5_ret_int16(sp, &h->serviceid);
125 }
126
127 static void
128 encode_rx_header (struct rx_header *h,
129                   krb5_storage *sp)
130 {
131     krb5_store_int32(sp, h->epoch);
132     krb5_store_int32(sp, h->connid);
133     krb5_store_int32(sp, h->callid);
134     krb5_store_int32(sp, h->seqno);
135     krb5_store_int32(sp, h->serialno);
136     krb5_store_int8(sp,  h->type);
137     krb5_store_int8(sp,  h->flags);
138     krb5_store_int8(sp,  h->status);
139     krb5_store_int8(sp,  h->secindex);
140     krb5_store_int16(sp, h->reserved);
141     krb5_store_int16(sp, h->serviceid);
142 }
143
144 static void
145 init_reply_header (struct rx_header *hdr,
146                    struct rx_header *reply_hdr,
147                    u_char type,
148                    u_char flags)
149 {
150     reply_hdr->epoch     = hdr->epoch;
151     reply_hdr->connid    = hdr->connid;
152     reply_hdr->callid    = hdr->callid;
153     reply_hdr->seqno     = 1;
154     reply_hdr->serialno  = 1;
155     reply_hdr->type      = type;
156     reply_hdr->flags     = flags;
157     reply_hdr->status    = 0;
158     reply_hdr->secindex  = 0;
159     reply_hdr->reserved  = 0;
160     reply_hdr->serviceid = hdr->serviceid;
161 }
162
163 static void
164 make_error_reply (struct rx_header *hdr,
165                   u_int32_t ret,
166                   krb5_data *reply)
167
168 {
169     krb5_storage *sp;
170     struct rx_header reply_hdr;
171
172     init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST);
173     sp = krb5_storage_emem();
174     encode_rx_header (&reply_hdr, sp);
175     krb5_store_int32(sp, ret);
176     krb5_storage_to_data (sp, reply);
177     krb5_storage_free (sp);
178 }
179
180 static krb5_error_code
181 krb5_ret_xdr_data(krb5_storage *sp,
182                   krb5_data *data)
183 {
184     int ret;
185     int size;
186     ret = krb5_ret_int32(sp, &size);
187     if(ret)
188         return ret;
189     if(size < 0)
190         return ERANGE;
191     data->length = size;
192     if (size) {
193         u_char foo[4];
194         size_t pad = (4 - size % 4) % 4;
195
196         data->data = malloc(size);
197         if (data->data == NULL)
198             return ENOMEM;
199         ret = krb5_storage_read(sp, data->data, size);
200         if(ret != size)
201             return (ret < 0)? errno : KRB5_CC_END;
202         if (pad) {
203             ret = krb5_storage_read(sp, foo, pad);
204             if (ret != pad)
205                 return (ret < 0)? errno : KRB5_CC_END;
206         }
207     } else
208         data->data = NULL;
209     return 0;
210 }
211
212 static krb5_error_code
213 krb5_store_xdr_data(krb5_storage *sp,
214                     krb5_data data)
215 {
216     u_char zero[4] = {0, 0, 0, 0};
217     int ret;
218     size_t pad;
219
220     ret = krb5_store_int32(sp, data.length);
221     if(ret < 0)
222         return ret;
223     ret = krb5_storage_write(sp, data.data, data.length);
224     if(ret != data.length){
225         if(ret < 0)
226             return errno;
227         return KRB5_CC_END;
228     }
229     pad = (4 - data.length % 4) % 4;
230     if (pad) {
231         ret = krb5_storage_write(sp, zero, pad);
232         if (ret != pad) {
233             if (ret < 0)
234                 return errno;
235             return KRB5_CC_END;
236         }
237     }
238     return 0;
239 }
240
241
242 static krb5_error_code
243 create_reply_ticket (struct rx_header *hdr,
244                      Key *skey,
245                      char *name, char *instance, char *realm,
246                      struct sockaddr_in *addr,
247                      int life,
248                      int kvno,
249                      int32_t max_seq_len,
250                      const char *sname, const char *sinstance,
251                      u_int32_t challenge,
252                      const char *label,
253                      des_cblock *key,
254                      krb5_data *reply)
255 {
256     KTEXT_ST ticket;
257     des_cblock session;
258     krb5_storage *sp;
259     krb5_data enc_data;
260     des_key_schedule schedule;
261     struct rx_header reply_hdr;
262     des_cblock zero;
263     size_t pad;
264     unsigned fyrtiosjuelva;
265
266     /* create the ticket */
267
268     des_new_random_key(&session);
269
270     krb_create_ticket (&ticket, 0, name, instance, realm,
271                        addr->sin_addr.s_addr,
272                        &session, life, kdc_time,
273                        sname, sinstance, skey->key.keyvalue.data);
274
275     /* create the encrypted part of the reply */
276     sp = krb5_storage_emem ();
277     krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva));
278     fyrtiosjuelva &= 0xffffffff;
279     krb5_store_int32 (sp, fyrtiosjuelva);
280     krb5_store_int32 (sp, challenge);
281     krb5_storage_write  (sp, session, 8);
282     memset (&session, 0, sizeof(session));
283     krb5_store_int32 (sp, kdc_time);
284     krb5_store_int32 (sp, kdc_time + krb_life_to_time (0, life));
285     krb5_store_int32 (sp, kvno);
286     krb5_store_int32 (sp, ticket.length);
287     krb5_store_stringz (sp, name);
288     krb5_store_stringz (sp, instance);
289 #if 1 /* XXX - Why shouldn't the realm go here? */
290     krb5_store_stringz (sp, "");
291 #else
292     krb5_store_stringz (sp, realm);
293 #endif
294     krb5_store_stringz (sp, sname);
295     krb5_store_stringz (sp, sinstance);
296     krb5_storage_write (sp, ticket.dat, ticket.length);
297     krb5_storage_write (sp, label, strlen(label));
298
299     /* pad to DES block */
300     memset (zero, 0, sizeof(zero));
301     pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8;
302     krb5_storage_write (sp, zero, pad);
303
304     krb5_storage_to_data (sp, &enc_data);
305     krb5_storage_free (sp);
306
307     if (enc_data.length > max_seq_len) {
308         krb5_data_free (&enc_data);
309         make_error_reply (hdr, KAANSWERTOOLONG, reply);
310         return 0;
311     }
312
313     /* encrypt it */
314     des_set_key (key, schedule);
315     des_pcbc_encrypt (enc_data.data,
316                       enc_data.data,
317                       enc_data.length,
318                       schedule,
319                       key,
320                       DES_ENCRYPT);
321     memset (&schedule, 0, sizeof(schedule));
322
323     /* create the reply packet */
324     init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST);
325     sp = krb5_storage_emem ();
326     encode_rx_header (&reply_hdr, sp);
327     krb5_store_int32 (sp, max_seq_len);
328     krb5_store_xdr_data (sp, enc_data);
329     krb5_data_free (&enc_data);
330     krb5_storage_to_data (sp, reply);
331     krb5_storage_free (sp);
332     return 0;
333 }
334
335 static krb5_error_code
336 unparse_auth_args (krb5_storage *sp,
337                    char **name,
338                    char **instance,
339                    time_t *start_time,
340                    time_t *end_time,
341                    krb5_data *request,
342                    int32_t *max_seq_len)
343 {
344     krb5_data data;
345     int32_t tmp;
346
347     krb5_ret_xdr_data (sp, &data);
348     *name = malloc(data.length + 1);
349     if (*name == NULL)
350         return ENOMEM;
351     memcpy (*name, data.data, data.length);
352     (*name)[data.length] = '\0';
353     krb5_data_free (&data);
354
355     krb5_ret_xdr_data (sp, &data);
356     *instance = malloc(data.length + 1);
357     if (*instance == NULL) {
358         free (*name);
359         return ENOMEM;
360     }
361     memcpy (*instance, data.data, data.length);
362     (*instance)[data.length] = '\0';
363     krb5_data_free (&data);
364
365     krb5_ret_int32 (sp, &tmp);
366     *start_time = tmp;
367     krb5_ret_int32 (sp, &tmp);
368     *end_time = tmp;
369     krb5_ret_xdr_data (sp, request);
370     krb5_ret_int32 (sp, max_seq_len);
371     /* ignore the rest */
372     return 0;
373 }
374
375 static void
376 do_authenticate (struct rx_header *hdr,
377                  krb5_storage *sp,
378                  struct sockaddr_in *addr,
379                  krb5_data *reply)
380 {
381     krb5_error_code ret;
382     char *name = NULL;
383     char *instance = NULL;
384     time_t start_time;
385     time_t end_time;
386     krb5_data request;
387     int32_t max_seq_len;
388     hdb_entry *client_entry = NULL;
389     hdb_entry *server_entry = NULL;
390     Key *ckey = NULL;
391     Key *skey = NULL;
392     des_cblock key;
393     des_key_schedule schedule;
394     krb5_storage *reply_sp;
395     time_t max_life;
396     u_int8_t life;
397     int32_t chal;
398     char client_name[256];
399     char server_name[256];
400         
401     krb5_data_zero (&request);
402
403     unparse_auth_args (sp, &name, &instance, &start_time, &end_time,
404                        &request, &max_seq_len);
405     if (request.length < 8) {
406         make_error_reply (hdr, KABADREQUEST, reply);
407         goto out;
408     }
409
410     snprintf (client_name, sizeof(client_name), "%s.%s@%s",
411               name, instance, v4_realm);
412
413     ret = db_fetch4 (name, instance, v4_realm, &client_entry);
414     if (ret) {
415         kdc_log(0, "Client not found in database: %s: %s",
416                 client_name, krb5_get_err_text(context, ret));
417         make_error_reply (hdr, KANOENT, reply);
418         goto out;
419     }
420
421     snprintf (server_name, sizeof(server_name), "%s.%s@%s",
422               "krbtgt", v4_realm, v4_realm);
423
424     ret = db_fetch4 ("krbtgt", v4_realm, v4_realm, &server_entry);
425     if (ret) {
426         kdc_log(0, "Server not found in database: %s: %s",
427                 server_name, krb5_get_err_text(context, ret));
428         make_error_reply (hdr, KANOENT, reply);
429         goto out;
430     }
431
432     ret = check_flags (client_entry, client_name,
433                        server_entry, server_name,
434                        TRUE);
435     if (ret) {
436         make_error_reply (hdr, KAPWEXPIRED, reply);
437         goto out;
438     }
439
440     /* find a DES key */
441     ret = get_des_key(client_entry, FALSE, TRUE, &ckey);
442     if(ret){
443         kdc_log(0, "no suitable DES key for client");
444         make_error_reply (hdr, KANOKEYS, reply);
445         goto out;
446     }
447
448     /* find a DES key */
449     ret = get_des_key(server_entry, TRUE, TRUE, &skey);
450     if(ret){
451         kdc_log(0, "no suitable DES key for server");
452         make_error_reply (hdr, KANOKEYS, reply);
453         goto out;
454     }
455
456     /* try to decode the `request' */
457     memcpy (&key, ckey->key.keyvalue.data, sizeof(key));
458     des_set_key (&key, schedule);
459     des_pcbc_encrypt (request.data,
460                       request.data,
461                       request.length,
462                       schedule,
463                       &key,
464                       DES_DECRYPT);
465     memset (&schedule, 0, sizeof(schedule));
466
467     /* check for the magic label */
468     if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) {
469         make_error_reply (hdr, KABADREQUEST, reply);
470         goto out;
471     }
472
473     reply_sp = krb5_storage_from_mem (request.data, 4);
474     krb5_ret_int32 (reply_sp, &chal);
475     krb5_storage_free (reply_sp);
476
477     if (abs(chal - kdc_time) > context->max_skew) {
478         make_error_reply (hdr, KACLOCKSKEW, reply);
479         goto out;
480     }
481
482     /* life */
483     max_life = end_time - kdc_time;
484     /* end_time - kdc_time can sometimes be non-positive due to slight
485        time skew between client and server. Let's make sure it is postive */
486     if(max_life < 1)
487         max_life = 1;
488     if (client_entry->max_life)
489         max_life = min(max_life, *client_entry->max_life);
490     if (server_entry->max_life)
491         max_life = min(max_life, *server_entry->max_life);
492
493     life = krb_time_to_life(kdc_time, kdc_time + max_life);
494
495     create_reply_ticket (hdr, skey,
496                          name, instance, v4_realm,
497                          addr, life, server_entry->kvno,
498                          max_seq_len,
499                          "krbtgt", v4_realm,
500                          chal + 1, "tgsT",
501                          &key, reply);
502     memset (&key, 0, sizeof(key));
503
504 out:
505     if (request.length) {
506         memset (request.data, 0, request.length);
507         krb5_data_free (&request);
508     }
509     if (name)
510         free (name);
511     if (instance)
512         free (instance);
513     if (client_entry)
514         free_ent (client_entry);
515     if (server_entry)
516         free_ent (server_entry);
517 }
518
519 static krb5_error_code
520 unparse_getticket_args (krb5_storage *sp,
521                         int *kvno,
522                         char **auth_domain,
523                         krb5_data *ticket,
524                         char **name,
525                         char **instance,
526                         krb5_data *times,
527                         int32_t *max_seq_len)
528 {
529     krb5_data data;
530     int32_t tmp;
531
532     krb5_ret_int32 (sp, &tmp);
533     *kvno = tmp;
534
535     krb5_ret_xdr_data (sp, &data);
536     *auth_domain = malloc(data.length + 1);
537     if (*auth_domain == NULL)
538         return ENOMEM;
539     memcpy (*auth_domain, data.data, data.length);
540     (*auth_domain)[data.length] = '\0';
541     krb5_data_free (&data);
542
543     krb5_ret_xdr_data (sp, ticket);
544
545     krb5_ret_xdr_data (sp, &data);
546     *name = malloc(data.length + 1);
547     if (*name == NULL) {
548         free (*auth_domain);
549         return ENOMEM;
550     }
551     memcpy (*name, data.data, data.length);
552     (*name)[data.length] = '\0';
553     krb5_data_free (&data);
554
555     krb5_ret_xdr_data (sp, &data);
556     *instance = malloc(data.length + 1);
557     if (*instance == NULL) {
558         free (*auth_domain);
559         free (*name);
560         return ENOMEM;
561     }
562     memcpy (*instance, data.data, data.length);
563     (*instance)[data.length] = '\0';
564     krb5_data_free (&data);
565
566     krb5_ret_xdr_data (sp, times);
567
568     krb5_ret_int32 (sp, max_seq_len);
569     /* ignore the rest */
570     return 0;
571 }
572
573 static void
574 do_getticket (struct rx_header *hdr,
575               krb5_storage *sp,
576               struct sockaddr_in *addr,
577               krb5_data *reply)
578 {
579     krb5_error_code ret;
580     int kvno;
581     char *auth_domain = NULL;
582     krb5_data aticket;
583     char *name = NULL;
584     char *instance = NULL;
585     krb5_data times;
586     int32_t max_seq_len;
587     hdb_entry *server_entry = NULL;
588     hdb_entry *krbtgt_entry = NULL;
589     Key *kkey = NULL;
590     Key *skey = NULL;
591     des_cblock key;
592     des_key_schedule schedule;
593     des_cblock session;
594     time_t max_life;
595     int8_t life;
596     time_t start_time, end_time;
597     char pname[ANAME_SZ];
598     char pinst[INST_SZ];
599     char prealm[REALM_SZ];
600     char server_name[256];
601
602     krb5_data_zero (&aticket);
603     krb5_data_zero (&times);
604
605     unparse_getticket_args (sp, &kvno, &auth_domain, &aticket,
606                             &name, &instance, &times, &max_seq_len);
607     if (times.length < 8) {
608         make_error_reply (hdr, KABADREQUEST, reply);
609         goto out;
610         
611     }
612
613     snprintf (server_name, sizeof(server_name),
614               "%s.%s@%s", name, instance, v4_realm);
615
616     ret = db_fetch4 (name, instance, v4_realm, &server_entry);
617     if (ret) {
618         kdc_log(0, "Server not found in database: %s: %s",
619                 server_name, krb5_get_err_text(context, ret));
620         make_error_reply (hdr, KANOENT, reply);
621         goto out;
622     }
623
624     ret = check_flags (NULL, NULL,
625                        server_entry, server_name,
626                        FALSE);
627     if (ret) {
628         make_error_reply (hdr, KAPWEXPIRED, reply);
629         goto out;
630     }
631
632     ret = db_fetch4 ("krbtgt", v4_realm, v4_realm, &krbtgt_entry);
633     if (ret) {
634         kdc_log(0, "Server not found in database: %s.%s@%s: %s",
635                 "krbtgt", v4_realm, v4_realm, krb5_get_err_text(context, ret));
636         make_error_reply (hdr, KANOENT, reply);
637         goto out;
638     }
639
640     /* find a DES key */
641     ret = get_des_key(krbtgt_entry, TRUE, TRUE, &kkey);
642     if(ret){
643         kdc_log(0, "no suitable DES key for krbtgt");
644         make_error_reply (hdr, KANOKEYS, reply);
645         goto out;
646     }
647
648     /* find a DES key */
649     ret = get_des_key(server_entry, TRUE, TRUE, &skey);
650     if(ret){
651         kdc_log(0, "no suitable DES key for server");
652         make_error_reply (hdr, KANOKEYS, reply);
653         goto out;
654     }
655
656     /* decrypt the incoming ticket */
657     memcpy (&key, kkey->key.keyvalue.data, sizeof(key));
658
659     /* unpack the ticket */
660     {
661         KTEXT_ST ticket;
662         u_char flags;
663         int life;
664         u_int32_t time_sec;
665         char sname[ANAME_SZ];
666         char sinstance[SNAME_SZ];
667         u_int32_t paddress;
668
669         if (aticket.length > sizeof(ticket.dat)) {
670             kdc_log(0, "ticket too long (%u > %u)",
671                     (unsigned)aticket.length,
672                     (unsigned)sizeof(ticket.dat));
673             make_error_reply (hdr, KABADTICKET, reply);
674             goto out;
675         }
676
677         ticket.length = aticket.length;
678         memcpy (ticket.dat, aticket.data, ticket.length);
679
680         des_set_key (&key, schedule);
681         decomp_ticket (&ticket, &flags, pname, pinst, prealm,
682                        &paddress, session, &life, &time_sec,
683                        sname, sinstance, 
684                        &key, schedule);
685
686         if (strcmp (sname, "krbtgt") != 0
687             || strcmp (sinstance, v4_realm) != 0) {
688             kdc_log(0, "no TGT: %s.%s for %s.%s@%s",
689                     sname, sinstance,
690                     pname, pinst, prealm);
691             make_error_reply (hdr, KABADTICKET, reply);
692             goto out;
693         }
694
695         if (kdc_time > krb_life_to_time(time_sec, life)) {
696             kdc_log(0, "TGT expired: %s.%s@%s",
697                     pname, pinst, prealm);
698             make_error_reply (hdr, KABADTICKET, reply);
699             goto out;
700         }
701     }
702
703     /* decrypt the times */
704     des_set_key (&session, schedule);
705     des_ecb_encrypt (times.data,
706                      times.data,
707                      schedule,
708                      DES_DECRYPT);
709     memset (&schedule, 0, sizeof(schedule));
710
711     /* and extract them */
712     {
713         krb5_storage *sp;
714         int32_t tmp;
715
716         sp = krb5_storage_from_mem (times.data, times.length);
717         krb5_ret_int32 (sp, &tmp);
718         start_time = tmp;
719         krb5_ret_int32 (sp, &tmp);
720         end_time = tmp;
721         krb5_storage_free (sp);
722     }
723
724     /* life */
725     max_life = end_time - kdc_time;
726     /* end_time - kdc_time can sometimes be non-positive due to slight
727        time skew between client and server. Let's make sure it is postive */
728     if(max_life < 1)
729         max_life = 1;
730     if (krbtgt_entry->max_life)
731         max_life = min(max_life, *krbtgt_entry->max_life);
732     if (server_entry->max_life)
733         max_life = min(max_life, *server_entry->max_life);
734
735     life = krb_time_to_life(kdc_time, kdc_time + max_life);
736
737     create_reply_ticket (hdr, skey,
738                          pname, pinst, prealm,
739                          addr, life, server_entry->kvno,
740                          max_seq_len,
741                          name, instance,
742                          0, "gtkt",
743                          &session, reply);
744     memset (&session, 0, sizeof(session));
745     
746 out:
747     if (aticket.length) {
748         memset (aticket.data, 0, aticket.length);
749         krb5_data_free (&aticket);
750     }
751     if (times.length) {
752         memset (times.data, 0, times.length);
753         krb5_data_free (&times);
754     }
755     if (auth_domain)
756         free (auth_domain);
757     if (name)
758         free (name);
759     if (instance)
760         free (instance);
761     if (krbtgt_entry)
762         free_ent (krbtgt_entry);
763     if (server_entry)
764         free_ent (server_entry);
765 }
766
767 krb5_error_code
768 do_kaserver(unsigned char *buf,
769             size_t len,
770             krb5_data *reply,
771             const char *from,
772             struct sockaddr_in *addr)
773 {
774     krb5_error_code ret = 0;
775     struct rx_header hdr;
776     u_int32_t op;
777     krb5_storage *sp;
778
779     if (len < RX_HEADER_SIZE)
780         return -1;
781     sp = krb5_storage_from_mem (buf, len);
782
783     decode_rx_header (sp, &hdr);
784     buf += RX_HEADER_SIZE;
785     len -= RX_HEADER_SIZE;
786
787     switch (hdr.type) {
788     case HT_DATA :
789         break;
790     case HT_ACK :
791     case HT_BUSY :
792     case HT_ABORT :
793     case HT_ACKALL :
794     case HT_CHAL :
795     case HT_RESP :
796     case HT_DEBUG :
797     default:
798         /* drop */
799         goto out;
800     }
801
802
803     if (hdr.serviceid != KA_AUTHENTICATION_SERVICE
804         && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) {
805         ret = -1;
806         goto out;
807     }
808
809     krb5_ret_int32(sp, &op);
810     switch (op) {
811     case AUTHENTICATE :
812         do_authenticate (&hdr, sp, addr, reply);
813         break;
814     case GETTICKET :
815         do_getticket (&hdr, sp, addr, reply);
816         break;
817     case AUTHENTICATE_OLD :
818     case CHANGEPASSWORD :
819     case GETTICKET_OLD :
820     case SETPASSWORD :
821     case SETFIELDS :
822     case CREATEUSER :
823     case DELETEUSER :
824     case GETENTRY :
825     case LISTENTRY :
826     case GETSTATS :
827     case DEBUG :
828     case GETPASSWORD :
829     case GETRANDOMKEY :
830     case AUTHENTICATE_V2 :
831     default :
832         make_error_reply (&hdr, RXGEN_OPCODE, reply);
833         break;
834     }
835
836 out:
837     krb5_storage_free (sp);
838     return ret;
839 }