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