1
/* This file is part of the Project Athena Zephyr Notification System.
2
* It contains source for the internal Zephyr routines.
4
* Created by: Robert French
6
* Copyright (c) 1987,1988,1991 by the Massachusetts Institute of
8
* For copying and distribution information, see the file
16
#ifndef ZEPHYR_USES_KERBEROS
17
int gettimeofday(struct timeval* p, struct timezone* tz ){
19
long long ns100; /*time since 1 Jan 1601 in 100ns units */
23
GetSystemTimeAsFileTime( &(_now.ft) );
24
p->tv_usec=(long)((_now.ns100 / 10LL) % 1000000LL );
25
p->tv_sec= (long)((_now.ns100-(116444736000000000LL))/10000000LL);
31
#include <arpa/inet.h>
32
#include <sys/socket.h>
37
int __Zephyr_port = -1;
38
struct in_addr __My_addr;
39
int __Q_CompleteLength;
41
struct _Z_InputQ *__Q_Head, *__Q_Tail;
42
struct sockaddr_in __HM_addr;
43
struct sockaddr_in __HM_addr_real;
46
ZLocations_t *__locate_list;
49
ZSubscription_t *__subscriptions_list;
50
int __subscriptions_num;
51
int __subscriptions_next;
52
int Z_discarded_packets = 0;
54
#ifdef ZEPHYR_USES_KERBEROS
55
C_Block __Zephyr_session;
57
char __Zephyr_realm[REALM_SZ];
60
void (*__Z_debug_print) __P((const char *fmt, va_list args, void *closure));
61
void *__Z_debug_print_closure;
64
#define min(a,b) ((a)<(b)?(a):(b))
66
static int Z_AddField __P((char **ptr, const char *field, char *end));
67
static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind));
69
/* Find or insert uid in the old uids buffer. The buffer is a sorted
70
* circular queue. We make the assumption that most packets arrive in
71
* order, so we can usually search for a uid or insert it into the buffer
72
* by looking back just a few entries from the end. Since this code is
73
* only executed by the client, the implementation isn't microoptimized. */
74
static int find_or_insert_uid(uid, kind)
78
static struct _filter {
92
/* Initialize the uid buffer if it hasn't been done already. */
94
size = Z_INITFILTERSIZE;
95
buffer = (struct _filter *) malloc(size * sizeof(*buffer));
100
/* Age the uid buffer, discarding any uids older than the clock skew. */
102
while (num && (now - buffer[start % size].t) > CLOCK_SKEW)
106
/* Make room for a new uid, since we'll probably have to insert one. */
108
new_size = size * 2 + 2;
109
new = (struct _filter *) malloc(new_size * sizeof(*new));
112
for (i = 0; i < num; i++)
113
new[i] = buffer[(start + i) % size];
120
/* Search for this uid in the buffer, starting from the end. */
121
for (i = start + num - 1; i >= start; i--) {
122
result = memcmp(uid, &buffer[i % size].uid, sizeof(*uid));
123
if (result == 0 && buffer[i % size].kind == kind)
129
/* We didn't find it; insert the uid into the buffer after i. */
131
for (j = start + num; j > i; j--)
132
buffer[j % size] = buffer[(j - 1) % size];
133
buffer[i % size].uid = *uid;
134
buffer[i % size].kind = kind;
135
buffer[i % size].t = now;
142
/* Return 1 if there is a packet waiting, 0 otherwise */
144
static int Z_PacketWaiting(void)
149
tv.tv_sec = tv.tv_usec = 0;
151
FD_SET(ZGetFD(), &read);
152
return (select(ZGetFD() + 1, &read, NULL, NULL, &tv));
156
/* Wait for a complete notice to become available */
158
Code_t Z_WaitForComplete(void)
162
if (__Q_CompleteLength)
163
return (Z_ReadEnqueue());
165
while (!__Q_CompleteLength)
166
if ((retval = Z_ReadWait()) != ZERR_NONE)
173
/* Read any available packets and enqueue them */
175
Code_t Z_ReadEnqueue()
180
return (ZERR_NOPORT);
182
while (Z_PacketWaiting())
183
if ((retval = Z_ReadWait()) != ZERR_NONE)
191
* Search the queue for a notice with the proper multiuid - remove any
192
* notices that haven't been touched in a while
195
static struct _Z_InputQ *Z_SearchQueue(ZUnique_Id_t *uid, ZNotice_Kind_t kind)
197
register struct _Z_InputQ *qptr;
198
struct _Z_InputQ *next;
201
(void) gettimeofday(&tv, (struct timezone *)0);
206
if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind)
209
if (qptr->timep && (qptr->timep+Z_NOTICETIMELIMIT < tv.tv_sec))
217
* Now we delve into really convoluted queue handling and
218
* fragmentation reassembly algorithms and other stuff you probably
219
* don't want to look at...
221
* This routine does NOT guarantee a complete packet will be ready when it
227
register struct _Z_InputQ *qptr;
230
struct sockaddr_in olddest, from;
231
int packet_len, zvlen, part, partof;
239
return (ZERR_NOPORT);
242
FD_SET(ZGetFD(), &fds);
246
if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0)
248
if (!FD_ISSET(ZGetFD(), &fds))
251
from_len = sizeof(struct sockaddr_in);
253
packet_len = recvfrom(ZGetFD(), packet, sizeof(packet), 0,
254
(struct sockaddr *)&from, &from_len);
262
/* Ignore obviously non-Zephyr packets. */
263
zvlen = sizeof(ZVERSIONHDR) - 1;
264
if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) {
265
Z_discarded_packets++;
269
/* Parse the notice */
270
if ((retval = ZParseNotice(packet, packet_len, ¬ice)) != ZERR_NONE)
274
* If we're not a server and the notice is of an appropriate kind,
275
* send back a CLIENTACK to whoever sent it to say we got it.
277
if (!__Zephyr_server) {
278
if (notice.z_kind != HMACK && notice.z_kind != SERVACK &&
279
notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) {
285
tmpnotice.z_kind = CLIENTACK;
286
tmpnotice.z_message_len = 0;
289
if ((retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len))
292
if ((retval = ZSendPacket(pkt, len, 0)) != ZERR_NONE)
296
if (find_or_insert_uid(¬ice.z_uid, notice.z_kind))
299
/* Check authentication on the notice. */
300
notice.z_checked_auth = ZCheckAuthentication(¬ice, &from);
305
* Parse apart the z_multinotice field - if the field is blank for
306
* some reason, assume this packet stands by itself.
308
slash = strchr(notice.z_multinotice, '/');
310
part = atoi(notice.z_multinotice);
311
partof = atoi(slash+1);
312
if (part > partof || partof == 0) {
314
partof = notice.z_message_len;
319
partof = notice.z_message_len;
322
/* Too big a packet...just ignore it! */
323
if (partof > Z_MAXNOTICESIZE)
327
* If we aren't a server and we can find a notice in the queue
328
* with the same multiuid field, insert the current fragment as
331
switch (notice.z_kind) {
334
/* The SERVACK and SERVNAK replies shouldn't be reassembled
335
(they have no parts). Instead, we should hold on to the reply
336
ONLY if it's the first part of a fragmented message, i.e.
337
multi_uid == uid. This allows programs to wait for the uid
338
of the first packet, and get a response when that notice
339
arrives. Acknowledgements of the other fragments are discarded
340
(XXX we assume here that they all carry the same information
341
regarding failure/success)
343
if (!__Zephyr_server &&
344
!ZCompareUID(¬ice.z_multiuid, ¬ice.z_uid))
345
/* they're not the same... throw away this packet. */
347
/* fall thru & process it */
349
/* for HMACK types, we assume no packet loss (local loopback
350
connections). The other types can be fragmented and MUST
351
run through this code. */
352
if (!__Zephyr_server && (qptr = Z_SearchQueue(¬ice.z_multiuid,
355
* If this is the first fragment, and we haven't already
356
* gotten a first fragment, grab the header from it.
358
if (part == 0 && !qptr->header) {
359
qptr->header_len = packet_len-notice.z_message_len;
360
qptr->header = (char *) malloc((unsigned) qptr->header_len);
363
(void) memcpy(qptr->header, packet, qptr->header_len);
365
return (Z_AddNoticeToEntry(qptr, ¬ice, part));
370
* We'll have to create a new entry...make sure the queue isn't
371
* going to get too big.
373
if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE)
377
* This is a notice we haven't heard of, so create a new queue
378
* entry for it and zero it out.
380
qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ));
383
(void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ));
385
/* Insert the entry at the end of the queue */
387
qptr->prev = __Q_Tail;
389
__Q_Tail->next = qptr;
396
/* Copy the from field, multiuid, kind, and checked authentication. */
398
qptr->uid = notice.z_multiuid;
399
qptr->kind = notice.z_kind;
400
qptr->auth = notice.z_checked_auth;
403
* If this is the first part of the notice, we take the header
404
* from it. We only take it if this is the first fragment so that
405
* the Unique ID's will be predictable.
407
* If a Zephyr Server, we always take the header.
409
if (__Zephyr_server || part == 0) {
410
qptr->header_len = packet_len-notice.z_message_len;
411
qptr->header = (char *) malloc((unsigned) qptr->header_len);
414
(void) memcpy(qptr->header, packet, qptr->header_len);
418
* If this is not a fragmented notice, then don't bother with a
420
* If we are a Zephyr server, all notices are treated as complete.
422
if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) {
423
__Q_CompleteLength++;
424
qptr->holelist = (struct _Z_Hole *) 0;
426
/* allocate a msg buf for this piece */
427
if (notice.z_message_len == 0)
429
else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len)))
432
(void) memcpy(qptr->msg, notice.z_message, notice.z_message_len);
433
qptr->msg_len = notice.z_message_len;
434
__Q_Size += notice.z_message_len;
435
qptr->packet_len = qptr->header_len+qptr->msg_len;
436
if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
438
(void) memcpy(qptr->packet, qptr->header, qptr->header_len);
440
(void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
446
* We know how long the message is going to be (this is better
447
* than IP fragmentation...), so go ahead and allocate it all.
449
if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof)
451
qptr->msg_len = partof;
455
* Well, it's a fragmented notice...allocate a hole list and
456
* initialize it to the full packet size. Then insert the
459
if (!(qptr->holelist = (struct _Z_Hole *)
460
malloc(sizeof(struct _Z_Hole))))
462
qptr->holelist->next = (struct _Z_Hole *) 0;
463
qptr->holelist->first = 0;
464
qptr->holelist->last = partof-1;
465
return (Z_AddNoticeToEntry(qptr, ¬ice, part));
469
/* Fragment management routines - compliments, more or less, of RFC815 */
471
Code_t Z_AddNoticeToEntry(qptr, notice, part)
472
struct _Z_InputQ *qptr;
476
int last, oldfirst, oldlast;
477
struct _Z_Hole *hole, *lasthole;
480
/* Incorporate this notice's checked authentication. */
481
if (notice->z_checked_auth == ZAUTH_FAILED)
482
qptr->auth = ZAUTH_FAILED;
483
else if (notice->z_checked_auth == ZAUTH_NO && qptr->auth != ZAUTH_FAILED)
484
qptr->auth = ZAUTH_NO;
486
(void) gettimeofday(&tv, (struct timezone *)0);
487
qptr->timep = tv.tv_sec;
489
last = part+notice->z_message_len-1;
491
hole = qptr->holelist;
492
lasthole = (struct _Z_Hole *) 0;
494
/* copy in the message body */
495
(void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len);
497
/* Search for a hole that overlaps with the current fragment */
499
if (part <= hole->last && last >= hole->first)
505
/* If we found one, delete it and reconstruct a new hole */
507
oldfirst = hole->first;
508
oldlast = hole->last;
510
lasthole->next = hole->next;
512
qptr->holelist = hole->next;
515
* Now create a new hole that is the original hole without the
518
if (part > oldfirst) {
519
/* Search for the end of the hole list */
520
hole = qptr->holelist;
521
lasthole = (struct _Z_Hole *) 0;
527
if (!(lasthole->next = (struct _Z_Hole *)
528
malloc(sizeof(struct _Z_InputQ))))
530
hole = lasthole->next;
533
if (!(qptr->holelist = (struct _Z_Hole *)
534
malloc(sizeof(struct _Z_InputQ))))
536
hole = qptr->holelist;
539
hole->first = oldfirst;
542
if (last < oldlast) {
543
/* Search for the end of the hole list */
544
hole = qptr->holelist;
545
lasthole = (struct _Z_Hole *) 0;
551
if (!(lasthole->next = (struct _Z_Hole *)
552
malloc(sizeof(struct _Z_InputQ))))
554
hole = lasthole->next;
557
if (!(qptr->holelist = (struct _Z_Hole *)
558
malloc(sizeof(struct _Z_InputQ))))
560
hole = qptr->holelist;
562
hole->next = (struct _Z_Hole *) 0;
563
hole->first = last+1;
564
hole->last = oldlast;
568
if (!qptr->holelist) {
570
__Q_CompleteLength++;
572
qptr->timep = 0; /* don't time out anymore */
573
qptr->packet_len = qptr->header_len+qptr->msg_len;
574
if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
576
(void) memcpy(qptr->packet, qptr->header, qptr->header_len);
577
(void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
584
Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine)
589
Z_AuthProc cert_routine;
592
static char version[BUFSIZ]; /* default init should be all \0 */
593
struct sockaddr_in name;
594
socklen_t namelen = sizeof(name);
596
if (!notice->z_sender)
597
notice->z_sender = ZGetSender();
599
if (notice->z_port == 0) {
601
retval = ZOpenPort((unsigned short *)0);
602
if (retval != ZERR_NONE)
605
retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
608
notice->z_port = name.sin_port;
611
notice->z_multinotice = "";
613
(void) gettimeofday(¬ice->z_uid.tv, (struct timezone *)0);
614
notice->z_uid.tv.tv_sec = htonl((unsigned long) notice->z_uid.tv.tv_sec);
615
notice->z_uid.tv.tv_usec = htonl((unsigned long) notice->z_uid.tv.tv_usec);
617
(void) memcpy(¬ice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
619
notice->z_multiuid = notice->z_uid;
622
(void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
624
notice->z_version = version;
626
return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
629
Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
634
Z_AuthProc cert_routine;
638
notice->z_authent_len = 0;
639
notice->z_ascii_authent = "";
640
notice->z_checksum = 0;
641
return (Z_FormatRawHeader(notice, buffer, buffer_len,
645
return ((*cert_routine)(notice, buffer, buffer_len, len));
648
Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend)
653
char **cstart, **cend;
655
char newrecip[BUFSIZ];
659
if (!notice->z_class)
660
notice->z_class = "";
662
if (!notice->z_class_inst)
663
notice->z_class_inst = "";
665
if (!notice->z_opcode)
666
notice->z_opcode = "";
668
if (!notice->z_recipient)
669
notice->z_recipient = "";
671
if (!notice->z_default_format)
672
notice->z_default_format = "";
675
end = buffer+buffer_len;
677
if (buffer_len < strlen(notice->z_version)+1)
678
return (ZERR_HEADERLEN);
680
g_strlcpy(ptr, notice->z_version, buffer_len);
681
ptr += strlen(ptr)+1;
683
if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields)
685
return (ZERR_HEADERLEN);
686
ptr += strlen(ptr)+1;
688
if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
689
return (ZERR_HEADERLEN);
690
ptr += strlen(ptr)+1;
692
if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_uid,
693
sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
694
return (ZERR_HEADERLEN);
695
ptr += strlen(ptr)+1;
697
if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
698
return (ZERR_HEADERLEN);
699
ptr += strlen(ptr)+1;
701
if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
702
return (ZERR_HEADERLEN);
703
ptr += strlen(ptr)+1;
705
if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
706
return (ZERR_HEADERLEN);
707
ptr += strlen(ptr)+1;
709
if (Z_AddField(&ptr, notice->z_ascii_authent, end))
710
return (ZERR_HEADERLEN);
711
if (Z_AddField(&ptr, notice->z_class, end))
712
return (ZERR_HEADERLEN);
713
if (Z_AddField(&ptr, notice->z_class_inst, end))
714
return (ZERR_HEADERLEN);
715
if (Z_AddField(&ptr, notice->z_opcode, end))
716
return (ZERR_HEADERLEN);
717
if (Z_AddField(&ptr, notice->z_sender, end))
718
return (ZERR_HEADERLEN);
719
if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
720
if (Z_AddField(&ptr, notice->z_recipient, end))
721
return (ZERR_HEADERLEN);
724
if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
726
return (ZERR_HEADERLEN);
727
(void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
728
if (Z_AddField(&ptr, newrecip, end))
729
return (ZERR_HEADERLEN);
731
if (Z_AddField(&ptr, notice->z_default_format, end))
732
return (ZERR_HEADERLEN);
734
/* copy back the end pointer location for crypto checksum */
737
if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
738
return (ZERR_HEADERLEN);
739
ptr += strlen(ptr)+1;
743
if (Z_AddField(&ptr, notice->z_multinotice, end))
744
return (ZERR_HEADERLEN);
746
if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_multiuid,
747
sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
748
return (ZERR_HEADERLEN);
749
ptr += strlen(ptr)+1;
751
for (i=0;i<notice->z_num_other_fields;i++)
752
if (Z_AddField(&ptr, notice->z_other_fields[i], end))
753
return (ZERR_HEADERLEN);
761
Z_AddField(char **ptr, const char *field, char *end)
765
len = field ? strlen (field) + 1 : 1;
778
struct _Z_InputQ *Z_GetFirstComplete()
780
struct _Z_InputQ *qptr;
790
return ((struct _Z_InputQ *)0);
793
struct _Z_InputQ *Z_GetNextComplete(qptr)
794
struct _Z_InputQ *qptr;
803
return ((struct _Z_InputQ *)0);
806
void Z_RemQueue(qptr)
807
struct _Z_InputQ *qptr;
809
struct _Z_Hole *hole, *nexthole;
812
__Q_CompleteLength--;
814
__Q_Size -= qptr->msg_len;
823
hole = qptr->holelist;
825
nexthole = hole->next;
830
if (qptr == __Q_Head && __Q_Head == __Q_Tail) {
832
__Q_Head = (struct _Z_InputQ *)0;
833
__Q_Tail = (struct _Z_InputQ *)0;
837
if (qptr == __Q_Head) {
838
__Q_Head = qptr->next;
839
__Q_Head->prev = (struct _Z_InputQ *)0;
843
if (qptr == __Q_Tail) {
844
__Q_Tail = qptr->prev;
845
__Q_Tail->next = (struct _Z_InputQ *)0;
849
qptr->prev->next = qptr->next;
850
qptr->next->prev = qptr->prev;
855
Code_t Z_SendFragmentedNotice(notice, len, cert_func, send_func)
858
Z_AuthProc cert_func;
859
Z_SendProc send_func;
861
ZNotice_t partnotice;
864
int offset, hdrsize, fragsize, ret_len, message_len, waitforack;
867
hdrsize = len-notice->z_message_len;
868
fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE;
872
waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED)
873
&& !__Zephyr_server);
875
partnotice = *notice;
877
while (offset < notice->z_message_len || !notice->z_message_len) {
878
(void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
879
partnotice.z_multinotice = multi;
881
(void) gettimeofday(&partnotice.z_uid.tv,
882
(struct timezone *)0);
883
partnotice.z_uid.tv.tv_sec =
884
htonl((unsigned long) partnotice.z_uid.tv.tv_sec);
885
partnotice.z_uid.tv.tv_usec =
886
htonl((unsigned long) partnotice.z_uid.tv.tv_usec);
887
(void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
890
message_len = min(notice->z_message_len-offset, fragsize);
891
partnotice.z_message = (char*)notice->z_message+offset;
892
partnotice.z_message_len = message_len;
893
if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN,
894
&ret_len, cert_func)) != ZERR_NONE) {
897
memcpy(buffer + ret_len, partnotice.z_message, message_len);
898
if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len,
899
waitforack)) != ZERR_NONE) {
903
if (!notice->z_message_len)
911
Code_t Z_XmitFragment(notice, buf, len, wait)
917
return(ZSendPacket(buf, len, wait));
921
/* For debugging printing */
922
const char *const ZNoticeKinds[] = {
923
"UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
932
void Z_debug (const char *format, ...)
935
if (!__Z_debug_print)
937
va_start (pvar, format);
938
(*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
942
void Z_debug (va_alist) va_dcl
946
if (!__Z_debug_print)
949
format = va_arg (pvar, char *);
950
(*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
955
void Z_debug_stderr (format, args, closure)
961
vfprintf (stderr, format, args);
963
_doprnt (format, args, stderr);
969
int ZGetFD () { return __Zephyr_fd; }
972
int ZQLength () { return __Q_CompleteLength; }
975
struct sockaddr_in ZGetDestAddr () { return __HM_addr; }
978
Zconst char * ZGetRealm () { return __Zephyr_realm; }
981
void ZSetDebug(proc, arg)
982
void (*proc) __P((const char *, va_list, void *));
985
__Z_debug_print = proc;
986
__Z_debug_print_closure = arg;