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