]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/Zinternal.c
done milestone 3; working on refactoring
[1ts-debian.git] / zephyr / lib / Zinternal.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains source for the internal Zephyr routines.
3  *
4  *      Created by:     Robert French
5  *
6  *      $Id: Zinternal.c,v 1.42 2002/09/10 16:04:31 ghudson Exp $
7  *
8  *      Copyright (c) 1987,1988,1991 by the Massachusetts Institute of
9  *      Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h". 
12  */
13
14 #include <internal.h>
15 #include <arpa/inet.h>
16 #include <sys/socket.h>
17 #include <utmp.h>
18
19 #ifndef lint
20 static const char rcsid_Zinternal_c[] =
21   "$Id: Zinternal.c,v 1.42 2002/09/10 16:04:31 ghudson Exp $";
22 static const char copyright[] =
23   "Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.";
24 #endif
25
26 extern char *inet_ntoa ();
27
28 int __Zephyr_fd = -1;
29 int __Zephyr_open;
30 int __Zephyr_port = -1;
31 struct in_addr __My_addr;
32 int __Q_CompleteLength;
33 int __Q_Size;
34 struct _Z_InputQ *__Q_Head, *__Q_Tail;
35 struct sockaddr_in __HM_addr;
36 struct sockaddr_in __HM_addr_real;
37 int __HM_set;
38 int __Zephyr_server;
39 ZLocations_t *__locate_list;
40 int __locate_num;
41 int __locate_next;
42 ZSubscription_t *__subscriptions_list;
43 int __subscriptions_num;
44 int __subscriptions_next;
45 int Z_discarded_packets = 0;
46
47 #ifdef HAVE_KRB5
48 /* This context is used throughout */
49 krb5_context Z_krb5_ctx;
50
51 static struct cksum_map_s {
52   krb5_enctype e;
53   krb5_cksumtype c;
54 } cksum_map[] = {
55   /* per RFC1510 and draft-ietf-krb-wg-crypto-02.txt */
56   { ENCTYPE_NULL,                     CKSUMTYPE_RSA_MD5 },
57   { ENCTYPE_DES_CBC_CRC,              CKSUMTYPE_RSA_MD5_DES },
58   { ENCTYPE_DES_CBC_MD4,              CKSUMTYPE_RSA_MD4_DES },
59   { ENCTYPE_DES_CBC_MD5,              CKSUMTYPE_RSA_MD5_DES },
60
61   /* 
62    * The implementors hate us, and are inconsistent with names for
63    * most things defined after RFC1510.  Note that des3-cbc-sha1
64    * and des3-cbc-sha1-kd are listed by number to avoid confusion 
65    * caused by inconsistency between the names used in the specs
66    * and those used by implementations.
67    * -- jhutz, 30-Nov-2002
68    */
69
70   /* source lost in history (an expired internet-draft) */
71   { 5 /* des3-cbc-md5 */,             9  /* rsa-md5-des3 */ },
72   { 7 /* des3-cbc-sha1 */,            12 /* hmac-sha1-des3 */ },
73
74   /* per draft-ietf-krb-wg-crypto-02.txt */
75   { 16 /* des3-cbc-sha1-kd */,        12 /* hmac-sha1-des3-kd */ },
76
77   /* per draft-raeburn-krb-rijndael-krb-02.txt */
78   { 17 /* aes128-cts-hmac-sha1-96 */, 10 /* hmac-sha1-96-aes128 */ },
79   { 18 /* aes256-cts-hmac-sha1-96 */, 11 /* hmac-sha1-96-aes256 */ },
80
81   /* per draft-brezak-win2k-krb-rc4-hmac-04.txt */
82   { 23 /* rc4-hmac */,                -138 /* hmac-md5 */ },
83   { 24 /* rc4-hmac-exp */,            -138 /* hmac-md5 */ },
84 };
85 #define N_CKSUM_MAP (sizeof(cksum_map) / sizeof(struct cksum_map_s))
86
87 Code_t Z_krb5_lookup_cksumtype(krb5_enctype e, krb5_cksumtype *c)
88 {
89   int i;
90
91   for (i = 0; i < N_CKSUM_MAP; i++) {
92     if (cksum_map[i].e == e) {
93       *c = cksum_map[i].c;
94       return ZERR_NONE;
95     }
96   }
97   return KRB5_PROG_ETYPE_NOSUPP;
98 }
99 #endif /* HAVE_KRB5 */
100
101 char __Zephyr_realm[REALM_SZ];
102
103 #ifdef Z_DEBUG
104 void (*__Z_debug_print) __P((const char *fmt, va_list args, void *closure));
105 void *__Z_debug_print_closure;
106 #endif
107
108 #define min(a,b) ((a)<(b)?(a):(b))
109
110 static int Z_AddField __P((char **ptr, char *field, char *end));
111 static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind));
112
113 /* Find or insert uid in the old uids buffer.  The buffer is a sorted
114  * circular queue.  We make the assumption that most packets arrive in
115  * order, so we can usually search for a uid or insert it into the buffer
116  * by looking back just a few entries from the end.  Since this code is
117  * only executed by the client, the implementation isn't microoptimized. */
118 static int find_or_insert_uid(uid, kind)
119     ZUnique_Id_t *uid;
120     ZNotice_Kind_t kind;
121 {
122     static struct _filter {
123         ZUnique_Id_t    uid;
124         ZNotice_Kind_t  kind;
125         time_t          t;
126     } *buffer;
127     static long size;
128     static long start;
129     static long num;
130
131     time_t now;
132     struct _filter *new;
133     long i, j, new_size;
134     int result;
135
136     /* Initialize the uid buffer if it hasn't been done already. */
137     if (!buffer) {
138         size = Z_INITFILTERSIZE;
139         buffer = (struct _filter *) malloc(size * sizeof(*buffer));
140         if (!buffer)
141             return 0;
142     }
143
144     /* Age the uid buffer, discarding any uids older than the clock skew. */
145     time(&now);
146     while (num && (now - buffer[start % size].t) > CLOCK_SKEW)
147         start++, num--;
148     start %= size;
149
150     /* Make room for a new uid, since we'll probably have to insert one. */
151     if (num == size) {
152         new_size = size * 2 + 2;
153         new = (struct _filter *) malloc(new_size * sizeof(*new));
154         if (!new)
155             return 0;
156         for (i = 0; i < num; i++)
157             new[i] = buffer[(start + i) % size];
158         free(buffer);
159         buffer = new;
160         size = new_size;
161         start = 0;
162     }
163
164     /* Search for this uid in the buffer, starting from the end. */
165     for (i = start + num - 1; i >= start; i--) {
166         result = memcmp(uid, &buffer[i % size].uid, sizeof(*uid));
167         if (result == 0 && buffer[i % size].kind == kind)
168             return 1;
169         if (result > 0)
170             break;
171     }
172
173     /* We didn't find it; insert the uid into the buffer after i. */
174     i++;
175     for (j = start + num; j > i; j--)
176         buffer[j % size] = buffer[(j - 1) % size];
177     buffer[i % size].uid = *uid;
178     buffer[i % size].kind = kind;
179     buffer[i % size].t = now;
180     num++;
181
182     return 0;
183 }
184
185
186 /* Return 1 if there is a packet waiting, 0 otherwise */
187
188 int Z_PacketWaiting()
189 {
190     struct timeval tv;
191     fd_set read;
192
193     tv.tv_sec = tv.tv_usec = 0;
194     FD_ZERO(&read);
195     FD_SET(ZGetFD(), &read);
196     return (select(ZGetFD() + 1, &read, NULL, NULL, &tv));
197
198
199
200 /* Wait for a complete notice to become available */
201
202 Code_t Z_WaitForComplete()
203 {
204     Code_t retval;
205
206     if (__Q_CompleteLength)
207         return (Z_ReadEnqueue());
208
209     while (!__Q_CompleteLength)
210         if ((retval = Z_ReadWait()) != ZERR_NONE)
211             return (retval);
212
213     return (ZERR_NONE);
214 }
215
216
217 /* Read any available packets and enqueue them */
218
219 Code_t Z_ReadEnqueue()
220 {
221     Code_t retval;
222
223     if (ZGetFD() < 0)
224         return (ZERR_NOPORT);
225     
226     while (Z_PacketWaiting())
227         if ((retval = Z_ReadWait()) != ZERR_NONE)
228             return (retval);
229
230     return (ZERR_NONE);
231 }
232
233
234 /*
235  * Search the queue for a notice with the proper multiuid - remove any
236  * notices that haven't been touched in a while
237  */
238
239 struct _Z_InputQ *Z_SearchQueue(uid, kind)
240     ZUnique_Id_t *uid;
241     ZNotice_Kind_t kind;
242 {
243     register struct _Z_InputQ *qptr;
244     struct _Z_InputQ *next;
245     struct timeval tv;
246
247     (void) gettimeofday(&tv, (struct timezone *)0);
248
249     qptr = __Q_Head;
250
251     while (qptr) {
252         if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind)
253             return (qptr);
254         next = qptr->next;
255         if (qptr->timep && (qptr->timep+Z_NOTICETIMELIMIT < tv.tv_sec))
256             Z_RemQueue(qptr);
257         qptr = next;
258     }
259     return (NULL);
260 }
261
262 /*
263  * Now we delve into really convoluted queue handling and
264  * fragmentation reassembly algorithms and other stuff you probably
265  * don't want to look at...
266  *
267  * This routine does NOT guarantee a complete packet will be ready when it
268  * returns.
269  */
270
271 Code_t Z_ReadWait()
272 {
273     register struct _Z_InputQ *qptr;
274     ZNotice_t notice;
275     ZPacket_t packet;
276     struct sockaddr_in olddest, from;
277     int from_len, packet_len, zvlen, part, partof;
278     char *slash;
279     Code_t retval;
280     fd_set fds;
281     struct timeval tv;
282
283     if (ZGetFD() < 0)
284         return (ZERR_NOPORT);
285         
286     FD_ZERO(&fds);
287     FD_SET(ZGetFD(), &fds);
288     tv.tv_sec = 60;
289     tv.tv_usec = 0;
290
291     if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0)
292       return (errno);
293     if (!FD_ISSET(ZGetFD(), &fds))
294       return ETIMEDOUT;
295
296     from_len = sizeof(struct sockaddr_in);
297
298     packet_len = recvfrom(ZGetFD(), packet, sizeof(packet), 0, 
299                           (struct sockaddr *)&from, &from_len);
300
301     if (packet_len < 0)
302         return (errno);
303
304     if (!packet_len)
305         return (ZERR_EOF);
306
307     /* Ignore obviously non-Zephyr packets. */
308     zvlen = sizeof(ZVERSIONHDR) - 1;
309     if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) {
310         Z_discarded_packets++;
311         return (ZERR_NONE);
312     }   
313
314     /* Parse the notice */
315     if ((retval = ZParseNotice(packet, packet_len, &notice)) != ZERR_NONE)
316         return (retval);
317
318     /*
319      * If we're not a server and the notice is of an appropriate kind,
320      * send back a CLIENTACK to whoever sent it to say we got it.
321      */
322     if (!__Zephyr_server) {
323         if (notice.z_kind != HMACK && notice.z_kind != SERVACK &&
324             notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) {
325             ZNotice_t tmpnotice;
326             ZPacket_t pkt;
327             int len;
328
329             tmpnotice = notice;
330             tmpnotice.z_kind = CLIENTACK;
331             tmpnotice.z_message_len = 0;
332             olddest = __HM_addr;
333             __HM_addr = from;
334             if ((retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len))
335                 != ZERR_NONE)
336                 return(retval);
337             if ((retval = ZSendPacket(pkt, len, 0)) != ZERR_NONE)
338                 return (retval);
339             __HM_addr = olddest;
340         }
341         if (find_or_insert_uid(&notice.z_uid, notice.z_kind))
342             return(ZERR_NONE);
343
344         /* Check authentication on the notice. */
345         notice.z_checked_auth = ZCheckAuthentication(&notice, &from);
346     }
347
348
349     /*
350      * Parse apart the z_multinotice field - if the field is blank for
351      * some reason, assume this packet stands by itself.
352      */
353     slash = strchr(notice.z_multinotice, '/');
354     if (slash) {
355         part = atoi(notice.z_multinotice);
356         partof = atoi(slash+1);
357         if (part > partof || partof == 0) {
358             part = 0;
359             partof = notice.z_message_len;
360         }
361     }
362     else {
363         part = 0;
364         partof = notice.z_message_len;
365     }
366
367     /* Too big a packet...just ignore it! */
368     if (partof > Z_MAXNOTICESIZE)
369         return (ZERR_NONE);
370
371     /*
372      * If we aren't a server and we can find a notice in the queue
373      * with the same multiuid field, insert the current fragment as
374      * appropriate.
375      */
376     switch (notice.z_kind) {
377     case SERVACK:
378     case SERVNAK:
379         /* The SERVACK and SERVNAK replies shouldn't be reassembled
380            (they have no parts).  Instead, we should hold on to the reply
381            ONLY if it's the first part of a fragmented message, i.e.
382            multi_uid == uid.  This allows programs to wait for the uid
383            of the first packet, and get a response when that notice
384            arrives.  Acknowledgements of the other fragments are discarded
385            (XXX we assume here that they all carry the same information
386            regarding failure/success)
387          */
388         if (!__Zephyr_server &&
389             !ZCompareUID(&notice.z_multiuid, &notice.z_uid))
390             /* they're not the same... throw away this packet. */
391             return(ZERR_NONE);
392         /* fall thru & process it */
393     default:
394         /* for HMACK types, we assume no packet loss (local loopback
395            connections).  The other types can be fragmented and MUST
396            run through this code. */
397         if (!__Zephyr_server && (qptr = Z_SearchQueue(&notice.z_multiuid,
398                                                       notice.z_kind))) {
399             /*
400              * If this is the first fragment, and we haven't already
401              * gotten a first fragment, grab the header from it.
402              */
403             if (part == 0 && !qptr->header) {
404                 qptr->header_len = packet_len-notice.z_message_len;
405                 qptr->header = (char *) malloc((unsigned) qptr->header_len);
406                 if (!qptr->header)
407                     return (ENOMEM);
408                 (void) memcpy(qptr->header, packet, qptr->header_len);
409             }
410             return (Z_AddNoticeToEntry(qptr, &notice, part));
411         }
412     }
413
414     /*
415      * We'll have to create a new entry...make sure the queue isn't
416      * going to get too big.
417      */
418     if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE)
419         return (ZERR_NONE);
420
421     /*
422      * This is a notice we haven't heard of, so create a new queue
423      * entry for it and zero it out.
424      */
425     qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ));
426     if (!qptr)
427         return (ENOMEM);
428     (void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ));
429
430     /* Insert the entry at the end of the queue */
431     qptr->next = NULL;
432     qptr->prev = __Q_Tail;
433     if (__Q_Tail)
434         __Q_Tail->next = qptr;
435     __Q_Tail = qptr;
436
437     if (!__Q_Head)
438         __Q_Head = qptr;
439
440     
441     /* Copy the from field, multiuid, kind, and checked authentication. */
442     qptr->from = from;
443     qptr->uid = notice.z_multiuid;
444     qptr->kind = notice.z_kind;
445     qptr->auth = notice.z_checked_auth;
446     
447     /*
448      * If this is the first part of the notice, we take the header
449      * from it.  We only take it if this is the first fragment so that
450      * the Unique ID's will be predictable.
451      *
452      * If a Zephyr Server, we always take the header.
453      */
454     if (__Zephyr_server || part == 0) {
455         qptr->header_len = packet_len-notice.z_message_len;
456         qptr->header = (char *) malloc((unsigned) qptr->header_len);
457         if (!qptr->header)
458             return ENOMEM;
459         (void) memcpy(qptr->header, packet, qptr->header_len);
460     }
461
462     /*
463      * If this is not a fragmented notice, then don't bother with a
464      * hole list.
465      * If we are a Zephyr server, all notices are treated as complete.
466      */
467     if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) {
468         __Q_CompleteLength++;
469         qptr->holelist = (struct _Z_Hole *) 0;
470         qptr->complete = 1;
471         /* allocate a msg buf for this piece */
472         if (notice.z_message_len == 0)
473             qptr->msg = 0;
474         else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len)))
475             return(ENOMEM);
476         else
477             (void) memcpy(qptr->msg, notice.z_message, notice.z_message_len);
478         qptr->msg_len = notice.z_message_len;
479         __Q_Size += notice.z_message_len;
480         qptr->packet_len = qptr->header_len+qptr->msg_len;
481         if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
482             return (ENOMEM);
483         (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
484         if(qptr->msg)
485             (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
486                            qptr->msg_len);
487         return (ZERR_NONE);
488     }
489
490     /*
491      * We know how long the message is going to be (this is better
492      * than IP fragmentation...), so go ahead and allocate it all.
493      */
494     if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof)
495         return (ENOMEM);
496     qptr->msg_len = partof;
497     __Q_Size += partof;
498
499     /*
500      * Well, it's a fragmented notice...allocate a hole list and
501      * initialize it to the full packet size.  Then insert the
502      * current fragment.
503      */
504     if (!(qptr->holelist = (struct _Z_Hole *)
505           malloc(sizeof(struct _Z_Hole))))
506         return (ENOMEM);
507     qptr->holelist->next = (struct _Z_Hole *) 0;
508     qptr->holelist->first = 0;
509     qptr->holelist->last = partof-1;
510     return (Z_AddNoticeToEntry(qptr, &notice, part));
511 }
512
513
514 /* Fragment management routines - compliments, more or less, of RFC815 */
515
516 Code_t Z_AddNoticeToEntry(qptr, notice, part)
517     struct _Z_InputQ *qptr;
518     ZNotice_t *notice;
519     int part;
520 {
521     int last, oldfirst, oldlast;
522     struct _Z_Hole *hole, *lasthole;
523     struct timeval tv;
524
525     /* Bounds check. */
526     if (part < 0 || notice->z_message_len < 0 || part > qptr->msg_len
527         || notice->z_message_len > qptr->msg_len - part)
528       return (ZERR_NONE);
529
530     /* Incorporate this notice's checked authentication. */
531     if (notice->z_checked_auth == ZAUTH_FAILED)
532         qptr->auth = ZAUTH_FAILED;
533     else if (notice->z_checked_auth == ZAUTH_NO && qptr->auth != ZAUTH_FAILED)
534         qptr->auth = ZAUTH_NO;
535
536     (void) gettimeofday(&tv, (struct timezone *)0);
537     qptr->timep = tv.tv_sec;
538     
539     last = part+notice->z_message_len-1;
540
541     hole = qptr->holelist;
542     lasthole = (struct _Z_Hole *) 0;
543
544     /* copy in the message body */
545     (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len);
546
547     /* Search for a hole that overlaps with the current fragment */
548     while (hole) {
549         if (part <= hole->last && last >= hole->first)
550             break;
551         lasthole = hole;
552         hole = hole->next;
553     }
554
555     /* If we found one, delete it and reconstruct a new hole */
556     if (hole) {
557         oldfirst = hole->first;
558         oldlast = hole->last;
559         if (lasthole)
560             lasthole->next = hole->next;
561         else
562             qptr->holelist = hole->next;
563         free((char *)hole);
564         /*
565          * Now create a new hole that is the original hole without the
566          * current fragment.
567          */
568         if (part > oldfirst) {
569             /* Search for the end of the hole list */
570             hole = qptr->holelist;
571             lasthole = (struct _Z_Hole *) 0;
572             while (hole) {
573                 lasthole = hole;
574                 hole = hole->next;
575             }
576             if (lasthole) {
577                 if (!(lasthole->next = (struct _Z_Hole *)
578                       malloc(sizeof(struct _Z_InputQ))))
579                     return (ENOMEM);
580                 hole = lasthole->next;
581             }
582             else {
583                 if (!(qptr->holelist = (struct _Z_Hole *)
584                       malloc(sizeof(struct _Z_InputQ))))
585                     return (ENOMEM);
586                 hole = qptr->holelist;
587             }
588             hole->next = NULL;
589             hole->first = oldfirst;
590             hole->last = part-1;
591         }
592         if (last < oldlast) {
593             /* Search for the end of the hole list */
594             hole = qptr->holelist;
595             lasthole = (struct _Z_Hole *) 0;
596             while (hole) {
597                 lasthole = hole;
598                 hole = hole->next;
599             }
600             if (lasthole) {
601                 if (!(lasthole->next = (struct _Z_Hole *)
602                       malloc(sizeof(struct _Z_InputQ))))
603                     return (ENOMEM);
604                 hole = lasthole->next;
605             }
606             else {
607                 if (!(qptr->holelist = (struct _Z_Hole *)
608                       malloc(sizeof(struct _Z_InputQ))))
609                     return (ENOMEM);
610                 hole = qptr->holelist;
611             }
612             hole->next = (struct _Z_Hole *) 0;
613             hole->first = last+1;
614             hole->last = oldlast;
615         }
616     }
617
618     if (!qptr->holelist) {
619         if (!qptr->complete)
620             __Q_CompleteLength++;
621         qptr->complete = 1;
622         qptr->timep = 0;                /* don't time out anymore */
623         qptr->packet_len = qptr->header_len+qptr->msg_len;
624         if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
625             return (ENOMEM);
626         (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
627         (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
628                        qptr->msg_len);
629     }
630     
631     return (ZERR_NONE);
632 }
633
634 void Z_gettimeofday(struct _ZTimeval *ztv, struct timezone *tz)
635 {
636         struct timeval tv;
637         (void) gettimeofday(&tv, tz); /* yeah, yeah, I know */
638         ztv->tv_sec=tv.tv_sec;
639         ztv->tv_usec=tv.tv_usec;
640 }
641
642 Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine)
643     ZNotice_t *notice;
644     char *buffer;
645     int buffer_len;
646     int *len;
647     Z_AuthProc cert_routine;
648 {
649     Code_t retval;
650     static char version[BUFSIZ]; /* default init should be all \0 */
651     struct sockaddr_in name;
652     int namelen = sizeof(name);
653
654     if (!notice->z_sender)
655         notice->z_sender = ZGetSender();
656
657     if (notice->z_port == 0) {
658         if (ZGetFD() < 0) {
659             retval = ZOpenPort((u_short *)0);
660             if (retval != ZERR_NONE)
661                 return (retval);
662         }
663         retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
664         if (retval != 0)
665             return (retval);
666         notice->z_port = name.sin_port;
667     }
668
669     notice->z_multinotice = "";
670     
671     (void) Z_gettimeofday(&notice->z_uid.tv, (struct timezone *)0);
672     notice->z_uid.tv.tv_sec = htonl((u_long) notice->z_uid.tv.tv_sec);
673     notice->z_uid.tv.tv_usec = htonl((u_long) notice->z_uid.tv.tv_usec);
674     
675     (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
676
677     notice->z_multiuid = notice->z_uid;
678
679     if (!version[0])
680             (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
681                            ZVERSIONMINOR);
682     notice->z_version = version;
683
684     return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
685 }
686
687 Code_t Z_NewFormatHeader(notice, buffer, buffer_len, len, cert_routine)
688     ZNotice_t *notice;
689     char *buffer;
690     int buffer_len;
691     int *len;
692     Z_AuthProc cert_routine;
693 {
694     Code_t retval;
695     static char version[BUFSIZ]; /* default init should be all \0 */
696     struct sockaddr_in name;
697     int namelen = sizeof(name);
698
699     if (!notice->z_sender)
700         notice->z_sender = ZGetSender();
701
702     if (notice->z_port == 0) {
703         if (ZGetFD() < 0) {
704             retval = ZOpenPort((u_short *)0);
705             if (retval != ZERR_NONE)
706                 return (retval);
707         }
708         retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
709         if (retval != 0)
710             return (retval);
711         notice->z_port = name.sin_port;
712     }
713
714     notice->z_multinotice = "";
715     
716     (void) gettimeofday(&notice->z_uid.tv, (struct timezone *)0);
717     notice->z_uid.tv.tv_sec = htonl((u_long) notice->z_uid.tv.tv_sec);
718     notice->z_uid.tv.tv_usec = htonl((u_long) notice->z_uid.tv.tv_usec);
719     
720     (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
721
722     notice->z_multiuid = notice->z_uid;
723
724     if (!version[0])
725             (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
726                            ZVERSIONMINOR);
727     notice->z_version = version;
728
729     return Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
730 }
731
732 Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
733     ZNotice_t *notice;
734     char *buffer;
735     int buffer_len;
736     int *len;
737     Z_AuthProc cert_routine;
738 {
739     if (!cert_routine) {
740         notice->z_auth = 0;
741         notice->z_authent_len = 0;
742         notice->z_ascii_authent = "";
743         notice->z_checksum = 0;
744         return (Z_FormatRawHeader(notice, buffer, buffer_len,
745                                   len, NULL, NULL));
746     }
747     
748     return ((*cert_routine)(notice, buffer, buffer_len, len));
749
750         
751 Code_t Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
752     ZNotice_t *notice;
753     char *buffer;
754     int buffer_len;
755     int *len;
756     Z_AuthProc cert_routine;
757 {
758     if (!cert_routine) {
759         notice->z_auth = 0;
760         notice->z_authent_len = 0;
761         notice->z_ascii_authent = "";
762         notice->z_checksum = 0;
763         return (Z_FormatRawHeader(notice, buffer, buffer_len,
764                                      len, NULL, NULL));
765     }
766     
767     return ((*cert_routine)(notice, buffer, buffer_len, len));
768
769         
770 Code_t Z_NewFormatRawHeader(notice, buffer, buffer_len, hdr_len,
771                          cksum_start, cksum_len, cstart, cend)
772     ZNotice_t *notice;
773     char *buffer;
774     int buffer_len;
775     int *hdr_len;
776     char **cksum_start;
777     int *cksum_len;
778     char **cstart, **cend;
779 {
780    return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len,
781                                  cksum_start, cksum_len, cstart, cend, 0));
782 }
783
784 Code_t Z_AsciiFormatRawHeader(notice, buffer, buffer_len, hdr_len,
785                               cksum_start, cksum_len, cstart, cend)
786     ZNotice_t *notice;
787     char *buffer;
788     int buffer_len;
789     int *hdr_len;
790     char **cksum_start;
791     int *cksum_len;
792     char **cstart, **cend;
793 {
794    return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len,
795                                  cksum_start, cksum_len, cstart, cend, 1));
796 }
797
798 Code_t Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, cksum_start,
799                               cksum_len, cstart, cend, cksumstyle)
800     ZNotice_t *notice;
801     char *buffer;
802     int buffer_len;
803     int *hdr_len;
804     char **cksum_start;
805     int *cksum_len;
806     char **cstart, **cend;
807     int cksumstyle;
808 {
809     static char version_nogalaxy[BUFSIZ]; /* default init should be all \0 */
810     char newrecip[BUFSIZ];
811     char *ptr, *end;
812     int i;
813
814     if (!notice->z_class)
815             notice->z_class = "";
816
817     if (!notice->z_class_inst)
818             notice->z_class_inst = "";
819
820     if (!notice->z_opcode)
821             notice->z_opcode = "";
822
823     if (!notice->z_recipient)
824             notice->z_recipient = "";
825
826     if (!notice->z_default_format)
827             notice->z_default_format = "";
828
829     ptr = buffer;
830     end = buffer+buffer_len;
831
832     if (cksum_start)
833         *cksum_start = ptr;
834
835     (void) sprintf(version_nogalaxy, "%s%d.%d", ZVERSIONHDR,
836                    ZVERSIONMAJOR, ZVERSIONMINOR);
837
838     notice->z_version = version_nogalaxy;
839
840     if (Z_AddField(&ptr, version_nogalaxy, end))
841         return (ZERR_HEADERLEN);
842
843     if (ZMakeAscii32(ptr, end-ptr,
844                      Z_NUMFIELDS + notice->z_num_other_fields)
845         == ZERR_FIELDLEN)
846         return (ZERR_HEADERLEN);
847     ptr += strlen(ptr)+1;
848
849     if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
850         return (ZERR_HEADERLEN);
851     ptr += strlen(ptr)+1;
852
853     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid, 
854                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
855         return (ZERR_HEADERLEN);
856     ptr += strlen(ptr)+1;
857
858     if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
859         return (ZERR_HEADERLEN);
860     ptr += strlen(ptr)+1;
861
862     if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
863         return (ZERR_HEADERLEN);
864     ptr += strlen(ptr)+1;
865
866     if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
867         return (ZERR_HEADERLEN);
868     ptr += strlen(ptr)+1;
869
870     if (Z_AddField(&ptr, notice->z_ascii_authent, end))
871         return (ZERR_HEADERLEN);
872     if (Z_AddField(&ptr, notice->z_class, end))
873         return (ZERR_HEADERLEN);
874     if (Z_AddField(&ptr, notice->z_class_inst, end))
875         return (ZERR_HEADERLEN);
876     if (Z_AddField(&ptr, notice->z_opcode, end))
877         return (ZERR_HEADERLEN);
878     if (Z_AddField(&ptr, notice->z_sender, end))
879         return (ZERR_HEADERLEN);
880     if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
881         if (Z_AddField(&ptr, notice->z_recipient, end))
882             return (ZERR_HEADERLEN);
883     }
884     else {
885         if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
886             sizeof(newrecip))
887             return (ZERR_HEADERLEN);
888         (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
889         if (Z_AddField(&ptr, newrecip, end))
890             return (ZERR_HEADERLEN);
891     }           
892     if (Z_AddField(&ptr, notice->z_default_format, end))
893         return (ZERR_HEADERLEN);
894
895     /* copy back the end pointer location for crypto checksum */
896     if (cstart)
897         *cstart = ptr;
898     if (cksumstyle == 1) {
899       if (Z_AddField(&ptr, notice->z_ascii_checksum, end))
900          return (ZERR_HEADERLEN);
901     } else {
902 #ifdef xZCODE_K4SUM
903     if (ZMakeZcode32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
904         return ZERR_HEADERLEN;
905 #else
906     if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
907         return (ZERR_HEADERLEN);
908 #endif
909     ptr += strlen(ptr)+1;
910     }
911     if (cend)
912         *cend = ptr;
913
914     if (Z_AddField(&ptr, notice->z_multinotice, end))
915         return (ZERR_HEADERLEN);
916
917     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid, 
918                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
919         return (ZERR_HEADERLEN);
920     ptr += strlen(ptr)+1;
921         
922     for (i=0;i<notice->z_num_other_fields;i++)
923         if (Z_AddField(&ptr, notice->z_other_fields[i], end))
924             return (ZERR_HEADERLEN);
925     
926     if (cksum_len)
927         *cksum_len = ptr-*cksum_start;
928
929     *hdr_len = ptr-buffer;
930
931 #if 0
932     {
933         printf("Z_FormatRawHeader output:\n");
934         for (i = 0; i < *hdr_len; i += 16) {
935             int i2;
936             printf("%03d:", i);
937             for (i2 = i; i2 < i+16 && i2 < *hdr_len; i2++)
938                 printf(" %02x", buffer[i2] & 0xff);
939             for (; i2 < i+16; i2++)
940                 printf("   ");
941             printf("  ");
942             for (i2 = i; i2 < i+16 && i2 < *hdr_len; i2++)
943                 printf("%c",
944                        ((buffer[i2] > 0 && buffer[i2] < 127 && isprint(buffer[i2]))
945                         ? buffer[i2]
946                         : '.'));
947             printf("\n");
948         }
949     }
950 #endif
951
952     return (ZERR_NONE);
953 }
954
955 Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend)
956     ZNotice_t *notice;
957     char *buffer;
958     int buffer_len;
959     int *len;
960     char **cstart, **cend;
961 {
962     char newrecip[BUFSIZ];
963     char *ptr, *end;
964     int i;
965
966     if (!notice->z_class)
967             notice->z_class = "";
968
969     if (!notice->z_class_inst)
970             notice->z_class_inst = "";
971
972     if (!notice->z_opcode)
973             notice->z_opcode = "";
974
975     if (!notice->z_recipient)
976             notice->z_recipient = "";
977
978     if (!notice->z_default_format)
979             notice->z_default_format = "";
980
981     ptr = buffer;
982     end = buffer+buffer_len;
983
984     if (buffer_len < strlen(notice->z_version)+1)
985         return (ZERR_HEADERLEN);
986
987     (void) strcpy(ptr, notice->z_version);
988     ptr += strlen(ptr)+1;
989
990     if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields)
991         == ZERR_FIELDLEN)
992         return (ZERR_HEADERLEN);
993     ptr += strlen(ptr)+1;
994
995     if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
996         return (ZERR_HEADERLEN);
997     ptr += strlen(ptr)+1;
998
999     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid, 
1000                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
1001         return (ZERR_HEADERLEN);
1002     ptr += strlen(ptr)+1;
1003
1004     if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
1005         return (ZERR_HEADERLEN);
1006     ptr += strlen(ptr)+1;
1007
1008     if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
1009         return (ZERR_HEADERLEN);
1010     ptr += strlen(ptr)+1;
1011
1012     if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
1013         return (ZERR_HEADERLEN);
1014     ptr += strlen(ptr)+1;
1015
1016     if (Z_AddField(&ptr, notice->z_ascii_authent, end))
1017         return (ZERR_HEADERLEN);
1018     if (Z_AddField(&ptr, notice->z_class, end))
1019         return (ZERR_HEADERLEN);
1020     if (Z_AddField(&ptr, notice->z_class_inst, end))
1021         return (ZERR_HEADERLEN);
1022     if (Z_AddField(&ptr, notice->z_opcode, end))
1023         return (ZERR_HEADERLEN);
1024     if (Z_AddField(&ptr, notice->z_sender, end))
1025         return (ZERR_HEADERLEN);
1026     if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
1027         if (Z_AddField(&ptr, notice->z_recipient, end))
1028             return (ZERR_HEADERLEN);
1029     }
1030     else {
1031         if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
1032             sizeof(newrecip))
1033             return (ZERR_HEADERLEN);
1034         (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
1035         if (Z_AddField(&ptr, newrecip, end))
1036             return (ZERR_HEADERLEN);
1037     }           
1038     if (Z_AddField(&ptr, notice->z_default_format, end))
1039         return (ZERR_HEADERLEN);
1040
1041     /* copy back the end pointer location for crypto checksum */
1042     if (cstart)
1043         *cstart = ptr;
1044     if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
1045         return (ZERR_HEADERLEN);
1046     ptr += strlen(ptr)+1;
1047     if (cend)
1048         *cend = ptr;
1049
1050     if (Z_AddField(&ptr, notice->z_multinotice, end))
1051         return (ZERR_HEADERLEN);
1052
1053     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid, 
1054                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
1055         return (ZERR_HEADERLEN);
1056     ptr += strlen(ptr)+1;
1057         
1058     for (i=0;i<notice->z_num_other_fields;i++)
1059         if (Z_AddField(&ptr, notice->z_other_fields[i], end))
1060             return (ZERR_HEADERLEN);
1061     
1062     *len = ptr-buffer;
1063         
1064     return (ZERR_NONE);
1065 }
1066
1067 static int
1068 Z_AddField(ptr, field, end)
1069     char **ptr, *field, *end;
1070 {
1071     register int len;
1072
1073     len = field ? strlen (field) + 1 : 1;
1074
1075     if (*ptr+len > end)
1076         return 1;
1077     if (field)
1078         (void) strcpy(*ptr, field);
1079     else
1080         **ptr = '\0';
1081     *ptr += len;
1082
1083     return 0;
1084 }
1085
1086 struct _Z_InputQ *Z_GetFirstComplete()
1087 {
1088     struct _Z_InputQ *qptr;
1089
1090     qptr = __Q_Head;
1091
1092     while (qptr) {
1093         if (qptr->complete)
1094             return (qptr);
1095         qptr = qptr->next;
1096     }
1097
1098     return ((struct _Z_InputQ *)0);
1099 }
1100
1101 struct _Z_InputQ *Z_GetNextComplete(qptr)
1102     struct _Z_InputQ *qptr;
1103 {
1104     qptr = qptr->next;
1105     while (qptr) {
1106         if (qptr->complete)
1107             return (qptr);
1108         qptr = qptr->next;
1109     }
1110
1111     return ((struct _Z_InputQ *)0);
1112 }
1113
1114 void Z_RemQueue(qptr)
1115     struct _Z_InputQ *qptr;
1116 {
1117     struct _Z_Hole *hole, *nexthole;
1118     
1119     if (qptr->complete)
1120         __Q_CompleteLength--;
1121
1122     __Q_Size -= qptr->msg_len;
1123     
1124     if (qptr->header)
1125         free(qptr->header);
1126     if (qptr->msg)
1127         free(qptr->msg);
1128     if (qptr->packet)
1129         free(qptr->packet);
1130     
1131     hole = qptr->holelist;
1132     while (hole) {
1133         nexthole = hole->next;
1134         free((char *)hole);
1135         hole = nexthole;
1136     }
1137     
1138     if (qptr == __Q_Head && __Q_Head == __Q_Tail) {
1139         free ((char *)qptr);
1140         __Q_Head = (struct _Z_InputQ *)0;
1141         __Q_Tail = (struct _Z_InputQ *)0;
1142         return;
1143     }
1144     
1145     if (qptr == __Q_Head) {
1146         __Q_Head = qptr->next;
1147         __Q_Head->prev = (struct _Z_InputQ *)0;
1148         free ((char *)qptr);
1149         return;
1150     } 
1151     if (qptr == __Q_Tail) {
1152         __Q_Tail = qptr->prev;
1153         __Q_Tail->next = (struct _Z_InputQ *)0;
1154         free ((char *)qptr);
1155         return;
1156     }
1157     qptr->prev->next = qptr->next;
1158     qptr->next->prev = qptr->prev;
1159     free ((char *)qptr);
1160     return;
1161 }
1162
1163 Code_t Z_SendFragmentedNotice(notice, len, cert_func, send_func)
1164     ZNotice_t *notice;
1165     int len;
1166     Z_AuthProc cert_func;
1167     Z_SendProc send_func;
1168 {
1169     ZNotice_t partnotice;
1170     ZPacket_t buffer;
1171     char multi[64];
1172     int offset, hdrsize, fragsize, ret_len, message_len, waitforack;
1173     Code_t retval;
1174     
1175     hdrsize = len-notice->z_message_len;
1176     fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE;
1177     
1178     offset = 0;
1179
1180     waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED)
1181                   && !__Zephyr_server);
1182     
1183     partnotice = *notice;
1184
1185     while (offset < notice->z_message_len || !notice->z_message_len) {
1186         (void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
1187         partnotice.z_multinotice = multi;
1188         if (offset > 0) {
1189             (void) Z_gettimeofday(&partnotice.z_uid.tv,
1190                                   (struct timezone *)0);
1191             partnotice.z_uid.tv.tv_sec =
1192                 htonl((u_long) partnotice.z_uid.tv.tv_sec);
1193             partnotice.z_uid.tv.tv_usec =
1194                 htonl((u_long) partnotice.z_uid.tv.tv_usec);
1195             (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, 
1196                           sizeof(__My_addr));
1197         }
1198         message_len = min(notice->z_message_len-offset, fragsize);
1199         partnotice.z_message = notice->z_message+offset;
1200         partnotice.z_message_len = message_len;
1201         if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN,
1202                                          &ret_len, cert_func)) != ZERR_NONE) {
1203             return (retval);
1204         }
1205         memcpy(buffer + ret_len, partnotice.z_message, message_len);
1206         if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len,
1207                                    waitforack)) != ZERR_NONE) {
1208             return (retval);
1209         }
1210         offset += fragsize;
1211         if (!notice->z_message_len)
1212             break;
1213     }
1214
1215     return (ZERR_NONE);
1216 }
1217
1218 /*ARGSUSED*/
1219 Code_t Z_XmitFragment(notice, buf, len, wait)
1220 ZNotice_t *notice;
1221 char *buf;
1222 int len;
1223 int wait;
1224 {
1225         return(ZSendPacket(buf, len, wait));
1226 }
1227
1228 #ifdef Z_DEBUG
1229 /* For debugging printing */
1230 const char *const ZNoticeKinds[] = {
1231     "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
1232     "CLIENTACK", "STAT"
1233 };
1234 #endif
1235
1236 #ifdef Z_DEBUG
1237
1238 #undef Z_debug
1239 #ifdef HAVE_STDARG_H
1240 void Z_debug (const char *format, ...)
1241 {
1242     va_list pvar;
1243     if (!__Z_debug_print)
1244       return;
1245     va_start (pvar, format);
1246     (*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
1247     va_end (pvar);
1248 }
1249 #else /* stdarg */
1250 void Z_debug (va_alist) va_dcl
1251 {
1252     va_list pvar;
1253     char *format;
1254     if (!__Z_debug_print)
1255       return;
1256     va_start (pvar);
1257     format = va_arg (pvar, char *);
1258     (*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
1259     va_end (pvar);
1260 }
1261 #endif
1262
1263 void Z_debug_stderr (format, args, closure)
1264      const char *format;
1265      va_list args;
1266      void *closure;
1267 {
1268 #ifdef HAVE_VPRINTF
1269     vfprintf (stderr, format, args);
1270 #else
1271     _doprnt (format, args, stderr);
1272 #endif
1273     putc ('\n', stderr);
1274 }
1275
1276 #undef ZGetFD
1277 int ZGetFD () { return __Zephyr_fd; }
1278
1279 #undef ZQLength
1280 int ZQLength () { return __Q_CompleteLength; }
1281
1282 #undef ZGetDestAddr
1283 struct sockaddr_in ZGetDestAddr () { return __HM_addr; }
1284
1285 #undef ZGetRealm
1286 Zconst char * ZGetRealm () { return __Zephyr_realm; }
1287
1288 #undef ZSetDebug
1289 void ZSetDebug(proc, arg)
1290     void (*proc) __P((const char *, va_list, void *));
1291     char *arg;
1292 {
1293     __Z_debug_print = proc;
1294     __Z_debug_print_closure = arg;
1295 }
1296 #endif /* Z_DEBUG */
1297
1298 #ifdef HAVE_KRB5
1299 Code_t Z_Checksum(krb5_data *cksumbuf, krb5_keyblock *keyblock, krb5_cksumtype cksumtype, char **asn1_data, int *asn1_len) {
1300     krb5_error_code result;
1301     char *data;
1302     int len;
1303 #if HAVE_KRB5_C_MAKE_CHECKSUM
1304     krb5_checksum checksum;
1305 #else
1306     Checksum checksum;
1307     krb5_crypto cryptctx;
1308 #endif
1309     
1310 #if HAVE_KRB5_C_MAKE_CHECKSUM
1311     /* Create the checksum -- MIT crypto API */
1312     result = krb5_c_make_checksum(Z_krb5_ctx, cksumtype,
1313                                   keyblock, Z_KEYUSAGE_CLT_CKSUM,
1314                                   cksumbuf, &checksum);
1315     if (result)
1316         return result;
1317     /* HOLDING: checksum */
1318
1319     data = checksum.contents;
1320     len = checksum.length;
1321 #else
1322     /* Create the checksum -- heimdal crypto API */
1323     result = krb5_crypto_init(Z_krb5_ctx, keyblock, enctype, &cryptctx);
1324     if (result)
1325         return result;
1326
1327     /* HOLDING: cryptctx */
1328     result = krb5_create_checksum(Z_krb5_ctx, cryptctx,
1329                                   Z_KEYUSAGE_CLT_CKSUM, cksumtype,
1330                                   cksumbuf->data, cksumbuf->length,
1331                                   &checksum);
1332     krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
1333     if (result)
1334         return result;
1335
1336     len = checksum.checksum.length;
1337     data = checksum.checksum.data;
1338     /* HOLDING: checksum */
1339 #endif
1340
1341     *asn1_data = malloc(len);
1342     if (*asn1_data == NULL)
1343         return errno;
1344     memcpy(*asn1_data, data, len);
1345     *asn1_len = len;
1346
1347 #if HAVE_KRB5_C_MAKE_CHECKSUM
1348     krb5_free_checksum_contents(Z_krb5_ctx, &checksum);
1349 #else
1350     free_Checksum(&checksum);
1351 #endif
1352
1353     return 0;
1354 }
1355
1356 Code_t
1357 Z_ExtractEncCksum(krb5_keyblock *keyblock, krb5_enctype *enctype, krb5_cksumtype *cksumtype) {
1358 #if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
1359     *enctype  = keyblock->enctype; 
1360     return Z_krb5_lookup_cksumtype(*enctype, cksumtype); 
1361 #else 
1362     unsigned int len; 
1363     ENCTYPE *val; 
1364     int i = 0; 
1365  
1366     result = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype, 
1367                                       &len, &val); 
1368     if (result)
1369       return result;
1370     
1371     do { 
1372       if (i == len) break;
1373       result = Z_krb5_lookup_cksumtype(val[i], cksumtype); 
1374       i++;
1375     } while (result != 0); 
1376     
1377     if (result)
1378       return result;
1379
1380     *enctype = val[i-1]; 
1381 #endif
1382     return 0;
1383 }
1384 #endif
1385
1386 #ifdef HAVE_KRB5
1387 /* returns 0 if invalid or losing, 1 if valid, *sigh* */
1388 int
1389 Z_krb5_verify_cksum(krb5_keyblock *keyblock, krb5_data *cksumbuf, krb5_cksumtype cksumtype, char *asn1_data, int asn1_len) {
1390     krb5_error_code result;
1391 #if HAVE_KRB5_C_MAKE_CHECKSUM
1392     krb5_checksum checksum;
1393     krb5_boolean valid;
1394 #else
1395     krb5_crypto cryptctx;
1396     Checksum checksum;
1397     size_t xlen;
1398 #endif
1399
1400     memset(&checksum, 0, sizeof(checksum));
1401 #if HAVE_KRB5_C_MAKE_CHECKSUM
1402     /* Verify the checksum -- MIT crypto API */
1403     checksum.length = asn1_len;
1404     checksum.contents = asn1_data;
1405     checksum.checksum_type = cksumtype;
1406     result = krb5_c_verify_checksum(Z_krb5_ctx,
1407                                     keyblock, Z_KEYUSAGE_SRV_CKSUM,
1408                                     cksumbuf, &checksum, &valid);
1409     if (!result && valid)
1410         return 1;
1411     else
1412         return 0;
1413 #else
1414     checksum.checksum.length = asn1_len;
1415     checksum.checksum.data = asn1_data;
1416     checksum.cksumtype = cksumtype;
1417
1418     result = krb5_crypto_init(Z_krb5_ctx, keyblock, enctype, &cryptctx);
1419     if (result)
1420         return result;
1421     
1422     /* HOLDING: cryptctx */
1423     result = krb5_verify_checksum(Z_krb5_ctx, cryptctx,
1424                                   Z_KEYUSAGE_SRV_CKSUM,
1425                                   cksumbuf.data, cksumbuf.length,
1426                                   &checksum);
1427     krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
1428     if (result)
1429         return 0;
1430     else
1431         return 1;
1432 #endif
1433 }
1434 #endif