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