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