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