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