c7d3a0b547ce4a510f9368ca432570803eaddd99
[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
403     if (cipherLen != 0) {
404         KALOG(name, inst, sname, sinst, NULL, client->sin_addr.s_addr,
405               LOG_TGTREQUEST);
406     }
407     osi_audit(UDPAuthenticateEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_END);
408     return 0;
409
410   abort:
411     COUNT_ABO;
412     ubik_AbortTrans(tt);
413
414   fail:
415     osi_audit(UDPAuthenticateEvent, code, AUD_STR, name, AUD_STR, inst,
416               AUD_END);
417     return code;
418 }
419
420 afs_int32
421 UDP_GetTicket(ksoc, pkt, kvno, authDomain, ticket, ticketLen, auth, authLen)
422      int ksoc;
423      struct packet *pkt;
424      afs_int32 kvno;
425      char *authDomain;
426      char *ticket;
427      int ticketLen;
428      char *auth;
429      int authLen;
430 {
431     afs_int32 code;
432     struct ktc_encryptionKey tgskey;
433     char name[MAXKTCNAMELEN];
434     char inst[MAXKTCNAMELEN];
435     char cell[MAXKTCREALMLEN];
436     struct ktc_encryptionKey authSessionKey;
437     afs_int32 host;
438     Date start;
439     Date authEnd;
440     Date now = time(0);
441     int celllen;
442     int import;
443
444     char *packet;
445     int slen;
446     int byteOrder = pkt->byteOrder;
447     char sname[MAXKTCNAMELEN];
448     char sinst[MAXKTCNAMELEN];
449     afs_int32 time_ws;
450     unsigned char life;
451
452     struct ubik_trans *tt;
453     afs_int32 to;
454     struct kaentry caller;
455     struct kaentry server;
456     Date reqEnd;
457     struct ktc_encryptionKey sessionKey;
458     int newTicketLen;
459     char newTicket[MAXKTCTICKETLEN];
460
461     char cipher[2 * MAXKTCTICKETLEN];   /* put encrypted part of answer here */
462     int cipherLen;
463     struct packet ans;
464
465     COUNT_REQ(UGetTicket);
466
467     if (code = InitAuthServ(&tt, LOCKREAD, this_op))
468         goto fail;
469     code =
470         ka_LookupKvno(tt, KA_TGS_NAME,
471                       ((strlen(authDomain) > 0) ? authDomain : lrealm), kvno,
472                       &tgskey);
473     if (code)
474         goto abort;
475
476     code =
477         tkt_DecodeTicket(ticket, ticketLen, &tgskey, name, inst, cell,
478                          &authSessionKey, &host, &start, &authEnd);
479     pkt->name = name;
480     pkt->inst = inst;
481     pkt->realm = cell;
482     if (code) {
483         code = KERB_ERR_AUTH_EXP;       /* was KANOAUTH */
484         goto abort;
485     }
486     save_principal(udptgsPrincipal, name, inst, cell);
487     code = tkt_CheckTimes(start, authEnd, now);
488     if (code <= 0) {
489         if (code == -1) {
490             code = KERB_ERR_SERVICE_EXP;        /* was RXKADEXPIRED */
491             goto abort;
492         }
493         code = KERB_ERR_AUTH_EXP;       /* was KANOAUTH */
494         goto abort;
495     }
496     celllen = strlen(cell);
497     import = 0;
498     if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
499         import = 1;
500     if (import && (celllen == 0)) {
501         code = KERB_ERR_PKT_VER;        /* was KABADTICKET */
502         goto abort;
503     }
504     if (celllen == 0) {
505         strncpy(cell, lrealm, MAXKTCREALMLEN - 1);
506         cell[MAXKTCREALMLEN - 1] = 0;
507     };
508
509     if (!krb4_cross && strcmp(lrealm, cell) != 0) {
510         code = KERB_ERR_PRINCIPAL_UNKNOWN;
511         goto abort;
512     }
513
514     if (krb_udp_debug) {
515         printf("UGetTicket: got ticket from '%s'.'%s'@'%s'\n", name, inst,
516                cell);
517     }
518
519     code = check_auth(pkt, auth, authLen, &authSessionKey, name, inst, cell);
520     if (code)
521         goto abort;
522
523     /* authenticator and all is OK so read actual request */
524     packet = pkt->rest;
525     getint(time_ws);
526     life = *(unsigned char *)packet++;
527     getstr(sname);
528     getstr(sinst);
529     start = now;
530     reqEnd = life_to_time(start, life);
531     if (krb_udp_debug) {
532         printf("UGetTicket: request for server '%s'.'%s'\n", sname, sinst);
533     }
534     save_principal(udptgsServerPrincipal, sname, sinst, 0);
535
536     if (import) {
537         strcpy(caller.userID.name, name);
538         strcpy(caller.userID.instance, inst);
539         caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
540     } else {
541         code = FindBlock(tt, name, inst, &to, &caller);
542         if (code)
543             goto abort;
544         if (to == 0) {
545             ka_PrintUserID("GetTicket: User ", name, inst, " unknown.\n");
546             code = KERB_ERR_PRINCIPAL_UNKNOWN;  /* KANOENT */
547             goto abort;
548         }
549         if (ntohl(caller.flags) & KAFNOTGS) {
550             code = KERB_ERR_AUTH_EXP;   /* was KABADUSER */
551             goto abort;
552         }
553     }
554
555     code = FindBlock(tt, sname, sinst, &to, &server);   /* get server's entry */
556     if (code)
557         goto abort;
558     if (to == 0) {              /* entry not found */
559         ka_PrintUserID("GetTicket: Server ", sname, sinst, " unknown.\n");
560         code = KERB_ERR_PRINCIPAL_UNKNOWN;      /* KANOENT */
561         goto abort;
562     }
563     code = ubik_EndTrans(tt);
564     if (code)
565         goto fail;
566
567     if (ntohl(server.flags) & KAFNOSEAL)
568         return KABADSERVER;
569
570     code = des_random_key(&sessionKey);
571     if (code) {
572         code = KERB_ERR_NULL_KEY;       /* was KANOKEYS */
573         goto fail;
574     }
575
576     reqEnd =
577         umin(umin(reqEnd, authEnd),
578              umin(start + ntohl(caller.max_ticket_lifetime),
579                   start + ntohl(server.max_ticket_lifetime)));
580
581     code =
582         tkt_MakeTicket(newTicket, &newTicketLen, &server.key,
583                        caller.userID.name, caller.userID.instance, cell,
584                        start, reqEnd, &sessionKey,
585                        htonl(pkt->from.sin_addr.s_addr), server.userID.name,
586                        server.userID.instance);
587     if (code)
588         goto fail;
589
590     cipherLen = sizeof(cipher);
591     code =
592         create_cipher(cipher, &cipherLen, &sessionKey, sname, sinst, start,
593                       reqEnd, ntohl(server.key_version), newTicket,
594                       newTicketLen, &authSessionKey);
595     if (code)
596         goto fail;
597
598     code =
599         create_reply(&ans, name, inst, start, reqEnd, 0, cipher, cipherLen);
600     if (code)
601         goto fail;
602
603     code =
604         sendto(ksoc, ans.data, ans.len, 0, (struct sockaddr *)&pkt->from,
605                sizeof(pkt->from));
606     if (code != ans.len) {
607         perror("calling sendto");
608         code = -1;
609         goto fail;
610     }
611
612     if (cipherLen != 0) {
613         KALOG(name, inst, sname, sinst, NULL, host, LOG_GETTICKET);
614     }
615     osi_audit(UDPGetTicketEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_STR,
616               cell, AUD_STR, sname, AUD_STR, sinst, AUD_END);
617     return 0;
618
619   abort:
620     ubik_AbortTrans(tt);
621   fail:
622     osi_audit(UDPGetTicketEvent, code, AUD_STR, name, AUD_STR, inst, AUD_STR,
623               NULL, AUD_STR, NULL, AUD_STR, NULL, AUD_END);
624     return code;
625 }
626
627 static int
628 err_packet(ksoc, pkt, code, reason)
629      int ksoc;
630      struct packet *pkt;
631      afs_int32 code;
632      char *reason;
633 {
634     struct packet ans;
635     char *answer = ans.data;
636     int slen;
637     char buf[256];
638
639     if (reason == 0)
640         reason = "";
641     snprintf(buf, 255, "code = %d: %s", code, reason);
642
643     if (krb_udp_debug) {
644         printf("Sending error packet to '%s'.'%s'@'%s' containing %s\n",
645                pkt->name, pkt->inst, pkt->realm, buf);
646     }
647
648     ans.len =
649         2 + strlen(pkt->name) + strlen(pkt->inst) + strlen(pkt->realm) +
650         3 /* nulls */  + (2 * sizeof(afs_int32)) + strlen(buf) + 1;
651     if (ans.len > sizeof(ans.data)) {
652         printf("Answer packet too long\n");
653         return -1;
654     }
655
656     *answer++ = (unsigned char)KRB_PROT_VERSION;
657     *answer++ = (unsigned char)AUTH_MSG_ERR_REPLY;
658     /* always send claiming network byte order */
659     putstr(pkt->name);
660     putstr(pkt->inst);
661     putstr(pkt->realm);
662     putint(pkt->time);
663     if ((code < 0) || (code > KERB_ERR_MAXIMUM)) {
664         /* It could be because of kauth errors so we should return something instead of success!! */
665         code = KDC_GEN_ERR;
666     }
667     putint(code);
668     putstr(buf);
669
670     code =
671         sendto(ksoc, ans.data, ans.len, 0, (struct sockaddr *)&pkt->from,
672                sizeof(pkt->from));
673     if (code != ans.len) {
674         if (code >= 0)
675             printf
676                 ("call to sendto returned %d, sending error packet %d bytes long\n",
677                  code, ans.len);
678         else
679             perror("err_packet: sendto");
680     }
681     return 0;
682 }
683
684 int
685 process_udp_auth(ksoc, pkt)
686      int ksoc;
687      struct packet *pkt;
688 {
689     char *packet = pkt->rest;
690     char name[MAXKTCNAMELEN];
691     char inst[MAXKTCNAMELEN];
692     char realm[MAXKTCREALMLEN];
693     char sname[MAXKTCNAMELEN];
694     char sinst[MAXKTCNAMELEN];
695     int slen;
696     Date now = time(0);
697     Date startTime, endTime;
698     unsigned char lifetime;
699     afs_int32 code;
700
701     pkt->name = packet;
702     getstr(name);
703     pkt->inst = packet;
704     getstr(inst);
705     pkt->realm = packet;
706     getstr(realm);
707     if (krb_udp_debug) {
708         printf("Processing KDC Request from '%s'.'%s'@'%s'\n", name, inst,
709                realm);
710     }
711
712     if ((strlen(realm) > 0) && (strcmp(realm, lrealm) != 0)) {
713         err_packet(ksoc, pkt, KERB_ERR_NONNULL_REALM,
714                    "null realm name not allowed");
715         return -1;
716     }
717     memcpy(&startTime, packet, sizeof(startTime));
718     packet += sizeof(startTime);
719     startTime = ktohl(pkt->byteOrder, startTime);
720     pkt->time = startTime;
721     lifetime = *packet++;
722     endTime = life_to_time(startTime, lifetime);
723     code = tkt_CheckTimes(startTime, endTime, now);
724     if (code < 0) {
725         err_packet(ksoc, pkt, KERB_ERR_BAD_LIFETIME,
726                    "requested ticket lifetime invalid");
727         return -1;
728     }
729     getstr(sname);
730     getstr(sinst);
731     if ((packet - pkt->data) != pkt->len) {
732         err_packet(ksoc, pkt, KERB_ERR_PKT_LENGTH,
733                    "packet length inconsistent");
734         return -1;
735     }
736     pkt->rest = packet;
737     code =
738         UDP_Authenticate(ksoc, &pkt->from, name, inst, startTime, endTime,
739                          sname, sinst);
740     if (code) {
741         if (code == KANOENT) {
742             code = KERB_ERR_PRINCIPAL_UNKNOWN;
743             err_packet(ksoc, pkt, code, (char *)afs_error_message(code));
744         } else if (code == KAPWEXPIRED) {
745             code = KERB_ERR_NAME_EXP;
746             err_packet(ksoc, pkt, code, "password has expired");
747         } else
748             err_packet(ksoc, pkt, code, (char *)afs_error_message(code));
749     }
750     return 0;
751 }
752
753 int
754 process_udp_appl(ksoc, pkt)
755      int ksoc;
756      struct packet *pkt;
757 {
758     char *packet = pkt->rest;
759     afs_int32 kvno;
760     char realm[MAXKTCREALMLEN];
761     char ticket[MAXKTCTICKETLEN];
762     char auth[3 * MAXKTCNAMELEN + 4 + 5];
763     int slen;
764     int ticketLen, authLen;
765     afs_int32 code;
766
767     if (krb_udp_debug) {
768         printf("Processing APPL Request\n");
769     }
770     kvno = *packet++;
771     getstr(realm);
772     ticketLen = *(unsigned char *)packet++;
773     authLen = *(unsigned char *)packet++;
774     if (ticketLen > sizeof(ticket)) {
775         err_packet(ksoc, pkt, KERB_ERR_TEXT_LENGTH, "ticket too long");
776         return -1;
777     }
778     memcpy(ticket, packet, ticketLen);
779     packet += ticketLen;
780     if (authLen > sizeof(auth)) {
781         err_packet(ksoc, pkt, KERB_ERR_TEXT_LENGTH, "authenticator too long");
782         return -1;
783     }
784     memcpy(auth, packet, authLen);
785     pkt->rest = packet + authLen;
786     code =
787         UDP_GetTicket(ksoc, pkt, kvno, realm, ticket, ticketLen, auth,
788                       authLen);
789     if (code) {
790         if (code == KANOENT)
791             code = KERB_ERR_PRINCIPAL_UNKNOWN;
792         err_packet(ksoc, pkt, code, (char *)afs_error_message(code));
793         return -1;
794     }
795     return 0;
796 }
797
798 void
799 process_udp_request(ksoc, pkt)
800      int ksoc;
801      struct packet *pkt;
802 {
803     char *packet = pkt->data;
804     unsigned char version, auth_msg_type;
805
806     version = *packet++;
807     if (version != KRB_PROT_VERSION) {
808         err_packet(ksoc, pkt, KERB_ERR_PKT_VER,
809                    "packet version number unknown");
810         return;
811     }
812     auth_msg_type = *packet++;
813     pkt->byteOrder = auth_msg_type & 1;
814     pkt->rest = packet;
815     switch (auth_msg_type & ~1) {
816     case AUTH_MSG_KDC_REQUEST:
817         process_udp_auth(ksoc, pkt);
818         break;
819     case AUTH_MSG_APPL_REQUEST:
820         process_udp_appl(ksoc, pkt);
821         break;
822     default:
823         printf("unknown msg type 0x%x\n", auth_msg_type);
824         err_packet(ksoc, pkt, KERB_ERR_BAD_MSG_TYPE,
825                    "message type not supported");
826         return;
827     }
828     return;
829 }
830
831 static
832 SocketListener()
833 {
834     fd_set rfds;
835     struct timeval tv;
836     struct packet packet;
837     int fromLen;
838     afs_int32 code;
839
840     printf("Starting to listen for UDP packets\n");
841     while (1) {
842         FD_ZERO(&rfds);
843         if (sock_kerb >= 0)
844             FD_SET(sock_kerb, &rfds);
845         if (sock_kerb5 >= 0)
846             FD_SET(sock_kerb5, &rfds);
847
848         tv.tv_sec = 100;
849         tv.tv_usec = 0;
850         /* write and exception fd_set's are null */
851         code = IOMGR_Select(32, &rfds, NULL, NULL, &tv);
852         if (code == 0) {        /* timeout */
853             /* printf ("Timeout\n"); */
854             continue;
855         } else if (code < 0) {
856             perror("calling IOMGR_Select");
857             break;
858         }
859
860         fromLen = sizeof(packet.from);
861         if ((sock_kerb >= 0) && FD_ISSET(sock_kerb, &rfds)) {
862             code =
863                 recvfrom(sock_kerb, packet.data, sizeof(packet.data), 0,
864                          (struct sockaddr *)&packet.from, &fromLen);
865             if (code < 0) {
866                 if (errno == EAGAIN || errno == ECONNREFUSED)
867                     goto try_kerb5;
868                 perror("calling recvfrom");
869                 break;
870             }
871             packet.len = code;
872             if (krb_udp_debug) {
873                 printf("Kerb:udp: Got %d bytes from addr %s which are '",
874                        code, afs_inet_ntoa(packet.from.sin_addr.s_addr));
875                 ka_PrintBytes(packet.data, packet.len);
876                 printf("'\n");
877             }
878             packet.name = packet.inst = packet.realm = "";
879             packet.time = 0;
880             process_udp_request(sock_kerb, &packet);
881         }
882       try_kerb5:
883         if ((sock_kerb5 >= 0) && FD_ISSET(sock_kerb5, &rfds)) {
884             code =
885                 recvfrom(sock_kerb5, packet.data, sizeof(packet.data), 0,
886                          (struct sockaddr *)&packet.from, &fromLen);
887             if (code < 0) {
888                 if (errno == EAGAIN || errno == ECONNREFUSED)
889                     continue;
890                 perror("calling recvfrom");
891                 break;
892             }
893             packet.len = code;
894             if (krb_udp_debug) {
895                 printf("Kerb5:udp: Got %d bytes from addr %s which are '",
896                        code, afs_inet_ntoa(packet.from.sin_addr.s_addr));
897                 ka_PrintBytes(packet.data, packet.len);
898                 printf("'\n");
899             }
900             packet.name = packet.inst = packet.realm = "";
901             packet.time = 0;
902             process_udp_request(sock_kerb5, &packet);
903         }
904     }
905     if (sock_kerb >= 0) {
906         close(sock_kerb);
907         sock_kerb = -1;
908     }
909     if (sock_kerb5 >= 0) {
910         close(sock_kerb5);
911         sock_kerb5 = -1;
912     }
913     printf("UDP SocketListener exiting due to error\n");
914 }
915
916 #if MAIN
917
918 #include "AFS_component_version_number.c"
919
920 main()
921 #else
922 afs_int32
923 init_krb_udp()
924 #endif
925 {
926     struct sockaddr_in taddr;
927     static PROCESS slPid;       /* socket listener pid */
928     static PROCESS checkPid;    /* fiveminute check */
929     afs_int32 code;
930     char *krb4name;             /* kerberos version4 service */
931
932 #if MAIN
933     PROCESS junk;
934 #endif
935     struct servent *sp;
936     static int inited = 0;
937     afs_int32 kerb_port;
938
939     if (inited)
940         return -1;
941     inited = 1;
942
943     memset(&taddr, 0, sizeof(taddr));
944     krb4name = "kerberos4";
945     sp = getservbyname(krb4name, "udp");
946     taddr.sin_family = AF_INET; /* added for NCR port */
947 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
948     taddr.sin_len = sizeof(struct sockaddr_in);
949 #endif
950     if (!sp) {
951         /* if kerberos-4 is not available, try "kerberos-iv" */
952         krb4name = "kerberos-iv";
953         sp = getservbyname(krb4name, "udp");
954     }
955     if (!sp) {
956         /* if kerberos-iv is not available, try "kerberos" */
957         krb4name = "kerberos";
958         sp = getservbyname(krb4name, "udp");
959     }
960     if (!sp) {
961         fprintf(stderr,
962                 "kerberos/udp is unknown; check /etc/services.  Using port=%d as default\n",
963                 KRB_PORT);
964         taddr.sin_port = htons(KRB_PORT);
965     } else {
966         /* copy the port number */
967         fprintf(stderr, "%s/udp port=%hu\n", krb4name,
968                 (unsigned short)sp->s_port);
969         taddr.sin_port = sp->s_port;
970     }
971     kerb_port = taddr.sin_port;
972     sock_kerb = socket(AF_INET, SOCK_DGRAM, 0);
973     code = bind(sock_kerb, (struct sockaddr *)&taddr, sizeof(taddr));
974     if (code < 0) {
975         perror("calling bind");
976         sock_kerb = -1;
977     }
978
979     sp = getservbyname("kerberos5", "udp");
980     if (!sp) {
981         fprintf(stderr,
982                 "kerberos5/udp is unknown; check /etc/services.  Using port=%d as default\n",
983                 KRB5_PORT);
984         taddr.sin_port = htons(KRB5_PORT);
985     } else {
986         /* copy the port number */
987         fprintf(stderr, "kerberos5/udp port=%hu\n",
988                 (unsigned short)sp->s_port);
989         taddr.sin_port = sp->s_port;
990     }
991     if (taddr.sin_port != kerb_port) {  /* a different port */
992         sock_kerb5 = socket(AF_INET, SOCK_DGRAM, 0);
993         code = bind(sock_kerb5, (struct sockaddr *)&taddr, sizeof(taddr));
994         if (code < 0) {
995             perror("calling bind");
996             sock_kerb5 = -1;
997         }
998     }
999
1000     /* Bail out if we can't bind with any port */
1001     if ((sock_kerb < 0) && (sock_kerb5 < 0))
1002         return -1;
1003
1004 #if MAIN
1005     /* this has already been done */
1006     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &junk);
1007     IOMGR_Initialize();
1008 #endif
1009     LWP_CreateProcess(SocketListener, /*stacksize */ 16000,
1010                       LWP_NORMAL_PRIORITY, (void *)0, "Socket Listener",
1011                       &slPid);
1012
1013     /* just to close the log every five minutes */
1014
1015     LWP_CreateProcess(FiveMinuteCheckLWP, 24 * 1024, LWP_MAX_PRIORITY - 2,
1016                       (void *)&fiveminutes, "FiveMinuteChecks", &checkPid);
1017
1018 #if MAIN
1019     initialize_ka_error_table();
1020     initialize_rxk_error_table();
1021     while (1)                   /* don't just stand there, run it */
1022         IOMGR_Sleep(60);
1023 #else
1024     return 0;
1025 #endif
1026
1027 }
1028
1029 #if MAIN
1030 char *lastOperation;            /* name of last operation */
1031 char *lrealm = "REALMNAME";
1032 struct kadstats dynamic_statistics;
1033
1034 static int
1035 InitAuthServ(tt, lock, this_op)
1036      struct ubik_trans **tt;
1037      int lock;                  /* read or write transaction */
1038      int *this_op;              /* op of RCP routine, for COUNT_ABO */
1039 {
1040     int code = 0;
1041
1042     *tt = 0;
1043     printf("Calling InitAuthServ\n");
1044     return code;
1045 }
1046
1047 static int
1048 ubik_EndTrans(tt)
1049      struct ubik_trans *tt;
1050 {
1051     printf("Calling ubik_EndTrans\n");
1052     return 0;
1053 }
1054
1055 static int
1056 ubik_AbortTrans(tt)
1057      struct ubik_trans *tt;
1058 {
1059     printf("Calling ubik_AbortTrans\n");
1060     return 0;
1061 }
1062
1063 static int
1064 FindBlock(at, aname, ainstance, tentry)
1065      struct ubik_trans *at;
1066      char *aname;
1067      char *ainstance;
1068      struct kaentry *tentry;
1069 {
1070     printf("Calling FindBlock with '%s'.'%s'\n", aname, ainstance);
1071     strcpy(tentry->userID.name, aname);
1072     strcpy(tentry->userID.instance, ainstance);
1073     tentry->key_version = htonl(17);
1074     des_string_to_key("toa", &tentry->key);
1075     tentry->flags = htonl(KAFNORMAL);
1076     tentry->user_expiration = htonl(NEVERDATE);
1077     tentry->max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1078     return 323232;
1079 }
1080
1081 static int
1082 ka_LookupKey(tt, name, inst, kvno, key)
1083      struct ubik_trans *tt;
1084      char *name;
1085      char *inst;
1086      afs_int32 *kvno;           /* returned */
1087      struct ktc_encryptionKey *key;     /* copied out */
1088 {
1089     printf("Calling ka_LookupKey with '%s'.'%s'\n", name, inst);
1090     *kvno = 23;
1091     des_string_to_key("applexx", key);
1092 }
1093
1094 static afs_int32
1095 kvno_tgs_key(authDomain, kvno, tgskey)
1096      char *authDomain;
1097      afs_int32 kvno;
1098      struct ktc_encryptionKey *tgskey;
1099 {
1100     if (strcmp(authDomain, lrealm) != 0)
1101         printf("Called with wrong %s as authDomain\n", authDomain);
1102     if (kvno != 23)
1103         printf("kvno_tgs_key: being called with wrong kvno: %d\n", kvno);
1104     des_string_to_key("applexx", tgskey);
1105     return 0;
1106 }
1107
1108 save_principal()
1109 {
1110 }
1111
1112 name_instance_legal()
1113 {
1114     return 1;
1115 }
1116 #endif