]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/Zinternal.c
r4255@bucket (orig r245): kcr | 2008-01-20 14:50:23 -0500
[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$
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$";
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     int from_len, packet_len, zvlen, part, partof;
284     char *slash;
285     Code_t retval;
286     fd_set fds;
287     struct timeval tv;
288
289     if (ZGetFD() < 0)
290         return (ZERR_NOPORT);
291         
292     FD_ZERO(&fds);
293     FD_SET(ZGetFD(), &fds);
294     tv.tv_sec = 60;
295     tv.tv_usec = 0;
296
297     if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0)
298       return (errno);
299     if (!FD_ISSET(ZGetFD(), &fds))
300       return ETIMEDOUT;
301
302     from_len = sizeof(struct sockaddr_in);
303
304     packet_len = recvfrom(ZGetFD(), packet, sizeof(packet), 0, 
305                           (struct sockaddr *)&from, &from_len);
306
307     if (packet_len < 0)
308         return (errno);
309
310     if (!packet_len)
311         return (ZERR_EOF);
312
313     /* Ignore obviously non-Zephyr packets. */
314     zvlen = sizeof(ZVERSIONHDR) - 1;
315     if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) {
316         Z_discarded_packets++;
317         return (ZERR_NONE);
318     }   
319
320     /* Parse the notice */
321     if ((retval = ZParseNotice(packet, packet_len, &notice)) != ZERR_NONE)
322         return (retval);
323
324     /*
325      * If we're not a server and the notice is of an appropriate kind,
326      * send back a CLIENTACK to whoever sent it to say we got it.
327      */
328     if (!__Zephyr_server) {
329         if (notice.z_kind != HMACK && notice.z_kind != SERVACK &&
330             notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) {
331             ZNotice_t tmpnotice;
332             ZPacket_t pkt;
333             int len;
334
335             tmpnotice = notice;
336             tmpnotice.z_kind = CLIENTACK;
337             tmpnotice.z_message_len = 0;
338             olddest = __HM_addr;
339             __HM_addr = from;
340             if ((retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len))
341                 != ZERR_NONE)
342                 return(retval);
343             if ((retval = ZSendPacket(pkt, len, 0)) != ZERR_NONE)
344                 return (retval);
345             __HM_addr = olddest;
346         }
347         if (find_or_insert_uid(&notice.z_uid, notice.z_kind))
348             return(ZERR_NONE);
349
350         /* Check authentication on the notice. */
351         notice.z_checked_auth = ZCheckAuthentication(&notice, &from);
352     }
353
354
355     /*
356      * Parse apart the z_multinotice field - if the field is blank for
357      * some reason, assume this packet stands by itself.
358      */
359     slash = strchr(notice.z_multinotice, '/');
360     if (slash) {
361         part = atoi(notice.z_multinotice);
362         partof = atoi(slash+1);
363         if (part > partof || partof == 0) {
364             part = 0;
365             partof = notice.z_message_len;
366         }
367     }
368     else {
369         part = 0;
370         partof = notice.z_message_len;
371     }
372
373     /* Too big a packet...just ignore it! */
374     if (partof > Z_MAXNOTICESIZE)
375         return (ZERR_NONE);
376
377     /*
378      * If we aren't a server and we can find a notice in the queue
379      * with the same multiuid field, insert the current fragment as
380      * appropriate.
381      */
382     switch (notice.z_kind) {
383     case SERVACK:
384     case SERVNAK:
385         /* The SERVACK and SERVNAK replies shouldn't be reassembled
386            (they have no parts).  Instead, we should hold on to the reply
387            ONLY if it's the first part of a fragmented message, i.e.
388            multi_uid == uid.  This allows programs to wait for the uid
389            of the first packet, and get a response when that notice
390            arrives.  Acknowledgements of the other fragments are discarded
391            (XXX we assume here that they all carry the same information
392            regarding failure/success)
393          */
394         if (!__Zephyr_server &&
395             !ZCompareUID(&notice.z_multiuid, &notice.z_uid))
396             /* they're not the same... throw away this packet. */
397             return(ZERR_NONE);
398         /* fall thru & process it */
399     default:
400         /* for HMACK types, we assume no packet loss (local loopback
401            connections).  The other types can be fragmented and MUST
402            run through this code. */
403         if (!__Zephyr_server && (qptr = Z_SearchQueue(&notice.z_multiuid,
404                                                       notice.z_kind))) {
405             /*
406              * If this is the first fragment, and we haven't already
407              * gotten a first fragment, grab the header from it.
408              */
409             if (part == 0 && !qptr->header) {
410                 qptr->header_len = packet_len-notice.z_message_len;
411                 qptr->header = (char *) malloc((unsigned) qptr->header_len);
412                 if (!qptr->header)
413                     return (ENOMEM);
414                 (void) memcpy(qptr->header, packet, qptr->header_len);
415             }
416             return (Z_AddNoticeToEntry(qptr, &notice, part));
417         }
418     }
419
420     /*
421      * We'll have to create a new entry...make sure the queue isn't
422      * going to get too big.
423      */
424     if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE)
425         return (ZERR_NONE);
426
427     /*
428      * This is a notice we haven't heard of, so create a new queue
429      * entry for it and zero it out.
430      */
431     qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ));
432     if (!qptr)
433         return (ENOMEM);
434     (void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ));
435
436     /* Insert the entry at the end of the queue */
437     qptr->next = NULL;
438     qptr->prev = __Q_Tail;
439     if (__Q_Tail)
440         __Q_Tail->next = qptr;
441     __Q_Tail = qptr;
442
443     if (!__Q_Head)
444         __Q_Head = qptr;
445
446     
447     /* Copy the from field, multiuid, kind, and checked authentication. */
448     qptr->from = from;
449     qptr->uid = notice.z_multiuid;
450     qptr->kind = notice.z_kind;
451     qptr->auth = notice.z_checked_auth;
452     
453     /*
454      * If this is the first part of the notice, we take the header
455      * from it.  We only take it if this is the first fragment so that
456      * the Unique ID's will be predictable.
457      *
458      * If a Zephyr Server, we always take the header.
459      */
460     if (__Zephyr_server || part == 0) {
461         qptr->header_len = packet_len-notice.z_message_len;
462         qptr->header = (char *) malloc((unsigned) qptr->header_len);
463         if (!qptr->header)
464             return ENOMEM;
465         (void) memcpy(qptr->header, packet, qptr->header_len);
466     }
467
468     /*
469      * If this is not a fragmented notice, then don't bother with a
470      * hole list.
471      * If we are a Zephyr server, all notices are treated as complete.
472      */
473     if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) {
474         __Q_CompleteLength++;
475         qptr->holelist = (struct _Z_Hole *) 0;
476         qptr->complete = 1;
477         /* allocate a msg buf for this piece */
478         if (notice.z_message_len == 0)
479             qptr->msg = 0;
480         else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len)))
481             return(ENOMEM);
482         else
483             (void) memcpy(qptr->msg, notice.z_message, notice.z_message_len);
484         qptr->msg_len = notice.z_message_len;
485         __Q_Size += notice.z_message_len;
486         qptr->packet_len = qptr->header_len+qptr->msg_len;
487         if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
488             return (ENOMEM);
489         (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
490         if(qptr->msg)
491             (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
492                            qptr->msg_len);
493         return (ZERR_NONE);
494     }
495
496     /*
497      * We know how long the message is going to be (this is better
498      * than IP fragmentation...), so go ahead and allocate it all.
499      */
500     if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof)
501         return (ENOMEM);
502     qptr->msg_len = partof;
503     __Q_Size += partof;
504
505     /*
506      * Well, it's a fragmented notice...allocate a hole list and
507      * initialize it to the full packet size.  Then insert the
508      * current fragment.
509      */
510     if (!(qptr->holelist = (struct _Z_Hole *)
511           malloc(sizeof(struct _Z_Hole))))
512         return (ENOMEM);
513     qptr->holelist->next = (struct _Z_Hole *) 0;
514     qptr->holelist->first = 0;
515     qptr->holelist->last = partof-1;
516     return (Z_AddNoticeToEntry(qptr, &notice, part));
517 }
518
519
520 /* Fragment management routines - compliments, more or less, of RFC815 */
521
522 Code_t
523 Z_AddNoticeToEntry(struct _Z_InputQ *qptr,
524                    ZNotice_t *notice,
525                    int part)
526 {
527     int last, oldfirst, oldlast;
528     struct _Z_Hole *hole, *lasthole;
529     struct timeval tv;
530
531     /* Bounds check. */
532     if (part < 0 || notice->z_message_len < 0 || part > qptr->msg_len
533         || notice->z_message_len > qptr->msg_len - part)
534       return (ZERR_NONE);
535
536     /* Incorporate this notice's checked authentication. */
537     if (notice->z_checked_auth == ZAUTH_FAILED)
538         qptr->auth = ZAUTH_FAILED;
539     else if (notice->z_checked_auth == ZAUTH_NO && qptr->auth != ZAUTH_FAILED)
540         qptr->auth = ZAUTH_NO;
541
542     (void) gettimeofday(&tv, (struct timezone *)0);
543     qptr->timep = tv.tv_sec;
544     
545     last = part+notice->z_message_len-1;
546
547     hole = qptr->holelist;
548     lasthole = (struct _Z_Hole *) 0;
549
550     /* copy in the message body */
551     (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len);
552
553     /* Search for a hole that overlaps with the current fragment */
554     while (hole) {
555         if (part <= hole->last && last >= hole->first)
556             break;
557         lasthole = hole;
558         hole = hole->next;
559     }
560
561     /* If we found one, delete it and reconstruct a new hole */
562     if (hole) {
563         oldfirst = hole->first;
564         oldlast = hole->last;
565         if (lasthole)
566             lasthole->next = hole->next;
567         else
568             qptr->holelist = hole->next;
569         free((char *)hole);
570         /*
571          * Now create a new hole that is the original hole without the
572          * current fragment.
573          */
574         if (part > oldfirst) {
575             /* Search for the end of the hole list */
576             hole = qptr->holelist;
577             lasthole = (struct _Z_Hole *) 0;
578             while (hole) {
579                 lasthole = hole;
580                 hole = hole->next;
581             }
582             if (lasthole) {
583                 if (!(lasthole->next = (struct _Z_Hole *)
584                       malloc(sizeof(struct _Z_InputQ))))
585                     return (ENOMEM);
586                 hole = lasthole->next;
587             }
588             else {
589                 if (!(qptr->holelist = (struct _Z_Hole *)
590                       malloc(sizeof(struct _Z_InputQ))))
591                     return (ENOMEM);
592                 hole = qptr->holelist;
593             }
594             hole->next = NULL;
595             hole->first = oldfirst;
596             hole->last = part-1;
597         }
598         if (last < oldlast) {
599             /* Search for the end of the hole list */
600             hole = qptr->holelist;
601             lasthole = (struct _Z_Hole *) 0;
602             while (hole) {
603                 lasthole = hole;
604                 hole = hole->next;
605             }
606             if (lasthole) {
607                 if (!(lasthole->next = (struct _Z_Hole *)
608                       malloc(sizeof(struct _Z_InputQ))))
609                     return (ENOMEM);
610                 hole = lasthole->next;
611             }
612             else {
613                 if (!(qptr->holelist = (struct _Z_Hole *)
614                       malloc(sizeof(struct _Z_InputQ))))
615                     return (ENOMEM);
616                 hole = qptr->holelist;
617             }
618             hole->next = (struct _Z_Hole *) 0;
619             hole->first = last+1;
620             hole->last = oldlast;
621         }
622     }
623
624     if (!qptr->holelist) {
625         if (!qptr->complete)
626             __Q_CompleteLength++;
627         qptr->complete = 1;
628         qptr->timep = 0;                /* don't time out anymore */
629         qptr->packet_len = qptr->header_len+qptr->msg_len;
630         if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
631             return (ENOMEM);
632         (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
633         (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
634                        qptr->msg_len);
635     }
636     
637     return (ZERR_NONE);
638 }
639
640 void
641 Z_gettimeofday(struct _ZTimeval *ztv,
642                struct timezone *tz)
643 {
644         struct timeval tv;
645         (void) gettimeofday(&tv, tz); /* yeah, yeah, I know */
646         ztv->tv_sec=tv.tv_sec;
647         ztv->tv_usec=tv.tv_usec;
648 }
649
650 Code_t
651 Z_FormatHeader(ZNotice_t *notice,
652                char *buffer,
653                int buffer_len,
654                int *len,
655                Z_AuthProc cert_routine)
656 {
657     Code_t retval;
658     static char version[BUFSIZ]; /* default init should be all \0 */
659     struct sockaddr_in name;
660     int namelen = sizeof(name);
661
662     if (!notice->z_sender)
663         notice->z_sender = ZGetSender();
664
665     if (notice->z_port == 0) {
666         if (ZGetFD() < 0) {
667             retval = ZOpenPort((u_short *)0);
668             if (retval != ZERR_NONE)
669                 return (retval);
670         }
671         retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
672         if (retval != 0)
673             return (retval);
674         notice->z_port = name.sin_port;
675     }
676
677     notice->z_multinotice = "";
678     
679     (void) Z_gettimeofday(&notice->z_uid.tv, (struct timezone *)0);
680     notice->z_uid.tv.tv_sec = htonl((u_long) notice->z_uid.tv.tv_sec);
681     notice->z_uid.tv.tv_usec = htonl((u_long) notice->z_uid.tv.tv_usec);
682     
683     (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
684
685     notice->z_multiuid = notice->z_uid;
686
687     if (!version[0])
688             (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
689                            ZVERSIONMINOR);
690     notice->z_version = version;
691
692     return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
693 }
694
695 Code_t
696 Z_NewFormatHeader(ZNotice_t *notice,
697                   char *buffer,
698                   int buffer_len,
699                   int *len,
700                   Z_AuthProc cert_routine)
701 {
702     Code_t retval;
703     static char version[BUFSIZ]; /* default init should be all \0 */
704     struct sockaddr_in name;
705     struct timeval tv;
706     int namelen = sizeof(name);
707
708     if (!notice->z_sender)
709         notice->z_sender = ZGetSender();
710
711     if (notice->z_port == 0) {
712         if (ZGetFD() < 0) {
713             retval = ZOpenPort((u_short *)0);
714             if (retval != ZERR_NONE)
715                 return (retval);
716         }
717         retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
718         if (retval != 0)
719             return (retval);
720         notice->z_port = name.sin_port;
721     }
722
723     notice->z_multinotice = "";
724     
725     (void) gettimeofday(&tv, (struct timezone *)0);
726     notice->z_uid.tv.tv_sec = htonl((u_long) tv.tv_sec);
727     notice->z_uid.tv.tv_usec = htonl((u_long) tv.tv_usec);
728     
729     (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
730
731     notice->z_multiuid = notice->z_uid;
732
733     if (!version[0])
734             (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
735                            ZVERSIONMINOR);
736     notice->z_version = version;
737
738     return Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
739 }
740
741 Code_t
742 Z_FormatAuthHeader(ZNotice_t *notice,
743                    char *buffer,
744                    int buffer_len,
745                    int *len,
746                    Z_AuthProc cert_routine)
747 {
748     if (!cert_routine) {
749         notice->z_auth = 0;
750         notice->z_authent_len = 0;
751         notice->z_ascii_authent = "";
752         notice->z_checksum = 0;
753         return (Z_FormatRawHeader(notice, buffer, buffer_len,
754                                   len, NULL, NULL));
755     }
756     
757     return ((*cert_routine)(notice, buffer, buffer_len, len));
758 }
759
760 Code_t
761 Z_NewFormatAuthHeader(ZNotice_t *notice,
762                       char *buffer,
763                       int buffer_len,
764                       int *len,
765                       Z_AuthProc cert_routine)
766 {
767     if (!cert_routine) {
768         notice->z_auth = 0;
769         notice->z_authent_len = 0;
770         notice->z_ascii_authent = "";
771         notice->z_checksum = 0;
772         return (Z_FormatRawHeader(notice, buffer, buffer_len,
773                                   len, NULL, NULL));
774     }
775     
776     return ((*cert_routine)(notice, buffer, buffer_len, len));
777
778         
779 Code_t
780 Z_NewFormatRawHeader(ZNotice_t *notice,
781                      char *buffer,
782                      int buffer_len,
783                      int *hdr_len,
784                      char **cksum_start,
785                      int *cksum_len,
786                      char **cstart,
787                      char **cend)
788 {
789    return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len,
790                                  cksum_start, cksum_len, cstart, cend, 0));
791 }
792
793 Code_t
794 Z_AsciiFormatRawHeader(ZNotice_t *notice,
795                        char *buffer,
796                        int buffer_len,
797                        int *hdr_len,
798                        char **cksum_start,
799                        int *cksum_len,
800                        char **cstart,
801                        char **cend)
802 {
803    return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len,
804                                  cksum_start, cksum_len, cstart, cend, 1));
805 }
806
807 static Code_t
808 Z_ZcodeFormatRawHeader(ZNotice_t *notice,
809                        char *buffer,
810                        int buffer_len,
811                        int *hdr_len,
812                        char **cksum_start,
813                        int *cksum_len,
814                        char **cstart,
815                        char **cend,
816                        int cksumstyle)
817 {
818     static char version_nogalaxy[BUFSIZ]; /* default init should be all \0 */
819     char newrecip[BUFSIZ];
820     char *ptr, *end;
821     int i;
822
823     if (!notice->z_class)
824             notice->z_class = "";
825
826     if (!notice->z_class_inst)
827             notice->z_class_inst = "";
828
829     if (!notice->z_opcode)
830             notice->z_opcode = "";
831
832     if (!notice->z_recipient)
833             notice->z_recipient = "";
834
835     if (!notice->z_default_format)
836             notice->z_default_format = "";
837
838     ptr = buffer;
839     end = buffer+buffer_len;
840
841     if (cksum_start)
842         *cksum_start = ptr;
843
844     (void) sprintf(version_nogalaxy, "%s%d.%d", ZVERSIONHDR,
845                    ZVERSIONMAJOR, ZVERSIONMINOR);
846
847     notice->z_version = version_nogalaxy;
848
849     if (Z_AddField(&ptr, version_nogalaxy, end))
850         return (ZERR_HEADERLEN);
851
852     if (ZMakeAscii32(ptr, end-ptr,
853                      Z_NUMFIELDS + notice->z_num_other_fields)
854         == ZERR_FIELDLEN)
855         return (ZERR_HEADERLEN);
856     ptr += strlen(ptr)+1;
857
858     if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
859         return (ZERR_HEADERLEN);
860     ptr += strlen(ptr)+1;
861
862     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid, 
863                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
864         return (ZERR_HEADERLEN);
865     ptr += strlen(ptr)+1;
866
867     if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
868         return (ZERR_HEADERLEN);
869     ptr += strlen(ptr)+1;
870
871     if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
872         return (ZERR_HEADERLEN);
873     ptr += strlen(ptr)+1;
874
875     if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
876         return (ZERR_HEADERLEN);
877     ptr += strlen(ptr)+1;
878
879     if (Z_AddField(&ptr, notice->z_ascii_authent, end))
880         return (ZERR_HEADERLEN);
881     if (Z_AddField(&ptr, notice->z_class, end))
882         return (ZERR_HEADERLEN);
883     if (Z_AddField(&ptr, notice->z_class_inst, end))
884         return (ZERR_HEADERLEN);
885     if (Z_AddField(&ptr, notice->z_opcode, end))
886         return (ZERR_HEADERLEN);
887     if (Z_AddField(&ptr, notice->z_sender, end))
888         return (ZERR_HEADERLEN);
889     if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
890         if (Z_AddField(&ptr, notice->z_recipient, end))
891             return (ZERR_HEADERLEN);
892     }
893     else {
894         if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
895             sizeof(newrecip))
896             return (ZERR_HEADERLEN);
897         (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
898         if (Z_AddField(&ptr, newrecip, end))
899             return (ZERR_HEADERLEN);
900     }           
901     if (Z_AddField(&ptr, notice->z_default_format, end))
902         return (ZERR_HEADERLEN);
903
904     /* copy back the end pointer location for crypto checksum */
905     if (cstart)
906         *cstart = ptr;
907     if (cksumstyle == 1) {
908       if (Z_AddField(&ptr, notice->z_ascii_checksum, end))
909          return (ZERR_HEADERLEN);
910     } else {
911 #ifdef xZCODE_K4SUM
912     if (ZMakeZcode32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
913         return ZERR_HEADERLEN;
914 #else
915     if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
916         return (ZERR_HEADERLEN);
917 #endif
918     ptr += strlen(ptr)+1;
919     }
920     if (cend)
921         *cend = ptr;
922
923     if (Z_AddField(&ptr, notice->z_multinotice, end))
924         return (ZERR_HEADERLEN);
925
926     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid, 
927                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
928         return (ZERR_HEADERLEN);
929     ptr += strlen(ptr)+1;
930         
931     for (i=0;i<notice->z_num_other_fields;i++)
932         if (Z_AddField(&ptr, notice->z_other_fields[i], end))
933             return (ZERR_HEADERLEN);
934     
935     if (cksum_len)
936         *cksum_len = ptr-*cksum_start;
937
938     *hdr_len = ptr-buffer;
939
940     return (ZERR_NONE);
941 }
942
943 Code_t
944 Z_FormatRawHeader(ZNotice_t *notice,
945                   char *buffer,
946                   int buffer_len,
947                   int *len,
948                   char **cstart,
949                   char **cend)
950 {
951     char newrecip[BUFSIZ];
952     char *ptr, *end;
953     int i;
954
955     if (!notice->z_class)
956             notice->z_class = "";
957
958     if (!notice->z_class_inst)
959             notice->z_class_inst = "";
960
961     if (!notice->z_opcode)
962             notice->z_opcode = "";
963
964     if (!notice->z_recipient)
965             notice->z_recipient = "";
966
967     if (!notice->z_default_format)
968             notice->z_default_format = "";
969
970     ptr = buffer;
971     end = buffer+buffer_len;
972
973     if (buffer_len < strlen(notice->z_version)+1)
974         return (ZERR_HEADERLEN);
975
976     (void) strcpy(ptr, notice->z_version);
977     ptr += strlen(ptr)+1;
978
979     if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields)
980         == ZERR_FIELDLEN)
981         return (ZERR_HEADERLEN);
982     ptr += strlen(ptr)+1;
983
984     if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
985         return (ZERR_HEADERLEN);
986     ptr += strlen(ptr)+1;
987
988     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid, 
989                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
990         return (ZERR_HEADERLEN);
991     ptr += strlen(ptr)+1;
992
993     if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
994         return (ZERR_HEADERLEN);
995     ptr += strlen(ptr)+1;
996
997     if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
998         return (ZERR_HEADERLEN);
999     ptr += strlen(ptr)+1;
1000
1001     if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
1002         return (ZERR_HEADERLEN);
1003     ptr += strlen(ptr)+1;
1004
1005     if (Z_AddField(&ptr, notice->z_ascii_authent, end))
1006         return (ZERR_HEADERLEN);
1007     if (Z_AddField(&ptr, notice->z_class, end))
1008         return (ZERR_HEADERLEN);
1009     if (Z_AddField(&ptr, notice->z_class_inst, end))
1010         return (ZERR_HEADERLEN);
1011     if (Z_AddField(&ptr, notice->z_opcode, end))
1012         return (ZERR_HEADERLEN);
1013     if (Z_AddField(&ptr, notice->z_sender, end))
1014         return (ZERR_HEADERLEN);
1015     if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
1016         if (Z_AddField(&ptr, notice->z_recipient, end))
1017             return (ZERR_HEADERLEN);
1018     }
1019     else {
1020         if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
1021             sizeof(newrecip))
1022             return (ZERR_HEADERLEN);
1023         (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
1024         if (Z_AddField(&ptr, newrecip, end))
1025             return (ZERR_HEADERLEN);
1026     }           
1027     if (Z_AddField(&ptr, notice->z_default_format, end))
1028         return (ZERR_HEADERLEN);
1029
1030     /* copy back the end pointer location for crypto checksum */
1031     if (cstart)
1032         *cstart = ptr;
1033     if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
1034         return (ZERR_HEADERLEN);
1035     ptr += strlen(ptr)+1;
1036     if (cend)
1037         *cend = ptr;
1038
1039     if (Z_AddField(&ptr, notice->z_multinotice, end))
1040         return (ZERR_HEADERLEN);
1041
1042     if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid, 
1043                    sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
1044         return (ZERR_HEADERLEN);
1045     ptr += strlen(ptr)+1;
1046         
1047     for (i=0;i<notice->z_num_other_fields;i++)
1048         if (Z_AddField(&ptr, notice->z_other_fields[i], end))
1049             return (ZERR_HEADERLEN);
1050     
1051     *len = ptr-buffer;
1052         
1053     return (ZERR_NONE);
1054 }
1055
1056 static int
1057 Z_AddField(char **ptr,
1058            char *field,
1059            char *end)
1060 {
1061     register int len;
1062
1063     len = field ? strlen (field) + 1 : 1;
1064
1065     if (*ptr+len > end)
1066         return 1;
1067     if (field)
1068         (void) strcpy(*ptr, field);
1069     else
1070         **ptr = '\0';
1071     *ptr += len;
1072
1073     return 0;
1074 }
1075
1076 struct _Z_InputQ *
1077 Z_GetFirstComplete(void)
1078 {
1079     struct _Z_InputQ *qptr;
1080
1081     qptr = __Q_Head;
1082
1083     while (qptr) {
1084         if (qptr->complete)
1085             return (qptr);
1086         qptr = qptr->next;
1087     }
1088
1089     return ((struct _Z_InputQ *)0);
1090 }
1091
1092 struct _Z_InputQ *
1093 Z_GetNextComplete(struct _Z_InputQ *qptr)
1094 {
1095     qptr = qptr->next;
1096     while (qptr) {
1097         if (qptr->complete)
1098             return (qptr);
1099         qptr = qptr->next;
1100     }
1101
1102     return ((struct _Z_InputQ *)0);
1103 }
1104
1105 void
1106 Z_RemQueue(struct _Z_InputQ *qptr)
1107 {
1108     struct _Z_Hole *hole, *nexthole;
1109     
1110     if (qptr->complete)
1111         __Q_CompleteLength--;
1112
1113     __Q_Size -= qptr->msg_len;
1114     
1115     if (qptr->header)
1116         free(qptr->header);
1117     if (qptr->msg)
1118         free(qptr->msg);
1119     if (qptr->packet)
1120         free(qptr->packet);
1121     
1122     hole = qptr->holelist;
1123     while (hole) {
1124         nexthole = hole->next;
1125         free((char *)hole);
1126         hole = nexthole;
1127     }
1128     
1129     if (qptr == __Q_Head && __Q_Head == __Q_Tail) {
1130         free ((char *)qptr);
1131         __Q_Head = (struct _Z_InputQ *)0;
1132         __Q_Tail = (struct _Z_InputQ *)0;
1133         return;
1134     }
1135     
1136     if (qptr == __Q_Head) {
1137         __Q_Head = qptr->next;
1138         __Q_Head->prev = (struct _Z_InputQ *)0;
1139         free ((char *)qptr);
1140         return;
1141     } 
1142     if (qptr == __Q_Tail) {
1143         __Q_Tail = qptr->prev;
1144         __Q_Tail->next = (struct _Z_InputQ *)0;
1145         free ((char *)qptr);
1146         return;
1147     }
1148     qptr->prev->next = qptr->next;
1149     qptr->next->prev = qptr->prev;
1150     free ((char *)qptr);
1151     return;
1152 }
1153
1154 Code_t
1155 Z_SendFragmentedNotice(ZNotice_t *notice,
1156                        int len,
1157                        Z_AuthProc cert_func,
1158                        Z_SendProc send_func)
1159 {
1160     ZNotice_t partnotice;
1161     ZPacket_t buffer;
1162     char multi[64];
1163     int offset, hdrsize, fragsize, ret_len, message_len, waitforack;
1164     Code_t retval;
1165     
1166     hdrsize = len-notice->z_message_len;
1167     fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE;
1168     
1169     offset = 0;
1170
1171     waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED)
1172                   && !__Zephyr_server);
1173     
1174     partnotice = *notice;
1175
1176     while (offset < notice->z_message_len || !notice->z_message_len) {
1177         (void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
1178         partnotice.z_multinotice = multi;
1179         if (offset > 0) {
1180             (void) Z_gettimeofday(&partnotice.z_uid.tv,
1181                                   (struct timezone *)0);
1182             partnotice.z_uid.tv.tv_sec =
1183                 htonl((u_long) partnotice.z_uid.tv.tv_sec);
1184             partnotice.z_uid.tv.tv_usec =
1185                 htonl((u_long) partnotice.z_uid.tv.tv_usec);
1186             (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, 
1187                           sizeof(__My_addr));
1188         }
1189         message_len = min(notice->z_message_len-offset, fragsize);
1190         partnotice.z_message = notice->z_message+offset;
1191         partnotice.z_message_len = message_len;
1192         if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN,
1193                                          &ret_len, cert_func)) != ZERR_NONE) {
1194             return (retval);
1195         }
1196         memcpy(buffer + ret_len, partnotice.z_message, message_len);
1197         if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len,
1198                                    waitforack)) != ZERR_NONE) {
1199             return (retval);
1200         }
1201         offset += fragsize;
1202         if (!notice->z_message_len)
1203             break;
1204     }
1205
1206     return (ZERR_NONE);
1207 }
1208
1209 /*ARGSUSED*/
1210 Code_t Z_XmitFragment(ZNotice_t *notice,
1211                       char *buf,
1212                       int len,
1213                       int wait)
1214 {
1215     return(ZSendPacket(buf, len, wait));
1216 }
1217
1218 #ifdef Z_DEBUG
1219 /* For debugging printing */
1220 const char *const ZNoticeKinds[] = {
1221     "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
1222     "CLIENTACK", "STAT"
1223 };
1224 #endif
1225
1226 #ifdef Z_DEBUG
1227
1228 #undef Z_debug
1229 void
1230 Z_debug(const char *format, ...)
1231 {
1232     va_list pvar;
1233     if (!__Z_debug_print)
1234       return;
1235     va_start (pvar, format);
1236     (*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
1237     va_end (pvar);
1238 }
1239
1240 void
1241 Z_debug_stderr(const char *format,
1242                va_list args,
1243                void *closure)
1244 {
1245 #ifdef HAVE_VPRINTF
1246     vfprintf (stderr, format, args);
1247 #else
1248     _doprnt (format, args, stderr);
1249 #endif
1250     putc ('\n', stderr);
1251 }
1252
1253 #undef ZGetFD
1254 int ZGetFD (void) { return __Zephyr_fd; }
1255
1256 #undef ZQLength
1257 int ZQLength (void) { return __Q_CompleteLength; }
1258
1259 #undef ZGetDestAddr
1260 struct sockaddr_in ZGetDestAddr (void) { return __HM_addr; }
1261
1262 #undef ZGetRealm
1263 Zconst char * ZGetRealm (void) { return __Zephyr_realm; }
1264
1265 #undef ZSetDebug
1266 void
1267 ZSetDebug(void (*proc) __P((const char *, va_list, void *)),
1268           char *arg)
1269 {
1270     __Z_debug_print = proc;
1271     __Z_debug_print_closure = arg;
1272 }
1273 #endif /* Z_DEBUG */
1274
1275 #ifdef HAVE_KRB5
1276 Code_t
1277 Z_Checksum(krb5_data *cksumbuf,
1278            krb5_keyblock *keyblock, 
1279            krb5_cksumtype cksumtype, 
1280            char **asn1_data,
1281            int *asn1_len)
1282 {
1283     krb5_error_code result;
1284     char *data;
1285     int len;
1286 #if HAVE_KRB5_C_MAKE_CHECKSUM
1287     krb5_checksum checksum;
1288 #else
1289     Checksum checksum;
1290     krb5_crypto cryptctx;
1291 #endif
1292     
1293 #if HAVE_KRB5_C_MAKE_CHECKSUM
1294     /* Create the checksum -- MIT crypto API */
1295     result = krb5_c_make_checksum(Z_krb5_ctx, cksumtype,
1296                                   keyblock, Z_KEYUSAGE_CLT_CKSUM,
1297                                   cksumbuf, &checksum);
1298     if (result)
1299         return result;
1300     /* HOLDING: checksum */
1301
1302     data = checksum.contents;
1303     len = checksum.length;
1304 #else
1305     /* Create the checksum -- heimdal crypto API */
1306     result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, 
1307                               &cryptctx);
1308     if (result)
1309         return result;
1310
1311     /* HOLDING: cryptctx */
1312     result = krb5_create_checksum(Z_krb5_ctx, cryptctx,
1313                                   Z_KEYUSAGE_CLT_CKSUM, cksumtype,
1314                                   cksumbuf->data, cksumbuf->length,
1315                                   &checksum);
1316     krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
1317     if (result)
1318         return result;
1319
1320     len = checksum.checksum.length;
1321     data = checksum.checksum.data;
1322     /* HOLDING: checksum */
1323 #endif
1324
1325     *asn1_data = malloc(len);
1326     if (*asn1_data == NULL)
1327         return errno;
1328     memcpy(*asn1_data, data, len);
1329     *asn1_len = len;
1330
1331 #if HAVE_KRB5_C_MAKE_CHECKSUM
1332     krb5_free_checksum_contents(Z_krb5_ctx, &checksum);
1333 #else
1334     free_Checksum(&checksum);
1335 #endif
1336
1337     return 0;
1338 }
1339
1340 Code_t
1341 Z_InsertZcodeChecksum(krb5_keyblock *keyblock,
1342                       ZNotice_t *notice, 
1343                       char *buffer,
1344                       char *cksum_start,
1345                       int cksum_len, 
1346                       char *cstart,
1347                       char *cend,
1348                       int buffer_len, 
1349                       int *length_adjust)
1350 {
1351      int plain_len;   /* length of part not to be checksummed */
1352      int cksum0_len;  /* length of part before checksum */
1353      int cksum1_len;  /* length of part after checksum */
1354      krb5_data cksumbuf;
1355      krb5_data cksum;
1356      char *key_data;
1357      int key_len;
1358      krb5_enctype enctype;
1359      krb5_cksumtype cksumtype;
1360      Code_t result;
1361      
1362      key_data = Z_keydata(keyblock);
1363      key_len = Z_keylen(keyblock);
1364      result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
1365      if (result)
1366           return (ZAUTH_FAILED);
1367      
1368      /* Assemble the things to be checksummed */
1369      plain_len  = cksum_start - buffer;
1370      cksum0_len = cstart - cksum_start;
1371      cksum1_len = (cksum_start + cksum_len) - cend;
1372      memset(&cksumbuf, 0, sizeof(cksumbuf));
1373      cksumbuf.length = cksum0_len + cksum1_len + notice->z_message_len;
1374      cksumbuf.data = malloc(cksumbuf.length);
1375      if (!cksumbuf.data)
1376           return ENOMEM;
1377      memcpy(cksumbuf.data, cksum_start, cksum0_len);
1378      memcpy(cksumbuf.data + cksum0_len, cend, cksum1_len);
1379      memcpy(cksumbuf.data + cksum0_len + cksum1_len,
1380             notice->z_message, notice->z_message_len);
1381      /* compute the checksum */
1382      result = Z_Checksum(&cksumbuf, keyblock, cksumtype, 
1383                         (char **)&cksum.data, &cksum.length);
1384      if (result) {
1385           free(cksumbuf.data);
1386           return result;
1387      }
1388      
1389      /*
1390       * OK....  we can zcode to a space starting at 'cstart',
1391       * with a length of buffer_len - (plain_len + cksum_len).
1392       * Then we tack on the end part, which is located at
1393       * cksumbuf.data + cksum0_len and has length cksum1_len
1394       */
1395      
1396      result = ZMakeZcode(cstart, buffer_len - (plain_len + cksum_len),
1397                          cksum.data, cksum.length);
1398      free(cksum.data);
1399      if (!result) {
1400           int zcode_len = strlen(cstart) + 1;
1401           memcpy(cstart + zcode_len, cksumbuf.data + cksum0_len, cksum1_len);
1402           *length_adjust = zcode_len - cksum_len + (cksum0_len + cksum1_len);
1403      }
1404      free(cksumbuf.data);
1405      return result;
1406 }
1407
1408 Code_t
1409 Z_ExtractEncCksum(krb5_keyblock *keyblock,
1410                   krb5_enctype *enctype, 
1411                   krb5_cksumtype *cksumtype)
1412 {
1413     *enctype  = Z_enctype(keyblock); 
1414     return Z_krb5_lookup_cksumtype(*enctype, cksumtype); 
1415 }
1416 #endif
1417
1418 #ifdef HAVE_KRB5
1419 /* returns 0 if invalid or losing, 1 if valid, *sigh* */
1420 int
1421 Z_krb5_verify_cksum(krb5_keyblock *keyblock,
1422                     krb5_data *cksumbuf, 
1423                     krb5_cksumtype cksumtype,
1424                     char *asn1_data, 
1425                     int asn1_len)
1426 {
1427     krb5_error_code result;
1428 #if HAVE_KRB5_C_MAKE_CHECKSUM
1429     krb5_checksum checksum;
1430     krb5_boolean valid;
1431 #else
1432     krb5_crypto cryptctx;
1433     Checksum checksum;
1434     size_t xlen;
1435 #endif
1436
1437     memset(&checksum, 0, sizeof(checksum));
1438 #if HAVE_KRB5_C_MAKE_CHECKSUM
1439     /* Verify the checksum -- MIT crypto API */
1440     checksum.length = asn1_len;
1441     checksum.contents = asn1_data;
1442     checksum.checksum_type = cksumtype;
1443     result = krb5_c_verify_checksum(Z_krb5_ctx,
1444                                     keyblock, Z_KEYUSAGE_SRV_CKSUM,
1445                                     cksumbuf, &checksum, &valid);
1446     if (!result && valid)
1447         return 1;
1448     else
1449         return 0;
1450 #else
1451     checksum.checksum.length = asn1_len;
1452     checksum.checksum.data = asn1_data;
1453     checksum.cksumtype = cksumtype;
1454
1455     result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, &cryptctx);
1456     if (result)
1457         return result;
1458     
1459     /* HOLDING: cryptctx */
1460     result = krb5_verify_checksum(Z_krb5_ctx, cryptctx,
1461                                   Z_KEYUSAGE_SRV_CKSUM,
1462                                   cksumbuf->data, cksumbuf->length,
1463                                   &checksum);
1464     krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
1465     if (result)
1466         return 0;
1467     else
1468         return 1;
1469 #endif
1470 }
1471 #endif