4154fe1fcb2919971f8e3093989c7d2bcab95456
[openafs.git] / src / kauth / krb_udp.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* This file contains the code to handle UDP requests to the authentication
11    server using the MIT Kerberos protocol for obtaining tickets.  It will only
12    handle authentication and get ticket requests to provide read-only protocol
13    level compatibility with the standard Kerberos servers. */
14
15 #include <afsconfig.h>
16 #include <afs/param.h>
17
18 RCSID("$Header$");
19
20 #include <afs/stds.h>
21 #include <sys/types.h>
22 #ifdef AFS_NT40_ENV
23 #include <winsock2.h>
24 #define snprintf _snprintf
25 #else
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <netinet/in.h>
29 #endif
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #else
33 #ifdef HAVE_STRINGS_H
34 #include <strings.h>
35 #endif
36 #endif
37 #include <afs/afsutil.h>
38 #include <time.h>
39 #include <afs/com_err.h>
40 #include <lwp.h>
41 #include <des.h>
42 #include <rx/xdr.h>
43 #include <rx/rx.h>
44 #include <rx/rxkad.h>
45 #include <afs/auth.h>
46 #include <ubik.h>
47
48 #include "kauth.h"
49 #include "kautils.h"
50 #include "kaserver.h"
51 #include "prot.h"                       /* protocol definitions */
52 #include "kaport.h"
53 #include "afs/audit.h"
54 #include "kalog.h"
55
56 /* my kerberos error codes */
57 #define KERB_ERR_BAD_MSG_TYPE  99
58 #define KERB_ERR_BAD_LIFETIME  98
59 #define KERB_ERR_NONNULL_REALM 97
60 #define KERB_ERR_PKT_LENGTH    96
61 #define KERB_ERR_TEXT_LENGTH   95
62 #ifndef KDC_GEN_ERR
63 #define KDC_GEN_ERR     20
64 #endif
65
66
67 int krb_udp_debug = 0;
68
69 static int sock_kerb =-1;                       /* the socket we're using */
70 static int sock_kerb5=-1;                       /* the socket we're using */
71
72 struct packet {
73     int   len;
74     struct sockaddr_in from;
75     int   byteOrder;
76     char *name;
77     char *inst;
78     char *realm;
79     Date  time;
80     char *rest;                         /* remaining bytes of packet */
81     char  data[MAX_PKT_LEN];
82 };
83
84 extern struct kadstats dynamic_statistics;
85 extern char *lastOperation;
86 extern char lrealm[];
87
88 char udpAuthPrincipal[256];
89 char udptgsPrincipal[256];
90 char udptgsServerPrincipal[256];
91
92 #define putstr(name) if ((slen = strlen(name)) >= MAXKTCNAMELEN) return -1;\
93                      else strcpy (answer, name), answer += slen+1
94 #define putint(num) num = htonl(num), \
95                     memcpy(answer, &num, sizeof(afs_int32)), \
96                     answer += sizeof(afs_int32)
97
98 #define getstr(name) if ((slen = strlen(packet)) >= sizeof(name)) return -1;\
99                      strcpy (name, packet), packet += slen+1
100 #define getint(num) memcpy(&num, packet, sizeof(afs_int32)), \
101                     num = ktohl (byteOrder, num), \
102                     packet += sizeof(afs_int32)
103
104 /* this is just to close the log every five minutes to rm works */
105
106 int fiveminutes=300;
107
108 static FiveMinuteCheckLWP()
109 {
110
111         printf("start 5 min check lwp\n");
112
113         while(1)
114         {
115             IOMGR_Sleep(fiveminutes);
116             /* close the log so it can be removed */
117             ReOpenLog(AFSDIR_SERVER_KALOG_FILEPATH);/* no trunc, just append */
118         }
119 }
120
121
122 static afs_int32 create_cipher (cipher, cipherLen, sessionKey, sname, sinst,
123                            start, end, kvno, ticket, ticketLen, key)
124   char *cipher;
125   int  *cipherLen;
126   struct ktc_encryptionKey *sessionKey;
127   char *sname;
128   char *sinst;
129   Date  start, end;
130   afs_int32  kvno;
131   char *ticket;
132   int   ticketLen;
133   struct ktc_encryptionKey *key;
134 {   char *answer;
135     int   slen;
136     unsigned char life = time_to_life (start, end);
137     int   len;
138     des_key_schedule schedule;
139     afs_int32  code;
140
141     answer = cipher;
142     len = sizeof(*sessionKey) + strlen(sname) + strlen(sinst) +
143         strlen(lrealm) + 3/*nulls*/ + 3 + ticketLen + sizeof(Date);
144     if (len > *cipherLen) return KAANSWERTOOLONG;
145     if (ticketLen > 255) return KAANSWERTOOLONG;
146     if (kvno > 255) return KAANSWERTOOLONG;
147
148     memcpy(answer, sessionKey, sizeof(*sessionKey));
149     answer += sizeof(*sessionKey);
150     putstr (sname);
151     putstr (sinst);
152     putstr (lrealm);
153     *answer++ = life;
154     *answer++ = (unsigned char) kvno;
155     *answer++ = (unsigned char) ticketLen;
156     memcpy(answer, ticket, ticketLen);
157     answer += ticketLen;
158     putint (start);
159
160     if (krb_udp_debug) {
161         printf ("Printing ticket (%d) and date: ", ticketLen);
162         ka_PrintBytes (ticket, ticketLen);
163         ka_PrintBytes (answer-4, 4);
164         printf ("\n");
165     }
166
167     if (code = des_key_sched (key, schedule))
168         printf ("In KAAuthenticate: key_sched returned %d\n", code);
169     des_pcbc_encrypt (cipher, cipher, len, schedule, key, ENCRYPT);
170     *cipherLen = round_up_to_ebs (len);
171
172     if (krb_udp_debug) {
173         printf ("Printing cipher (%d): ", *cipherLen);
174         ka_PrintBytes (cipher, *cipherLen);
175         printf ("\n");
176     }
177     return 0;
178 }
179
180 static afs_int32 create_reply (ans, name, inst, startTime, endTime, kvno,
181                           cipher, cipherLen)
182   struct packet *ans;
183   char *name;
184   char *inst;
185   Date  startTime, endTime;
186   afs_int32  kvno;
187   char *cipher;
188   int   cipherLen;
189 {   char *answer = ans->data;
190     int   slen;
191
192     ans->len = 2 + strlen(name) + strlen(inst) + 3/*nulls*/ +
193         sizeof(afs_int32) + 1/*ntkts*/ + sizeof(afs_int32) + 1/*kvno*/ +
194         sizeof(short) + cipherLen;
195     if (ans->len > sizeof(ans->data)) return KAANSWERTOOLONG;
196     if (kvno > 255) return KAANSWERTOOLONG;
197         
198     *answer++ = (unsigned char) KRB_PROT_VERSION;
199     *answer++ = (unsigned char) AUTH_MSG_KDC_REPLY;
200     /* always send claiming network byte order */
201     putstr (name);
202     putstr (inst);
203     putstr ("");
204     putint (startTime);
205     *answer++ = 1;                      /* undocumented number of tickets! */
206     putint (endTime);
207     *answer++ = (unsigned char) kvno;
208     {   short w = (short) cipherLen;
209         w = htons(w);
210         memcpy(answer, &w, sizeof(short));
211         answer += sizeof(short);
212     }
213     memcpy(answer, cipher, cipherLen);
214     return 0;
215 }
216
217 static afs_int32 check_auth (pkt, auth, authLen, key, name, inst, cell)
218   struct packet *pkt;
219   char *auth;
220   int   authLen;
221   struct ktc_encryptionKey *key;
222   char *name;
223   char *inst;
224   char *cell;
225 {   char *packet;
226     des_key_schedule schedule;
227     afs_int32  cksum;
228     /* unsigned char time_msec; */
229     afs_int32  time_sec;
230     int   byteOrder = pkt->byteOrder;
231
232     des_key_sched (key, schedule);
233     des_pcbc_encrypt (auth, auth, authLen, schedule, key, DECRYPT);
234     packet = auth;
235     if (strcmp (packet, name) != 0) return KABADTICKET;
236     packet += strlen (packet) + 1;
237     if (strcmp (packet, inst) != 0) return KABADTICKET;
238     packet += strlen (packet) + 1;
239     if (strcmp (packet, cell) != 0) return KABADTICKET;
240     packet += strlen (packet) + 1;
241     getint (cksum);
242     /* time_msec = */ *(unsigned char *)packet++;
243     getint (time_sec);
244     if ((packet-auth) > authLen) return KABADTICKET;
245     return 0;
246 }
247
248 afs_int32 UDP_Authenticate (ksoc, client, name, inst, startTime, endTime, sname, sinst)
249   int ksoc;
250   struct sockaddr_in *client;
251   char *name;
252   char *inst;
253   Date  startTime;
254   Date  endTime;
255   char *sname;
256   char *sinst;
257 {   struct ubik_trans *tt;
258     afs_int32  to;                              /* offset of block */
259     struct kaentry tentry;
260     afs_int32  tgskvno;                 /* key version of service key */
261     struct ktc_encryptionKey tgskey;    /* service key for encrypting ticket */
262     int   tgt;
263     Date  now = time(0);
264     afs_int32  code;
265
266     char  ticket[MAXKTCTICKETLEN];      /* our copy of the ticket */
267     int   ticketLen;
268     struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
269
270     char  cipher[2*MAXKTCTICKETLEN];    /* put encrypted part of answer here */
271     int   cipherLen;
272     struct packet ans;
273
274     COUNT_REQ (UAuthenticate);
275     if (!name_instance_legal (name, inst)) return KERB_ERR_NAME_EXP;    /* KABADNAME */
276     if (code = InitAuthServ (&tt, LOCKREAD, this_op)) return code;
277     
278     code = FindBlock (tt, name, inst, &to, &tentry);
279     if (code) goto abort;
280     if (to) {                           /* if user exists check other stuff */
281         afs_int32 sto;
282         struct kaentry sentry;
283         save_principal (udpAuthPrincipal, name, inst, 0);
284         
285         tgt = ((strcmp (sname, KA_TGS_NAME) == 0) &&
286                (strcmp (sinst, lrealm) == 0));
287         if ((ntohl(tentry.user_expiration) < now) ||
288             (tgt && (ntohl(tentry.flags) & KAFNOTGS))) {
289             code = KERB_ERR_NAME_EXP;   /* KABADUSER */
290             goto abort;
291         }
292         code = FindBlock (tt, KA_TGS_NAME, lrealm, &sto, &sentry);
293         if (code) goto abort;
294         if (sto == 0) {code = KANOENT; goto abort; }
295         if ((ntohl(sentry.user_expiration) < now)) {
296             code = KERB_ERR_NAME_EXP;   /* XXX Could use another error code XXX */
297             goto abort;
298         }
299         if (abs (startTime - now) > KTC_TIME_UNCERTAINTY) {
300             code = KERB_ERR_SERVICE_EXP;        /* was KABADREQUEST */
301             goto abort;
302         }
303         
304         if (tentry.misc_auth_bytes) {
305           unsigned char misc_auth_bytes[4];
306           afs_uint32 temp;        /* unsigned for safety */
307           afs_uint32 pwexpires;
308           
309           temp = ntohl(*((afs_int32 *)(tentry.misc_auth_bytes)));
310           unpack_long(temp, misc_auth_bytes);
311           pwexpires = misc_auth_bytes[0];
312           if (pwexpires) {
313             pwexpires= ntohl(tentry.change_password_time) + 24*60*60*pwexpires;
314             if ( pwexpires < now ) {
315               code = KERB_ERR_AUTH_EXP; /* was KAPWEXPIRED */
316               goto abort;
317             }
318           }
319         }
320
321         /* make the ticket */
322         code = des_random_key (&sessionKey);
323         if (code) {
324             code = KERB_ERR_NULL_KEY;   /* was KANOKEYS */
325             goto abort;
326         }
327         endTime = umin (endTime,
328                         startTime + ntohl(tentry.max_ticket_lifetime));
329         if ((code = ka_LookupKey (tt, sname, sinst, &tgskvno, &tgskey)) ||
330             (code = tkt_MakeTicket (ticket, &ticketLen, &tgskey,
331                                     name, inst, lrealm,
332                                     startTime, endTime, &sessionKey,
333                                     htonl(client->sin_addr.s_addr), sname, sinst)))
334             goto abort;
335
336         cipherLen = sizeof(cipher);
337         code = create_cipher
338             (cipher, &cipherLen, &sessionKey, sname, sinst,
339              startTime, endTime, tgskvno, ticket, ticketLen, &tentry.key);
340         if (code) goto abort;
341     } else { /* no such user */
342         cipherLen = 0;
343         tentry.key_version = 0;
344     }
345     code = ubik_EndTrans(tt);
346     if (code) 
347       goto fail;
348
349     code = create_reply (&ans, name, inst, startTime, endTime,
350                          ntohl(tentry.key_version), cipher, cipherLen);
351     if (code) 
352        goto fail;
353
354     if (krb_udp_debug) {
355         printf ("Sending %d bytes ending in: ", ans.len);
356         ka_PrintBytes (ans.data+ans.len-8, 8);
357         printf ("\n");
358     }
359
360     code = sendto (ksoc, ans.data, ans.len, 0,
361                    (struct sockaddr *) client, sizeof(*client));
362     if (code != ans.len) {
363         perror ("calling sendto");
364         code = -1;
365         goto fail;
366     }
367     KALOG(name, inst, sname, sinst, NULL, client->sin_addr.s_addr, LOG_AUTHENTICATE);
368     osi_audit ( UDPAuthenticateEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_END);
369     return 0;
370
371 abort:
372     COUNT_ABO;
373     ubik_AbortTrans (tt);
374
375 fail:
376     osi_audit ( UDPAuthenticateEvent, code, AUD_STR, name, AUD_STR, inst, AUD_END);
377     return code;
378 }
379
380 afs_int32 UDP_GetTicket (ksoc, pkt, kvno, authDomain, ticket, ticketLen, auth, authLen)
381   int ksoc;
382   struct packet *pkt;
383   afs_int32  kvno;
384   char *authDomain;
385   char *ticket;
386   int   ticketLen;
387   char *auth;
388   int   authLen;
389 {   afs_int32  code;
390     struct ktc_encryptionKey tgskey;
391     char  name[MAXKTCNAMELEN];
392     char  inst[MAXKTCNAMELEN];
393     char  cell[MAXKTCREALMLEN];
394     struct ktc_encryptionKey authSessionKey;
395     afs_int32  host;
396     Date  start;
397     Date  authEnd;
398     Date  now = time(0);
399     int   celllen;
400     int   import;
401
402     char *packet;
403     int   slen;
404     int   byteOrder = pkt->byteOrder;
405     char  sname[MAXKTCNAMELEN];
406     char  sinst[MAXKTCNAMELEN];
407     afs_int32  time_ws;
408     unsigned char life;
409
410     struct ubik_trans *tt;
411     afs_int32  to;
412     struct kaentry caller;
413     struct kaentry server;
414     Date  reqEnd;
415     struct ktc_encryptionKey sessionKey;
416     int   newTicketLen;
417     char  newTicket[MAXKTCTICKETLEN];
418
419     char  cipher[2*MAXKTCTICKETLEN];    /* put encrypted part of answer here */
420     int   cipherLen;
421     struct packet ans;
422
423     COUNT_REQ (UGetTicket);
424
425     if (code = InitAuthServ(&tt, LOCKREAD, this_op)) goto fail;
426     code = ka_LookupKvno (tt, KA_TGS_NAME,
427                           ((strlen(authDomain) > 0) ? authDomain : lrealm),
428                           kvno, &tgskey);
429     if (code) goto abort;
430
431     code = tkt_DecodeTicket (ticket, ticketLen, &tgskey, name, inst, cell,
432                              &authSessionKey, &host, &start, &authEnd);
433     pkt->name = name;
434     pkt->inst = inst;
435     pkt->realm = cell;
436     if (code) {
437       code = KERB_ERR_AUTH_EXP; /* was KANOAUTH */
438       goto abort;
439     }
440     save_principal (udptgsPrincipal, name, inst, cell);
441     code = tkt_CheckTimes (start, authEnd, now);
442     if (code <= 0) {
443       if (code == -1) {
444         code = KERB_ERR_SERVICE_EXP; /* was RXKADEXPIRED */
445         goto abort;
446       }
447       code = KERB_ERR_AUTH_EXP; /* was KANOAUTH */
448       goto abort;
449     }
450     celllen = strlen (cell);
451     import = 0;
452     if ((strlen(authDomain) > 0) && (strcmp (authDomain, lrealm) != 0))
453         import = 1;
454     if (import && (celllen == 0)) {
455       code = KERB_ERR_PKT_VER;  /* was KABADTICKET */
456       goto abort;
457     }
458     if (celllen == 0) {
459         strncpy (cell, lrealm, MAXKTCREALMLEN-1);
460         cell[MAXKTCREALMLEN-1] = 0;
461     };
462
463     if (krb_udp_debug) {
464         printf ("UGetTicket: got ticket from '%s'.'%s'@'%s'\n",
465                 name, inst, cell);
466     }
467
468     code = check_auth (pkt, auth, authLen, &authSessionKey, name, inst, cell);
469     if (code) goto abort;
470
471     /* authenticator and all is OK so read actual request */
472     packet = pkt->rest;
473     getint (time_ws);
474     life = *(unsigned char *)packet++;
475     getstr (sname);
476     getstr (sinst);
477     start = now;
478     reqEnd = life_to_time (start, life);
479     if (krb_udp_debug) {
480         printf ("UGetTicket: request for server '%s'.'%s'\n", sname, sinst);
481     }
482     save_principal (udptgsServerPrincipal, sname, sinst, 0);
483     
484     if (import) {
485         strcpy (caller.userID.name, name);
486         strcpy (caller.userID.instance, inst);
487         caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
488     }
489     else {
490         code = FindBlock(tt, name, inst, &to, &caller);
491         if (code) goto abort;
492         if (to == 0) {
493             ka_PrintUserID ("GetTicket: User ", name, inst, " unknown.\n");
494             code = KERB_ERR_PRINCIPAL_UNKNOWN;  /* KANOENT */
495             goto abort;
496         }
497         if (ntohl(caller.flags) & KAFNOTGS)
498             { code =  KERB_ERR_AUTH_EXP; /* was KABADUSER */
499               goto abort; }
500     }
501
502     code = FindBlock (tt, sname, sinst, &to, &server); /* get server's entry */
503     if (code) goto abort;
504     if (to == 0) {                      /* entry not found */
505         ka_PrintUserID ("GetTicket: Server ", sname, sinst, " unknown.\n");
506         code = KERB_ERR_PRINCIPAL_UNKNOWN; /* KANOENT */
507         goto abort;
508     }
509     code = ubik_EndTrans (tt);
510     if (code) goto fail;
511
512     if (ntohl(server.flags) & KAFNOSEAL) return KABADSERVER;
513
514     code = des_random_key (&sessionKey);
515     if (code) {
516       code = KERB_ERR_NULL_KEY; /* was KANOKEYS */
517       goto fail;
518     }
519
520     reqEnd = umin (umin (reqEnd, authEnd),
521                 umin (start+ntohl(caller.max_ticket_lifetime),
522                       start+ntohl(server.max_ticket_lifetime)));
523
524     code = tkt_MakeTicket (newTicket, &newTicketLen, &server.key,
525                            caller.userID.name, caller.userID.instance, cell,
526                            start, reqEnd, &sessionKey,
527                            htonl(pkt->from.sin_addr.s_addr),
528                            server.userID.name, server.userID.instance);
529     if (code) goto fail;
530
531     cipherLen = sizeof(cipher);
532     code = create_cipher
533         (cipher, &cipherLen, &sessionKey, sname, sinst,
534          start, reqEnd, ntohl(server.key_version),
535          newTicket, newTicketLen, &authSessionKey);
536     if (code) goto fail;
537
538     code = create_reply (&ans, name, inst, start, reqEnd, 0,
539                          cipher, cipherLen);
540     if (code) goto fail;
541
542     code = sendto (ksoc, ans.data, ans.len, 0,
543                    (struct sockaddr *) &pkt->from, sizeof(pkt->from));
544     if (code != ans.len) {
545         perror ("calling sendto");
546         code = -1;
547         goto fail;
548     }
549
550     if (cipherLen != 0) {
551         KALOG(name, inst, sname, sinst, NULL, host, LOG_GETTICKET);
552     }
553     osi_audit ( UDPGetTicketEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_STR, cell, AUD_STR, sname, AUD_STR, sinst, AUD_END);
554     return 0;
555
556 abort:
557     ubik_AbortTrans(tt);
558 fail:
559     osi_audit ( UDPGetTicketEvent, code, AUD_STR, name, AUD_STR, inst, AUD_STR, NULL, AUD_STR, NULL, AUD_STR, NULL, AUD_END);
560     return code;
561 }
562  
563 static int err_packet (ksoc, pkt, code, reason)
564   int ksoc;
565   struct packet *pkt;
566   afs_int32  code;
567   char *reason;
568 {   struct packet ans;
569     char *answer = ans.data;
570     int   slen;
571     char  buf[256];
572
573     if (reason == 0) reason = "";
574     snprintf (buf, 255, "code = %d: %s", code, reason);
575
576     if (krb_udp_debug) {
577         printf ("Sending error packet to '%s'.'%s'@'%s' containing %s\n",
578                 pkt->name, pkt->inst, pkt->realm, buf);
579     }
580
581     ans.len = 2 + strlen(pkt->name) + strlen(pkt->inst) + strlen(pkt->realm) +
582         3/* nulls */ + (2 * sizeof(afs_int32)) + strlen (buf) + 1;
583     if (ans.len > sizeof(ans.data)) {
584         printf ("Answer packet too long\n");
585         return -1;
586     }
587
588     *answer++ = (unsigned char) KRB_PROT_VERSION;
589     *answer++ = (unsigned char) AUTH_MSG_ERR_REPLY;
590     /* always send claiming network byte order */
591     putstr (pkt->name);
592     putstr (pkt->inst);
593     putstr (pkt->realm);
594     putint (pkt->time);
595     if ((code < 0) || (code > KERB_ERR_MAXIMUM)) {
596         /* It could be because of kauth errors so we should return something instead of success!! */
597         code = KDC_GEN_ERR;
598     }
599     putint (code);
600     putstr (buf);
601
602     code = sendto(ksoc, ans.data, ans.len, 0,
603                   (struct sockaddr *) &pkt->from, sizeof(pkt->from));
604     if (code != ans.len) {
605         if (code >= 0)
606             printf ("call to sendto returned %d, sending error packet %d bytes long\n",
607                     code, ans.len);
608         else perror ("err_packet: sendto");
609     }
610     return 0;
611 }
612
613 int
614 process_udp_auth (ksoc, pkt)
615   int ksoc;
616   struct packet *pkt;
617 {   char *packet = pkt->rest;
618     char  name[MAXKTCNAMELEN];
619     char  inst[MAXKTCNAMELEN];
620     char  realm[MAXKTCREALMLEN];
621     char  sname[MAXKTCNAMELEN];
622     char  sinst[MAXKTCNAMELEN];
623     int   slen;
624     Date  now = time(0);
625     Date  startTime, endTime;
626     unsigned char lifetime;
627     afs_int32  code;
628
629     pkt->name = packet;
630     getstr (name);
631     pkt->inst = packet;
632     getstr (inst);
633     pkt->realm = packet;
634     getstr (realm);
635     if (krb_udp_debug) {
636         printf ("Processing KDC Request from '%s'.'%s'@'%s'\n",
637                 name, inst, realm);
638     }
639
640     if ((strlen(realm) > 0) && (strcmp (realm, lrealm) != 0)) {
641         err_packet (ksoc, pkt, KERB_ERR_NONNULL_REALM,
642                     "null realm name not allowed");
643         return -1;
644     }
645     memcpy(&startTime, packet, sizeof(startTime));
646     packet += sizeof(startTime);
647     startTime = ktohl (pkt->byteOrder, startTime);
648     pkt->time = startTime;
649     lifetime = *packet++;
650     endTime = life_to_time (startTime, lifetime);
651     code = tkt_CheckTimes (startTime, endTime, now);
652     if (code < 0) {
653         err_packet (ksoc, pkt, KERB_ERR_BAD_LIFETIME,
654                     "requested ticket lifetime invalid");
655         return -1;
656     }
657     getstr (sname);
658     getstr (sinst);
659     if ((packet - pkt->data) != pkt->len) {
660         err_packet (ksoc, pkt, KERB_ERR_PKT_LENGTH, "packet length inconsistent");
661         return -1;
662     }
663     pkt->rest = packet;
664     code = UDP_Authenticate (ksoc, &pkt->from, name, inst,
665                              startTime, endTime, sname, sinst);
666     if (code) {
667         if (code == KANOENT) {
668            code = KERB_ERR_PRINCIPAL_UNKNOWN;
669            err_packet (ksoc, pkt, code, (char *)error_message (code));
670         } else if (code == KAPWEXPIRED) {
671             code = KERB_ERR_NAME_EXP;
672             err_packet (ksoc, pkt, code, "password has expired");
673         } else 
674             err_packet (ksoc, pkt, code, (char *)error_message (code));
675     }
676     return 0;
677 }
678
679 int
680 process_udp_appl (ksoc, pkt)
681   int ksoc;
682   struct packet *pkt;
683 {   char *packet = pkt->rest;
684     afs_int32  kvno;
685     char  realm[MAXKTCREALMLEN];
686     char  ticket[MAXKTCTICKETLEN];
687     char  auth[3*MAXKTCNAMELEN+4+5];
688     int   slen;
689     int   ticketLen, authLen;
690     afs_int32  code;
691
692     if (krb_udp_debug) {
693         printf ("Processing APPL Request\n");
694     }
695     kvno = *packet++;
696     getstr (realm);
697     ticketLen = *(unsigned char *)packet++;
698     authLen = *(unsigned char *)packet++;
699     if (ticketLen > sizeof(ticket)) {
700         err_packet (ksoc, pkt, KERB_ERR_TEXT_LENGTH, "ticket too long");
701         return -1;
702     }
703     memcpy(ticket, packet, ticketLen);
704     packet += ticketLen;
705     if (authLen > sizeof(auth)) {
706         err_packet (ksoc, pkt, KERB_ERR_TEXT_LENGTH, "authenticator too long");
707         return -1;
708     }
709     memcpy(auth, packet, authLen);
710     pkt->rest = packet + authLen;
711     code = UDP_GetTicket (ksoc, pkt, kvno, realm, ticket, ticketLen, auth, authLen);
712     if (code) {
713         if (code == KANOENT) code = KERB_ERR_PRINCIPAL_UNKNOWN;
714         err_packet (ksoc, pkt, code, (char*)error_message (code));
715         return -1;
716     }
717     return 0;
718 }
719
720 void
721 process_udp_request (ksoc, pkt)
722   int ksoc;
723   struct packet *pkt;
724 {   char *packet = pkt->data;
725     unsigned char version, auth_msg_type;
726
727     version = *packet++;
728     if (version != KRB_PROT_VERSION) {
729         err_packet (ksoc, pkt, KERB_ERR_PKT_VER, "packet version number unknown");
730         return;
731     }
732     auth_msg_type = *packet++;
733     pkt->byteOrder = auth_msg_type & 1;
734     pkt->rest = packet;
735     switch (auth_msg_type & ~1) {
736       case AUTH_MSG_KDC_REQUEST:
737         process_udp_auth (ksoc, pkt);
738         break;
739       case AUTH_MSG_APPL_REQUEST:
740         process_udp_appl (ksoc, pkt);
741         break;
742       default:
743         printf ("unknown msg type 0x%x\n", auth_msg_type);
744         err_packet (ksoc, pkt, KERB_ERR_BAD_MSG_TYPE, "message type not supported");
745         return;
746     }
747     return;
748 }
749
750 static SocketListener ()
751 {   fd_set rfds;
752     struct timeval tv;
753     struct packet packet;
754     int fromLen;
755     afs_int32 code;
756
757     printf ("Starting to listen for UDP packets\n");
758     while (1) {
759         FD_ZERO(&rfds);
760         if (sock_kerb  >= 0) FD_SET(sock_kerb, &rfds);
761         if (sock_kerb5 >= 0) FD_SET(sock_kerb5, &rfds);
762
763         tv.tv_sec = 100;
764         tv.tv_usec = 0;
765         /* write and exception fd_set's are null */
766         code = IOMGR_Select(32, &rfds, NULL, NULL, &tv);
767         if (code == 0) { /* timeout */
768             /* printf ("Timeout\n"); */
769             continue;
770         }
771         else if (code < 0) {
772             perror ("calling IOMGR_Select");
773             break;
774         }
775     
776         fromLen = sizeof(packet.from);
777         if ((sock_kerb >= 0) && FD_ISSET(sock_kerb, &rfds)) {
778             code = recvfrom(sock_kerb, packet.data, sizeof(packet.data), 0,
779                             (struct sockaddr *) &packet.from, &fromLen);
780             if (code < 0) {
781                 if (errno == EAGAIN || errno == ECONNREFUSED) 
782                     goto try_kerb5;
783                 perror ("calling recvfrom");
784                 break;
785             }
786             packet.len = code;
787             if (krb_udp_debug) {
788                 printf ("Kerb:udp: Got %d bytes from addr %s which are '",
789                         code, afs_inet_ntoa(packet.from.sin_addr.s_addr));
790                 ka_PrintBytes (packet.data, packet.len);
791                 printf ("'\n");
792             }
793             packet.name = packet.inst = packet.realm = "";
794             packet.time = 0;
795             process_udp_request (sock_kerb, &packet);
796         } 
797 try_kerb5:
798         if ((sock_kerb5 >= 0) && FD_ISSET(sock_kerb5, &rfds)) {
799             code = recvfrom(sock_kerb5, packet.data, sizeof(packet.data), 0,
800                             (struct sockaddr *) &packet.from, &fromLen);
801             if (code < 0) {
802                 if (errno == EAGAIN || errno == ECONNREFUSED) 
803                     continue;
804                 perror ("calling recvfrom");
805                 break;
806             }
807             packet.len = code;
808             if (krb_udp_debug) {
809                 printf ("Kerb5:udp: Got %d bytes from addr %s which are '",
810                         code, afs_inet_ntoa(packet.from.sin_addr.s_addr));
811                 ka_PrintBytes (packet.data, packet.len);
812                 printf ("'\n");
813             }
814             packet.name = packet.inst = packet.realm = "";
815             packet.time = 0;
816             process_udp_request (sock_kerb5, &packet);
817         } 
818     }
819     if (sock_kerb >= 0) {
820         close(sock_kerb);
821         sock_kerb = -1;
822     }
823     if (sock_kerb5 >= 0) {
824         close(sock_kerb5);
825         sock_kerb5 = -1;
826     }
827     printf("UDP SocketListener exiting due to error\n");
828 }
829
830 #if MAIN
831
832 #include "AFS_component_version_number.c"
833
834 main ()
835 #else
836 afs_int32 init_krb_udp ()
837 #endif
838 {   struct sockaddr_in taddr;
839     static PROCESS slPid;               /* socket listener pid */
840     static PROCESS checkPid;            /* fiveminute check */
841     afs_int32  code;
842     char*  krb4name;                    /* kerberos version4 service */
843
844 #if MAIN
845     PROCESS junk;
846 #endif
847     struct servent *sp;
848     static int inited = 0;
849     afs_int32 kerb_port;
850
851     if (inited) return -1;
852     inited = 1;
853
854     memset(&taddr, 0, sizeof(taddr));
855     krb4name = "kerberos4";
856     sp = getservbyname(krb4name, "udp");
857     taddr.sin_family = AF_INET;  /* added for NCR port */
858 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
859     taddr.sin_len = sizeof(struct sockaddr_in);
860 #endif
861     if ( !sp )  
862     {
863         /* if kerberos-4 is not available, try "kerberos-iv" */
864         krb4name = "kerberos-iv";
865         sp = getservbyname(krb4name, "udp");
866     }
867     if ( !sp )  
868     {
869         /* if kerberos-iv is not available, try "kerberos" */
870         krb4name = "kerberos";
871         sp = getservbyname(krb4name, "udp");
872     }
873     if (!sp) {
874         fprintf (stderr, 
875           "kerberos/udp is unknown; check /etc/services.  Using port=%d as default\n",
876           KRB_PORT);
877         taddr.sin_port = htons(KRB_PORT);
878     } else {
879         /* copy the port number */
880         fprintf (stderr, "%s/udp port=%hu\n", krb4name, (unsigned short)sp->s_port);
881         taddr.sin_port = sp->s_port;
882     }
883     kerb_port = taddr.sin_port;
884     sock_kerb = socket(AF_INET, SOCK_DGRAM, 0);
885     code = bind(sock_kerb, (struct sockaddr *) &taddr, sizeof(taddr));
886     if (code < 0) {
887         perror ("calling bind");
888         sock_kerb = -1;
889     }
890
891     sp = getservbyname("kerberos5", "udp");
892     if (!sp) {
893         fprintf (stderr, 
894           "kerberos5/udp is unknown; check /etc/services.  Using port=%d as default\n",
895           KRB5_PORT);
896         taddr.sin_port = htons(KRB5_PORT);
897     } else {
898         /* copy the port number */
899         fprintf (stderr, "kerberos5/udp port=%hu\n", (unsigned short)sp->s_port);
900         taddr.sin_port = sp->s_port;
901     }
902     if (taddr.sin_port != kerb_port) { /* a different port */
903        sock_kerb5 = socket(AF_INET, SOCK_DGRAM, 0);
904        code = bind(sock_kerb5, (struct sockaddr *) &taddr, sizeof(taddr));
905        if (code < 0) {
906           perror ("calling bind");
907           sock_kerb5 = -1;
908        }
909     }
910
911     /* Bail out if we can't bind with any port */
912     if ((sock_kerb < 0) && (sock_kerb5 < 0))
913        return -1;
914
915 #if MAIN
916     /* this has already been done */
917     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &junk);
918     IOMGR_Initialize();
919 #endif
920     LWP_CreateProcess(SocketListener, /*stacksize*/16000, LWP_NORMAL_PRIORITY,
921                       0, "Socket Listener", &slPid);
922
923         /* just to close the log every five minutes */
924
925         LWP_CreateProcess(FiveMinuteCheckLWP, 24*1024,
926                  LWP_MAX_PRIORITY - 2, &fiveminutes,
927                  "FiveMinuteChecks", &checkPid);
928
929 #if MAIN
930     initialize_ka_error_table();
931     initialize_rxk_error_table();
932     while (1)                           /* don't just stand there, run it */
933         IOMGR_Sleep (60);
934 #else
935     return 0;
936 #endif
937
938 }
939
940 #if MAIN
941 char *lastOperation;            /* name of last operation */
942 char *lrealm = "REALMNAME";
943 struct kadstats dynamic_statistics;
944
945 static int InitAuthServ (tt, lock, this_op)
946   struct ubik_trans **tt;
947   int                 lock;             /* read or write transaction */
948   int                *this_op;          /* op of RCP routine, for COUNT_ABO */
949 {   int   code = 0;
950
951     *tt = 0;
952     printf ("Calling InitAuthServ\n");
953     return code;
954 }
955
956 static int ubik_EndTrans (tt)
957   struct ubik_trans *tt;
958 {
959     printf ("Calling ubik_EndTrans\n");
960     return 0;
961 }
962
963 static int ubik_AbortTrans (tt)
964   struct ubik_trans *tt;
965 {
966     printf ("Calling ubik_AbortTrans\n");
967     return 0;
968 }
969
970 static int FindBlock (at, aname, ainstance, tentry)
971   struct ubik_trans *at;
972   char              *aname;
973   char              *ainstance;
974   struct kaentry    *tentry;
975 {
976     printf ("Calling FindBlock with '%s'.'%s'\n", aname, ainstance);
977     strcpy (tentry->userID.name, aname);
978     strcpy (tentry->userID.instance, ainstance);
979     tentry->key_version = htonl(17);
980     des_string_to_key ("toa", &tentry->key);
981     tentry->flags = htonl(KAFNORMAL);
982     tentry->user_expiration = htonl(NEVERDATE);
983     tentry->max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
984     return 323232;
985 }
986
987 static int ka_LookupKey (tt, name, inst, kvno, key)
988   struct ubik_trans *tt;
989   char              *name;
990   char              *inst;
991   afs_int32                 *kvno;              /* returned */
992   struct ktc_encryptionKey *key;        /* copied out */
993 {
994     printf ("Calling ka_LookupKey with '%s'.'%s'\n", name, inst);
995     *kvno = 23;
996     des_string_to_key ("applexx", key);
997 }
998
999 static afs_int32 kvno_tgs_key (authDomain, kvno, tgskey)
1000   char *authDomain;
1001   afs_int32  kvno;
1002   struct ktc_encryptionKey *tgskey;
1003 {
1004     if (strcmp (authDomain, lrealm) != 0)
1005         printf ("Called with wrong %s as authDomain\n", authDomain);
1006     if (kvno != 23)
1007         printf ("kvno_tgs_key: being called with wrong kvno: %d\n", kvno);
1008     des_string_to_key ("applexx", tgskey);
1009     return 0;
1010 }
1011
1012 save_principal ()
1013 {
1014 }
1015 name_instance_legal ()
1016 {
1017     return 1;
1018 }
1019 #endif