1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains functions for managing subscription lists.
4 * Created by: John T. Kohl
6 * $Id: subscr.c,v 1.56 1999/01/22 23:19:48 ghudson Exp $
8 * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
13 #include <zephyr/mit-copyright.h>
18 static const char rcsid_subscr_c[] = "$Id: subscr.c,v 1.56 1999/01/22 23:19:48 ghudson Exp $";
23 * The subscription manager.
27 * Code_t subscr_subscribe(who, notice)
31 * Code_t subscr_cancel(sin, notice)
32 * struct sockaddr_in *sin;
35 * Code_t subscr_cancel_client(client)
38 * Code_t subscr_cancel_host(addr)
39 * struct in_addr *addr;
41 * Client *subscr_match_list(notice)
44 * void subscr_free_list(list)
47 * void subscr_sendlist(notice, auth, who)
50 * struct sockaddr_in *who;
52 * Code_t subscr_send_subs(client, vers)
56 * Code_t subscr_def_subs(who)
59 * void subscr_reset();
70 /* for compatibility when sending subscription information to old clients */
73 #define OLD_ZEPHYR_VERSION "ZEPH0.0"
74 #define OLD_CLIENT_INCOMPSUBS "INCOMP"
75 static void old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
76 struct sockaddr_in *who));
77 extern int old_compat_count_subscr; /* counter of old use */
78 #endif /* OLD_COMPAT */
80 #define NEW_OLD_ZEPHYR_VERSION "ZEPH0.1"
81 static void new_old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
82 struct sockaddr_in *who));
83 extern int new_compat_count_subscr; /* counter of old use */
84 #endif /* NEW_COMPAT */
86 extern char *re_comp(), *re_conv();
87 static Code_t add_subscriptions __P((Client *who, Destlist *subs_queue,
89 static Destlist *extract_subscriptions __P((ZNotice_t *notice));
90 static void free_subscriptions __P((Destlist *subs));
91 static char **subscr_marshal_subs __P((ZNotice_t *notice, int auth,
92 struct sockaddr_in *who,
94 static Destlist *subscr_copy_def_subs __P((char *person));
95 static Code_t subscr_subscribe_realms __P((struct sockaddr_in *who,
98 static Code_t subscr_realm_sendit __P((Client *who, Destlist *subs,
99 ZNotice_t *notice, Realm *realm));
100 static void subscr_unsub_realms __P((Destlist *newsubs));
101 static void subscr_unsub_sendit __P((Destlist *subs, Realm *realm));
102 static int cl_match __P((Destlist*, Client *));
104 static int defaults_read = 0; /* set to 1 if the default subs
106 static ZNotice_t default_notice; /* contains default subscriptions */
108 String *wildcard_instance;
111 /* WARNING: make sure this is the same as the number of strings you */
112 /* plan to hand back to the user in response to a subscription check, */
113 /* else you will lose. See subscr_sendlist() */
117 * subscribe the client to types described in notice.
121 subscr_subscribe(who, notice)
127 subs = extract_subscriptions(notice);
128 return add_subscriptions(who, subs, notice);
132 add_subscriptions(who, subs, notice)
144 return ZERR_NONE; /* no subscr -> no error */
146 sender = make_string(notice->z_sender, 0);
148 /* Loop over the new subscriptions. */
149 for (; subs; subs = next) {
152 zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
153 subs->dest.inst->string, subs->dest.recip->string));
156 if (subs->dest.recip != empty && subs->dest.recip != sender
157 && subs->dest.recip->string[0] != '@') {
158 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
159 sender->string, subs->dest.recip->string);
162 acl = class_get_acl(subs->dest.classname);
164 if (!access_check(sender->string, acl, SUBSCRIBE)) {
165 syslog(LOG_WARNING, "subscr unauth %s class %s",
166 sender->string, subs->dest.classname->string);
167 continue; /* the for loop */
169 if (wildcard_instance == subs->dest.inst) {
170 if (!access_check(sender->string, acl, INSTWILD)) {
172 "subscr unauth %s class %s wild inst",
173 sender->string, subs->dest.classname->string);
179 /* check the recipient for a realm which isn't ours */
181 if (subs->dest.recip->string[0] == '@' &&
182 strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
183 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
185 retval = subscr_realm_sendit(who, subs, notice, realm);
186 if (retval != ZERR_NONE) {
191 retval = triplet_register(who, &subs->dest, realm);
192 if (retval != ZERR_NONE) {
194 if (retval == ZSRV_CLASSXISTS) {
197 free_subscriptions(next);
201 LIST_INSERT(&who->subs, subs);
208 * add default subscriptions to the client's subscription chain.
217 subs = subscr_copy_def_subs(who->principal->string);
218 return add_subscriptions(who, subs, &default_notice);
225 zdbug((LOG_DEBUG, "subscr_reset()"));
227 free(default_notice.z_message);
228 default_notice.z_message = NULL;
233 subscr_copy_def_subs(person)
238 char *def_sub_area, *cp;
239 Destlist *subs, *sub;
241 if (!defaults_read) {
243 zdbug((LOG_DEBUG, "reading default subscription file"));
245 fd = open(subs_file, O_RDONLY, 0666);
247 syslog(LOG_ERR, "can't open %s:%m", subs_file);
250 retval = fstat(fd, &statbuf);
252 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
256 def_sub_area = (char *) malloc(statbuf.st_size + 1);
258 syslog(LOG_ERR, "no mem copy_def_subs");
262 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
263 if (retval != statbuf.st_size) {
264 syslog(LOG_ERR, "short read in copy_def_subs");
270 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
273 def_subs_area now points to a buffer full of subscription info.
274 Each line of the stuff is of the form:
277 Commas and newlines may not appear as part of the class,
278 instance, or recipient. XXX!
281 /* split up the subscription info */
282 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
283 if (*cp == '\n' || *cp == ',')
286 default_notice.z_message = def_sub_area;
287 default_notice.z_message_len = statbuf.st_size + 1;
288 default_notice.z_auth = 1;
292 /* needed later for access_check() */
293 default_notice.z_sender = person;
294 subs = extract_subscriptions(&default_notice);
295 /* replace any non-* recipients with "person" */
297 for (sub = subs; sub; sub = sub->next) {
298 /* if not a wildcard, replace it with person */
299 if (strcmp(sub->dest.recip->string, "*")) {
300 free_string(sub->dest.recip);
301 sub->dest.recip = make_string(person, 0);
302 } else { /* replace with null recipient */
303 free_string(sub->dest.recip);
304 sub->dest.recip = dup_string(empty);
311 * Cancel a specific set of subscriptions.
315 subscr_cancel(sin, notice)
316 struct sockaddr_in *sin;
321 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
327 zdbug((LOG_DEBUG,"subscr_cancel"));
329 who = client_find(&sin->sin_addr, notice->z_port);
336 cancel_subs = extract_subscriptions(notice);
338 return ZERR_NONE; /* no subscr -> no error */
340 for (subs = cancel_subs; subs; subs = cancel_next) {
341 cancel_next = subs->next;
342 for (client_subs = who->subs; client_subs; client_subs = client_next) {
343 client_next = client_subs->next;
344 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
345 LIST_DELETE(client_subs);
346 triplet_deregister(who, &client_subs->dest, NULL);
347 if (retval == ZSRV_EMPTYCLASS &&
348 client_subs->dest.recip->string[0] == '@') {
350 realm_get_realm_by_name(client_subs->dest.recip->string
353 subscr_unsub_sendit(client_subs, realm);
356 free_string(client_subs->dest.classname);
357 free_string(client_subs->dest.inst);
358 free_string(client_subs->dest.recip);
366 free_subscriptions(cancel_subs);
370 zdbug((LOG_DEBUG, "found & removed"));
375 zdbug((LOG_DEBUG, "not found"));
382 subscr_realm_cancel(sin, notice, realm)
383 struct sockaddr_in *sin;
388 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
398 cancel_subs = extract_subscriptions(notice);
400 return ZERR_NONE; /* no subscr -> no error */
402 for (subs = cancel_subs; subs; subs = next) {
404 for (client_subs = realm->subs; client_subs; client_subs = next2) {
405 next2 = client_subs->next;
406 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
407 LIST_DELETE(client_subs);
408 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
409 free_string(client_subs->dest.classname);
410 free_string(client_subs->dest.inst);
411 free_string(client_subs->dest.recip);
419 free_subscriptions(cancel_subs);
423 zdbug((LOG_DEBUG, "found & removed"));
428 zdbug((LOG_DEBUG, "not found"));
435 * Cancel all the subscriptions for this client.
439 subscr_cancel_client(client)
442 Destlist *subs, *next;
447 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
448 inet_ntoa(client->addr.sin_addr)));
453 for (subs = client->subs; subs; subs = next) {
456 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
458 retval = triplet_deregister(client, &subs->dest, NULL);
459 if (retval == ZSRV_EMPTYCLASS &&
460 subs->dest.recip->string[0] == '@') {
461 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
463 subscr_unsub_sendit(subs, realm);
466 free_string(subs->dest.classname);
467 free_string(subs->dest.inst);
468 free_string(subs->dest.recip);
476 * Send the requester a list of his current subscriptions
480 subscr_sendlist(notice, auth, who)
483 struct sockaddr_in *who;
487 struct sockaddr_in send_to_who;
491 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
492 /* we are talking to an old client; use the old-style
493 acknowledgement-message */
494 old_compat_subscr_sendlist(notice, auth, who);
497 #endif /* OLD_COMPAT */
499 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
500 /* we are talking to a new old client; use the new-old-style
501 acknowledgement-message */
502 new_old_compat_subscr_sendlist(notice, auth, who);
505 #endif /* NEW_COMPAT */
506 answer = subscr_marshal_subs(notice, auth, who, &found);
508 send_to_who.sin_port = notice->z_port; /* Return port */
510 retval = ZSetDestAddr(&send_to_who);
511 if (retval != ZERR_NONE) {
512 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
513 error_message(retval));
519 /* XXX for now, don't do authentication */
522 notice->z_kind = ACKED;
524 /* use xmit_frag() to send each piece of the notice */
526 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
527 if (retval != ZERR_NONE)
528 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
534 subscr_marshal_subs(notice, auth, who, found)
537 struct sockaddr_in *who;
540 char **answer = NULL;
544 Destlist *subs = NULL, *sub;
549 zdbug((LOG_DEBUG, "subscr_marshal"));
553 /* Note that the following code is an incredible crock! */
555 /* We cannot send multiple packets as acknowledgements to the client,
556 since the hostmanager will ignore the later packets. So we need
557 to send directly to the client. */
559 /* Make our own copy so we can send directly back to the client */
562 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
563 /* If the client has requested his current subscriptions,
564 the message field of the notice contains the port number
565 of the client for which the sender desires the subscription
566 list. The port field is the port of the sender. */
568 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
569 if (retval != ZERR_NONE) {
570 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
571 error_message(retval));
575 client = client_find(&who->sin_addr, htons(temp));
579 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
581 zdbug((LOG_DEBUG, "gimmedefs"));
583 /* subscr_copy_def_subs allocates new pointer rings, so
584 it must be freed when finished.
585 the string areas pointed to are static, however.*/
586 subs = subscr_copy_def_subs(notice->z_sender);
589 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
596 /* check authenticity here. The user must be authentic to get
597 a list of subscriptions. If he is not subscribed to
598 anything, this if-clause fails, and he gets a response
599 indicating no subscriptions.
600 if retrieving default subscriptions, don't care about
603 if (!auth && !defsubs)
606 if (client && (strcmp(client->principal->string,
607 notice->z_sender) != 0)) {
609 "subscr_marshal: %s requests subs for %s at %s/%d",
610 notice->z_sender, client->principal->string,
611 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
616 for (sub = subs; sub; sub = sub->next)
619 /* found is now the number of subscriptions */
621 /* coalesce the subscription information into a list of char *'s */
622 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
623 if (answer == NULL) {
624 syslog(LOG_ERR, "subscr no mem(answer)");
628 for (sub = subs; sub; sub = sub->next) {
629 answer[i * NUM_FIELDS] = sub->dest.classname->string;
630 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
631 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
637 free_subscriptions(subs);
643 new_old_compat_subscr_sendlist(notice, auth, who)
646 struct sockaddr_in *who;
651 int packlen, found, count, initfound, zerofound;
654 struct sockaddr_in send_to_who;
657 new_compat_count_subscr++;
659 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
661 reply.z_kind = SERVACK;
662 reply.z_authent_len = 0; /* save some space */
666 send_to_who.sin_port = notice->z_port; /* Return port */
668 retval = ZSetDestAddr(&send_to_who);
669 if (retval != ZERR_NONE) {
670 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
671 error_message(retval));
675 /* retrieve the subscriptions */
676 answer = subscr_marshal_subs(notice, auth, who, &found);
678 /* note that when there are no subscriptions, found == 0, so
679 we needn't worry about answer being NULL since
680 ZFormatSmallRawNoticeList won't reference the pointer */
682 /* send 5 at a time until we are finished */
683 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
684 i = 0; /* pkt # counter */
686 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
689 zerofound = (found == 0);
690 while (found > 0 || zerofound) {
691 packlen = sizeof(reppacket);
692 sprintf(buf, "%d/%d", ++i, count);
693 reply.z_opcode = buf;
694 retval = ZFormatSmallRawNoticeList(&reply,
695 answer + (initfound - found)
697 ((found > 5) ? 5 : found)
699 reppacket, &packlen);
700 if (retval != ZERR_NONE) {
701 syslog(LOG_ERR, "subscr_sendlist format: %s",
702 error_message(retval));
707 retval = ZSendPacket(reppacket, packlen, 0);
708 if (retval != ZERR_NONE) {
709 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
710 error_message(retval));
719 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
724 #endif /* NEW_COMPAT */
728 old_compat_subscr_sendlist(notice, auth, who)
731 struct sockaddr_in *who;
733 Client *client = client_find(&who->sin_addr, notice->z_port);
738 int packlen, i, found = 0;
739 char **answer = NULL;
741 old_compat_count_subscr++;
743 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
744 if (client && client->subs) {
746 /* check authenticity here. The user must be authentic to get
747 a list of subscriptions. If he is not subscribed to
748 anything, the above test fails, and he gets a response
749 indicating no subscriptions */
752 clt_ack(notice, who, AUTH_FAILED);
756 for (subs = client->subs; subs; subs = subs->next)
758 /* found is now the number of subscriptions */
760 /* coalesce the subscription information into a list of char *'s */
761 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
763 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
767 for (subs = client->subs; subs; subs = subs->next) {
768 answer[i*NUM_FIELDS] = subs->dest.classname->string;
769 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
770 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
776 /* note that when there are no subscriptions, found == 0, so
777 we needn't worry about answer being NULL */
780 reply.z_kind = SERVACK;
781 reply.z_authent_len = 0; /* save some space */
784 /* if it's too long, chop off one at a time till it fits */
785 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
788 &packlen)) != ZERR_PKTLEN) {
790 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
792 if (retval != ZERR_NONE) {
793 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
794 error_message(retval));
799 retval = ZSetDestAddr(who);
800 if (retval != ZERR_NONE) {
801 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
802 error_message(retval));
807 retval = ZSendPacket(reppacket, packlen, 0);
808 if (retval != ZERR_NONE) {
809 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
810 error_message(retval));
816 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
821 #endif /* OLD_COMPAT */
824 * Send the client's subscriptions to another server
827 /* version is currently unused; if necessary later versions may key off it
828 to determine what to send to the peer (protocol changes) */
832 subscr_send_subs(client)
840 #endif /* HAVE_KRB4 */
842 char *list[7 * NUM_FIELDS];
847 zdbug((LOG_DEBUG, "send_subs"));
849 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
855 memcpy(cblock, client->session_key, sizeof(C_Block));
857 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
860 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
861 if (retval != ZERR_NONE) {
863 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
868 zdbug((LOG_DEBUG, "cblock %s", buf));
871 #endif /* HAVE_KRB4 */
872 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
873 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
874 client->principal->string, "", list, num);
875 if (retval != ZERR_NONE) {
876 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
883 for (subs = client->subs; subs; subs = subs->next) {
884 /* for each subscription */
885 list[i * NUM_FIELDS] = subs->dest.classname->string;
886 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
887 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
890 /* we only put 7 in each packet, so we don't run out of room */
891 retval = bdump_send_list_tcp(ACKED, &client->addr,
892 ZEPHYR_CTL_CLASS, "",
893 CLIENT_SUBSCRIBE, "", "", list,
895 if (retval != ZERR_NONE) {
896 syslog(LOG_ERR, "subscr_send_subs subs: %s",
897 error_message(retval));
904 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
905 "", CLIENT_SUBSCRIBE, "", "", list,
907 if (retval != ZERR_NONE) {
908 syslog(LOG_ERR, "subscr_send_subs subs: %s",
909 error_message(retval));
918 * free the memory allocated for the list of subscriptions.
922 free_subscriptions(subs)
927 for (; subs; subs = next) {
929 free_string(subs->dest.classname);
930 free_string(subs->dest.inst);
931 free_string(subs->dest.recip);
936 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
937 if (cp >= notice->z_message + notice->z_message_len) { \
938 syslog(LOG_WARNING, "malformed subscription %d", \
944 * Parse the message body, returning a linked list of subscriptions, or
945 * NULL if there are no subscriptions there.
949 extract_subscriptions(notice)
952 Destlist *subs = NULL, *sub;
953 char *recip, *class_name, *classinst;
954 char *cp = notice->z_message;
956 /* parse the data area for the subscriptions */
957 while (cp < notice->z_message + notice->z_message_len) {
959 if (*cp == '\0') /* we've exhausted the subscriptions */
966 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
967 class_name, classinst, cp));
969 cp += (strlen(cp) + 1);
970 if (cp > notice->z_message + notice->z_message_len) {
971 syslog(LOG_WARNING, "malformed sub 3");
974 sub = (Destlist *) malloc(sizeof(Destlist));
976 syslog(LOG_WARNING, "ex_subs: no mem 2");
979 sub->dest.classname = make_string(class_name, 1);
980 sub->dest.inst = make_string(classinst, 1);
981 /* Nuke @REALM if REALM is us. */
982 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
983 sub->dest.recip = make_string("", 0);
985 sub->dest.recip = make_string(recip, 0);
986 LIST_INSERT(&subs, sub);
992 * print subscriptions in subs onto fp.
993 * assumed to be called with SIGFPE blocked
994 * (true if called from signal handler)
998 subscr_dump_subs(fp, subs)
1004 if (!subs) /* no subscriptions to dump */
1007 for (; subs; subs = subs->next) {
1009 dump_quote(subs->dest.classname->string, fp);
1011 dump_quote(subs->dest.inst->string, fp);
1013 dump_quote(subs->dest.recip->string, fp);
1018 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1019 if (cp >= notice->z_message + notice->z_message_len) { \
1020 syslog(LOG_WARNING, "malformed subscription %d", \
1022 return (ZERR_NONE); \
1025 /* As it exists, this function expects to take only the first sub from the
1026 * Destlist. At some point, it and the calling code should be replaced */
1028 subscr_realm_sendit(who, subs, notice, realm)
1043 char addr[16]; /* xxx.xxx.xxx.xxx max */
1047 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1052 for (subs2 = subs; subs2; subs2 = subs2->next, found++);
1053 /* found is now the number of subscriptions */
1055 /* coalesce the subscription information into a list of char *'s */
1056 /* one extra for client information */
1057 if ((text = (char **) malloc((found * NUM_FIELDS + 2)
1058 * sizeof(char *))) == (char **) 0)
1060 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1065 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1066 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1069 /* convert the address to a string of the form x.x.x.x/port */
1070 strcpy(addr, inet_ntoa(notice->z_sender_addr));
1071 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1072 ¬ice->z_port, sizeof(u_short))) != ZERR_NONE)
1074 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1075 error_message(retval));
1082 for (i = 0, subs2 = subs; subs2, i < found ; i++, subs2 = subs2->next) {
1083 text[i*NUM_FIELDS + 2] = subs2->dest.classname->string;
1084 text[i*NUM_FIELDS + 3] = subs2->dest.inst->string;
1085 text[i*NUM_FIELDS + 4] = subs2->dest.recip->string;
1089 text[2] = subs->dest.classname->string;
1090 text[3] = subs->dest.inst->string;
1091 text[4] = subs->dest.recip->string;
1093 /* format snotice */
1094 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1095 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1096 snotice.z_port = srv_addr.sin_port;
1098 snotice.z_class = ZEPHYR_CTL_CLASS;
1100 snotice.z_recipient = "";
1101 snotice.z_kind = ACKED;
1102 snotice.z_num_other_fields = 0;
1103 snotice.z_default_format = "";
1104 snotice.z_sender = notice->z_sender;
1105 snotice.z_recipient = notice->z_recipient;
1106 snotice.z_default_format = notice->z_default_format;
1109 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2,
1110 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1112 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1113 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1116 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1117 error_message(retval));
1123 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1124 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1125 error_message(retval));
1131 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1133 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1140 subscr_add_raw(client, realm, newsubs)
1145 Destlist *subs, *subs2, *subs3, **head;
1149 zdbug((LOG_DEBUG, "subscr_add_raw"));
1151 head = (realm) ? &realm->subs : &client->subs;
1153 /* Loop over the new subscriptions. */
1154 for (subs = newsubs; subs; subs = subs2) {
1157 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1159 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1161 retval = triplet_register(client, &subs->dest, realm);
1162 if (retval != ZERR_NONE) {
1164 if (retval == ZSRV_CLASSXISTS) {
1167 free_subscriptions(subs2);
1171 LIST_INSERT(head, subs);
1177 subscr_realm(realm, notice)
1183 newsubs = extract_subscriptions(notice);
1186 syslog(LOG_WARNING, "empty subs in subscr_realm");
1190 return(subscr_add_raw(realm->client, realm, newsubs));
1193 /* Like realm_sendit, this only takes one item from subs */
1195 subscr_unsub_sendit(subs, realm)
1202 char *list[7 * NUM_FIELDS];
1204 char *list[NUM_FIELDS];
1211 unotice.z_class = ZEPHYR_CTL_CLASS;
1212 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1213 unotice.z_opcode = REALM_UNSUBSCRIBE;
1214 unotice.z_recipient = "";
1215 unotice.z_kind = ACKED;
1217 unotice.z_sender = "";
1218 unotice.z_port = srv_addr.sin_port;
1219 unotice.z_num_other_fields = 0;
1220 unotice.z_default_format = "";
1224 for (subs2 = subs; subs2; subs2 = subs2->next) {
1225 list[found * NUM_FIELDS] = subs2->dest.classname->string;
1226 list[found * NUM_FIELDS + 1] = subs2->dest.inst->string;
1227 list[found * NUM_FIELDS + 2] = "";
1232 if ((retval = ZFormatNoticeList(&unotice, list, found * NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1233 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1234 error_message(retval));
1237 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1238 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1239 error_message(retval));
1244 realm_handoff(&unotice, 1, (struct sockaddr_in *) 0, realm, 0);
1252 if ((retval = ZFormatNoticeList(&unotice, list, found * NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1253 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1254 error_message(retval));
1258 list[0] = subs->dest.classname->string;
1259 list[1] = subs->dest.inst->string;
1262 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1263 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1264 error_message(retval));
1269 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1270 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1271 error_message(retval));
1276 realm_handoff(&unotice, 1, (struct sockaddr_in *) 0, realm, 0);
1280 subscr_send_realm_subs(realm)
1284 Destlist *subs, *next;
1286 char *list[7 * NUM_FIELDS];
1291 zdbug((LOG_DEBUG, "send_realm_subs"));
1294 strcpy(buf, realm->name);
1297 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1298 "", ADMIN_NEWREALM, "", "", list, num);
1299 if (retval != ZERR_NONE) {
1300 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1307 for (subs=realm->subs; subs; subs = next) {
1310 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1311 subs->dest.inst->string, subs->dest.recip->string));
1313 /* for each subscription */
1314 list[i * NUM_FIELDS] = subs->dest.classname->string;
1315 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1316 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1319 /* we only put 7 in each packet, so we don't run out of room */
1320 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1321 ZEPHYR_CTL_CLASS, "",
1322 REALM_SUBSCRIBE, "", "", list,
1324 if (retval != ZERR_NONE) {
1325 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1326 error_message(retval));
1333 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1334 "", REALM_SUBSCRIBE, "", "", list,
1336 if (retval != ZERR_NONE) {
1337 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1338 error_message(retval));
1347 subscr_check_foreign_subs(notice, who, realm, newsubs)
1349 struct sockaddr_in *who;
1353 Destlist *subs, *subs2, *next;
1363 for (subs = newsubs; subs; subs = subs->next)
1369 sender = make_string(notice->z_sender, 0);
1371 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) == (char **) 0) {
1372 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1376 /* grab the client information from the incoming message */
1377 cp = notice->z_message;
1386 for (subs = newsubs; subs; subs = next) {
1388 acl = class_get_acl(subs->dest.classname);
1390 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1391 syslog(LOG_WARNING, "subscr unauth %s class %s",
1392 sender->string, subs->dest.classname->string);
1393 continue; /* the for loop */
1395 if (wildcard_instance == subs->dest.inst) {
1396 if (!access_check(sender->string, acl, INSTWILD)) {
1398 "subscr unauth %s class %s wild inst",
1399 sender->string, subs->dest.classname->string);
1405 /* okay to subscribe. save for return trip */
1406 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1407 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1408 text[found*NUM_FIELDS + 4] = "";
1411 retval = triplet_register(realm->client, &subs->dest, realm);
1413 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1414 subs->dest.inst->string, subs->dest.recip->string));
1417 if (retval != ZERR_NONE) {
1418 if (retval == ZSRV_CLASSXISTS) {
1421 free_subscriptions(subs->next);
1426 LIST_INSERT(&realm->subs, subs);
1428 /* don't send confirmation if we're not the initial server contacted */
1429 if (!(server_which_server(who) || found == 0)) {
1431 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1432 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1433 snotice.z_port = srv_addr.sin_port;
1434 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1435 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1436 error_message(retval));
1440 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1441 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1442 error_message(retval));
1447 realm_handoff(&snotice, 1, who, realm, 0);
1454 Code_t subscr_foreign_user(notice, who, realm)
1456 struct sockaddr_in *who;
1459 Destlist *newsubs, *temp;
1464 struct sockaddr_in newwho;
1466 char rlm_recipient[REALM_SZ + 1];
1469 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1472 cp = notice->z_message;
1474 newwho.sin_addr.s_addr = inet_addr(cp);
1475 if (newwho.sin_addr.s_addr == -1) {
1476 syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1484 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1487 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1488 error_message(status));
1494 snotice.z_message = cp;
1495 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1497 newsubs = extract_subscriptions(&snotice);
1499 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1503 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1504 /* this was approved by the other realm, add subscriptions */
1506 client = client_find(&newwho.sin_addr, snotice.z_port);
1507 if (client == (Client *)0) {
1508 syslog(LOG_WARNING, "no client at %s/%d",
1509 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1510 free_subscriptions(newsubs);
1514 /* translate the recipient to represent the foreign realm */
1515 sprintf(rlm_recipient, "@%s", realm->name);
1516 for (temp = newsubs; temp; temp = temp->next) {
1518 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1520 temp->dest.recip = make_string(rlm_recipient, 0);
1523 status = subscr_add_raw(client, (Realm *)0, newsubs);
1524 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1525 status = subscr_check_foreign_subs(notice, who, realm, newsubs);
1527 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",