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