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 * $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/subscr.c,v $
9 * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
14 #include <zephyr/mit-copyright.h>
19 static const char rcsid_subscr_c[] = "$Id$";
24 * The subscription manager.
28 * Code_t subscr_subscribe(who, notice)
32 * Code_t subscr_cancel(sin, notice)
33 * struct sockaddr_in *sin;
36 * Code_t subscr_cancel_client(client)
39 * Code_t subscr_cancel_host(addr)
40 * struct in_addr *addr;
42 * Client *subscr_match_list(notice)
45 * void subscr_free_list(list)
48 * void subscr_sendlist(notice, auth, who)
51 * struct sockaddr_in *who;
53 * Code_t subscr_send_subs(client, vers)
57 * Code_t subscr_def_subs(who)
60 * void subscr_reset();
71 /* for compatibility when sending subscription information to old clients */
74 #define OLD_ZEPHYR_VERSION "ZEPH0.0"
75 #define OLD_CLIENT_INCOMPSUBS "INCOMP"
76 static void old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
77 struct sockaddr_in *who));
78 extern int old_compat_count_subscr; /* counter of old use */
79 #endif /* OLD_COMPAT */
81 #define NEW_OLD_ZEPHYR_VERSION "ZEPH0.1"
82 static void new_old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
83 struct sockaddr_in *who));
84 extern int new_compat_count_subscr; /* counter of old use */
85 #endif /* NEW_COMPAT */
87 extern char *re_comp(), *re_conv();
88 static Code_t add_subscriptions __P((Client *who, Destlist *subs_queue,
89 ZNotice_t *notice, Server *server));
90 static Destlist *extract_subscriptions __P((ZNotice_t *notice));
91 static void free_subscriptions __P((Destlist *subs));
92 static void free_subscription __P((Destlist *sub));
93 static char **subscr_marshal_subs __P((ZNotice_t *notice, int auth,
94 struct sockaddr_in *who,
96 static Destlist *subscr_copy_def_subs __P((char *person));
97 static Code_t subscr_realm_sendit __P((Client *who, Destlist *subs,
98 ZNotice_t *notice, Realm *realm));
99 static void subscr_unsub_realms __P((Destlist *newsubs));
100 static void subscr_unsub_sendit __P((Client *who, Destlist *subs,
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, server)
128 subs = extract_subscriptions(notice);
129 return add_subscriptions(who, subs, notice, server);
133 add_subscriptions(who, subs, notice, server)
146 return ZERR_NONE; /* no subscr -> no error */
148 sender = make_string(notice->z_sender, 0);
150 /* Loop over the new subscriptions. */
151 for (; subs; subs = next) {
154 zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
155 subs->dest.inst->string, subs->dest.recip->string));
157 /* check the recipient for a realm which isn't ours */
159 if (subs->dest.recip->string[0] == '@' &&
160 strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
161 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
163 if (subs->dest.recip != empty && subs->dest.recip != sender
164 && subs->dest.recip->string[0] != '@') {
165 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
166 sender->string, subs->dest.recip->string);
167 free_subscription(subs); /* free this one - denied */
168 continue; /* the for loop */
170 acl = class_get_acl(subs->dest.classname);
172 if (!access_check(sender->string, acl, SUBSCRIBE)) {
173 syslog(LOG_WARNING, "subscr unauth %s class %s",
174 sender->string, subs->dest.classname->string);
175 free_subscription(subs); /* free this one - denied */
176 continue; /* the for loop */
178 if (wildcard_instance == subs->dest.inst) {
179 if (!access_check(sender->string, acl, INSTWILD)) {
181 "subscr unauth %s class %s wild inst",
182 sender->string, subs->dest.classname->string);
183 free_subscription(subs); /* free this one - denied */
184 continue; /* the for loop */
189 if (realm && !bdumping) {
190 if (server && server == me_server) {
191 retval = subscr_realm_sendit(who, subs, notice, realm);
192 if (retval != ZERR_NONE) {
193 free_subscriptions(subs);
197 /* free this one, will get from ADD */
198 free_subscription(subs);
201 /* Indicates we leaked traffic back to our realm */
204 retval = triplet_register(who, &subs->dest, NULL);
205 if (retval != ZERR_NONE) {
206 if (retval == ZSRV_CLASSXISTS) {
207 free_subscription(subs); /* free this one */
209 free_subscriptions(subs);
214 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
215 LIST_INSERT(&who->subs, subs);
225 * add default subscriptions to the client's subscription chain.
234 subs = subscr_copy_def_subs(who->principal->string);
235 return add_subscriptions(who, subs, &default_notice, NULL);
242 zdbug((LOG_DEBUG, "subscr_reset()"));
244 free(default_notice.z_message);
245 default_notice.z_message = NULL;
250 subscr_copy_def_subs(person)
255 char *def_sub_area, *cp;
256 Destlist *subs, *sub;
258 if (!defaults_read) {
260 zdbug((LOG_DEBUG, "reading default subscription file"));
262 fd = open(subs_file, O_RDONLY, 0666);
264 syslog(LOG_ERR, "can't open %s:%m", subs_file);
267 retval = fstat(fd, &statbuf);
269 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
273 def_sub_area = (char *) malloc(statbuf.st_size + 1);
275 syslog(LOG_ERR, "no mem copy_def_subs");
279 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
280 if (retval != statbuf.st_size) {
281 syslog(LOG_ERR, "short read in copy_def_subs");
287 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
290 def_subs_area now points to a buffer full of subscription info.
291 Each line of the stuff is of the form:
294 Commas and newlines may not appear as part of the class,
295 instance, or recipient. XXX!
298 /* split up the subscription info */
299 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
300 if (*cp == '\n' || *cp == ',')
303 default_notice.z_message = def_sub_area;
304 default_notice.z_message_len = statbuf.st_size + 1;
305 default_notice.z_auth = 1;
309 /* needed later for access_check() */
310 default_notice.z_sender = person;
311 subs = extract_subscriptions(&default_notice);
312 /* replace any non-* recipients with "person" */
314 for (sub = subs; sub; sub = sub->next) {
315 /* if not a wildcard, replace it with person */
316 if (strcmp(sub->dest.recip->string, "*")) {
317 free_string(sub->dest.recip);
318 sub->dest.recip = make_string(person, 0);
319 } else { /* replace with null recipient */
320 free_string(sub->dest.recip);
321 sub->dest.recip = dup_string(empty);
328 * Cancel a specific set of subscriptions.
332 subscr_cancel(sin, notice)
333 struct sockaddr_in *sin;
338 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
344 zdbug((LOG_DEBUG,"subscr_cancel"));
346 who = client_find(&sin->sin_addr, notice->z_port);
353 cancel_subs = extract_subscriptions(notice);
355 return ZERR_NONE; /* no subscr -> no error */
357 for (subs = cancel_subs; subs; subs = cancel_next) {
358 cancel_next = subs->next;
359 for (client_subs = who->subs; client_subs; client_subs = client_next) {
360 client_next = client_subs->next;
361 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
362 LIST_DELETE(client_subs);
363 retval = triplet_deregister(who, &client_subs->dest, NULL);
364 if (retval == ZSRV_EMPTYCLASS &&
365 client_subs->dest.recip->string[0] == '@') {
367 realm_get_realm_by_name(client_subs->dest.recip->string
370 subscr_unsub_sendit(who, client_subs, realm);
373 free_subscription(client_subs);
380 free_subscriptions(cancel_subs);
384 zdbug((LOG_DEBUG, "found & removed"));
389 zdbug((LOG_DEBUG, "not found"));
396 subscr_realm_cancel(sin, notice, realm)
397 struct sockaddr_in *sin;
402 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
412 cancel_subs = extract_subscriptions(notice);
414 return ZERR_NONE; /* no subscr -> no error */
416 for (subs = cancel_subs; subs; subs = next) {
418 for (client_subs = realm->subs; client_subs; client_subs = next2) {
419 next2 = client_subs->next;
420 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
421 LIST_DELETE(client_subs);
422 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
423 free_subscription(client_subs);
430 free_subscriptions(cancel_subs);
434 zdbug((LOG_DEBUG, "found & removed"));
439 zdbug((LOG_DEBUG, "not found"));
446 * Cancel all the subscriptions for this client.
450 subscr_cancel_client(client)
453 Destlist *subs, *next;
458 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
459 inet_ntoa(client->addr.sin_addr)));
464 for (subs = client->subs; subs; subs = next) {
467 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
469 retval = triplet_deregister(client, &subs->dest, NULL);
470 if (retval == ZSRV_EMPTYCLASS &&
471 subs->dest.recip->string[0] == '@') {
472 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
474 subscr_unsub_sendit(client, subs, realm);
477 free_subscription(subs);
484 * Send the requester a list of his current subscriptions
488 subscr_sendlist(notice, auth, who)
491 struct sockaddr_in *who;
495 struct sockaddr_in send_to_who;
499 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
500 /* we are talking to an old client; use the old-style
501 acknowledgement-message */
502 old_compat_subscr_sendlist(notice, auth, who);
505 #endif /* OLD_COMPAT */
507 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
508 /* we are talking to a new old client; use the new-old-style
509 acknowledgement-message */
510 new_old_compat_subscr_sendlist(notice, auth, who);
513 #endif /* NEW_COMPAT */
514 answer = subscr_marshal_subs(notice, auth, who, &found);
516 send_to_who.sin_port = notice->z_port; /* Return port */
518 retval = ZSetDestAddr(&send_to_who);
519 if (retval != ZERR_NONE) {
520 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
521 error_message(retval));
527 /* XXX for now, don't do authentication */
530 notice->z_kind = ACKED;
532 /* use xmit_frag() to send each piece of the notice */
534 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
535 if (retval != ZERR_NONE)
536 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
542 subscr_marshal_subs(notice, auth, who, found)
545 struct sockaddr_in *who;
548 char **answer = NULL;
552 Destlist *subs = NULL, *sub;
557 zdbug((LOG_DEBUG, "subscr_marshal"));
561 /* Note that the following code is an incredible crock! */
563 /* We cannot send multiple packets as acknowledgements to the client,
564 since the hostmanager will ignore the later packets. So we need
565 to send directly to the client. */
567 /* Make our own copy so we can send directly back to the client */
570 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
571 /* If the client has requested his current subscriptions,
572 the message field of the notice contains the port number
573 of the client for which the sender desires the subscription
574 list. The port field is the port of the sender. */
576 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
577 if (retval != ZERR_NONE) {
578 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
579 error_message(retval));
583 client = client_find(&who->sin_addr, htons(temp));
587 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
589 zdbug((LOG_DEBUG, "gimmedefs"));
591 /* subscr_copy_def_subs allocates new pointer rings, so
592 it must be freed when finished.
593 the string areas pointed to are static, however.*/
594 subs = subscr_copy_def_subs(notice->z_sender);
597 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
604 /* check authenticity here. The user must be authentic to get
605 a list of subscriptions. If he is not subscribed to
606 anything, this if-clause fails, and he gets a response
607 indicating no subscriptions.
608 if retrieving default subscriptions, don't care about
611 if (!auth && !defsubs)
614 if (client && (strcmp(client->principal->string,
615 notice->z_sender) != 0)) {
617 "subscr_marshal: %s requests subs for %s at %s/%d",
618 notice->z_sender, client->principal->string,
619 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
624 for (sub = subs; sub; sub = sub->next)
627 /* found is now the number of subscriptions */
629 /* coalesce the subscription information into a list of char *'s */
630 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
631 if (answer == NULL) {
632 syslog(LOG_ERR, "subscr no mem(answer)");
636 for (sub = subs; sub; sub = sub->next) {
637 answer[i * NUM_FIELDS] = sub->dest.classname->string;
638 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
639 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
645 free_subscriptions(subs);
651 new_old_compat_subscr_sendlist(notice, auth, who)
654 struct sockaddr_in *who;
659 int packlen, found, count, initfound, zerofound;
662 struct sockaddr_in send_to_who;
665 new_compat_count_subscr++;
667 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
669 reply.z_kind = SERVACK;
670 reply.z_authent_len = 0; /* save some space */
674 send_to_who.sin_port = notice->z_port; /* Return port */
676 retval = ZSetDestAddr(&send_to_who);
677 if (retval != ZERR_NONE) {
678 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
679 error_message(retval));
683 /* retrieve the subscriptions */
684 answer = subscr_marshal_subs(notice, auth, who, &found);
686 /* note that when there are no subscriptions, found == 0, so
687 we needn't worry about answer being NULL since
688 ZFormatSmallRawNoticeList won't reference the pointer */
690 /* send 5 at a time until we are finished */
691 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
692 i = 0; /* pkt # counter */
694 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
697 zerofound = (found == 0);
698 while (found > 0 || zerofound) {
699 packlen = sizeof(reppacket);
700 sprintf(buf, "%d/%d", ++i, count);
701 reply.z_opcode = buf;
702 retval = ZFormatSmallRawNoticeList(&reply,
703 answer + (initfound - found)
705 ((found > 5) ? 5 : found)
707 reppacket, &packlen);
708 if (retval != ZERR_NONE) {
709 syslog(LOG_ERR, "subscr_sendlist format: %s",
710 error_message(retval));
715 retval = ZSendPacket(reppacket, packlen, 0);
716 if (retval != ZERR_NONE) {
717 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
718 error_message(retval));
727 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
732 #endif /* NEW_COMPAT */
736 old_compat_subscr_sendlist(notice, auth, who)
739 struct sockaddr_in *who;
741 Client *client = client_find(&who->sin_addr, notice->z_port);
746 int packlen, i, found = 0;
747 char **answer = NULL;
749 old_compat_count_subscr++;
751 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
752 if (client && client->subs) {
754 /* check authenticity here. The user must be authentic to get
755 a list of subscriptions. If he is not subscribed to
756 anything, the above test fails, and he gets a response
757 indicating no subscriptions */
760 clt_ack(notice, who, AUTH_FAILED);
764 for (subs = client->subs; subs; subs = subs->next)
766 /* found is now the number of subscriptions */
768 /* coalesce the subscription information into a list of char *'s */
769 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
771 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
775 for (subs = client->subs; subs; subs = subs->next) {
776 answer[i*NUM_FIELDS] = subs->dest.classname->string;
777 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
778 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
784 /* note that when there are no subscriptions, found == 0, so
785 we needn't worry about answer being NULL */
788 reply.z_kind = SERVACK;
789 reply.z_authent_len = 0; /* save some space */
792 /* if it's too long, chop off one at a time till it fits */
793 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
796 &packlen)) != ZERR_PKTLEN) {
798 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
800 if (retval != ZERR_NONE) {
801 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
802 error_message(retval));
807 retval = ZSetDestAddr(who);
808 if (retval != ZERR_NONE) {
809 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
810 error_message(retval));
815 retval = ZSendPacket(reppacket, packlen, 0);
816 if (retval != ZERR_NONE) {
817 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
818 error_message(retval));
824 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
829 #endif /* OLD_COMPAT */
832 * Send the client's subscriptions to another server
835 /* version is currently unused; if necessary later versions may key off it
836 to determine what to send to the peer (protocol changes) */
840 subscr_send_subs(client)
848 #endif /* HAVE_KRB4 */
850 char *list[7 * NUM_FIELDS];
855 zdbug((LOG_DEBUG, "send_subs"));
857 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
863 memcpy(cblock, client->session_key, sizeof(C_Block));
865 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
868 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
869 if (retval != ZERR_NONE) {
871 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
876 zdbug((LOG_DEBUG, "cblock %s", buf));
879 #endif /* HAVE_KRB4 */
880 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
881 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
882 client->principal->string, "", list, num);
883 if (retval != ZERR_NONE) {
884 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
891 for (subs = client->subs; subs; subs = subs->next) {
892 /* for each subscription */
893 list[i * NUM_FIELDS] = subs->dest.classname->string;
894 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
895 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
898 /* we only put 7 in each packet, so we don't run out of room */
899 retval = bdump_send_list_tcp(ACKED, &client->addr,
900 ZEPHYR_CTL_CLASS, "",
901 CLIENT_SUBSCRIBE, "", "", list,
903 if (retval != ZERR_NONE) {
904 syslog(LOG_ERR, "subscr_send_subs subs: %s",
905 error_message(retval));
912 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
913 "", CLIENT_SUBSCRIBE, "", "", list,
915 if (retval != ZERR_NONE) {
916 syslog(LOG_ERR, "subscr_send_subs subs: %s",
917 error_message(retval));
926 * free the memory allocated for the list of subscriptions.
930 * free the memory allocated for one subscription.
934 free_subscription(Destlist *sub)
936 free_string(sub->dest.classname);
937 free_string(sub->dest.inst);
938 free_string(sub->dest.recip);
943 free_subscriptions(subs)
948 for (; subs; subs = next) {
950 free_subscription (subs);
954 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
955 if (cp >= notice->z_message + notice->z_message_len) { \
956 syslog(LOG_WARNING, "malformed subscription %d", \
962 * Parse the message body, returning a linked list of subscriptions, or
963 * NULL if there are no subscriptions there.
967 extract_subscriptions(notice)
970 Destlist *subs = NULL, *sub;
971 char *recip, *class_name, *classinst;
972 char *cp = notice->z_message;
974 /* parse the data area for the subscriptions */
975 while (cp < notice->z_message + notice->z_message_len) {
977 if (*cp == '\0') /* we've exhausted the subscriptions */
984 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
985 class_name, classinst, cp));
987 cp += (strlen(cp) + 1);
988 if (cp > notice->z_message + notice->z_message_len) {
989 syslog(LOG_WARNING, "malformed sub 3");
992 sub = (Destlist *) malloc(sizeof(Destlist));
994 syslog(LOG_WARNING, "ex_subs: no mem 2");
997 sub->dest.classname = make_string(class_name, 1);
998 sub->dest.inst = make_string(classinst, 1);
999 /* Nuke @REALM if REALM is us. */
1000 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
1001 sub->dest.recip = make_string("", 0);
1003 sub->dest.recip = make_string(recip, 0);
1004 LIST_INSERT(&subs, sub);
1010 * print subscriptions in subs onto fp.
1011 * assumed to be called with SIGFPE blocked
1012 * (true if called from signal handler)
1016 subscr_dump_subs(fp, subs)
1022 if (!subs) /* no subscriptions to dump */
1025 for (; subs; subs = subs->next) {
1027 dump_quote(subs->dest.classname->string, fp);
1029 dump_quote(subs->dest.inst->string, fp);
1031 dump_quote(subs->dest.recip->string, fp);
1036 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1037 if (cp >= notice->z_message + notice->z_message_len) { \
1038 syslog(LOG_WARNING, "malformed subscription %d", \
1040 return (ZERR_NONE); \
1043 /* As it exists, this function expects to take only the first sub from the
1044 * Destlist. At some point, it and the calling code should be replaced */
1046 subscr_realm_sendit(who, subs, notice, realm)
1058 char addr[16]; /* xxx.xxx.xxx.xxx max */
1062 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1066 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1067 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1070 /* convert the address to a string of the form x.x.x.x/port */
1071 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1072 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1073 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1075 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1076 error_message(retval));
1082 text[2] = subs->dest.classname->string;
1083 text[3] = subs->dest.inst->string;
1084 text[4] = subs->dest.recip->string;
1086 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1087 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1089 /* format snotice */
1090 memset (&snotice, 0, sizeof(snotice));
1091 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1092 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1093 snotice.z_port = srv_addr.sin_port;
1095 snotice.z_class = ZEPHYR_CTL_CLASS;
1097 snotice.z_recipient = "";
1098 snotice.z_kind = ACKED;
1099 snotice.z_num_other_fields = 0;
1100 snotice.z_default_format = "";
1101 snotice.z_sender = who->principal->string;
1102 snotice.z_recipient = notice->z_recipient;
1103 snotice.z_default_format = notice->z_default_format;
1105 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1106 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1108 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1109 error_message(retval));
1115 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1116 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1117 error_message(retval));
1123 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1125 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1131 /* Called from subscr_realm and subscr_foreign_user */
1133 subscr_add_raw(client, realm, newsubs)
1138 Destlist *subs, *subs2, *subs3, **head;
1142 zdbug((LOG_DEBUG, "subscr_add_raw"));
1144 head = (realm) ? &realm->subs : &client->subs;
1146 /* Loop over the new subscriptions. */
1147 for (subs = newsubs; subs; subs = subs2) {
1150 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1152 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1154 retval = triplet_register(client, &subs->dest, realm);
1155 if (retval != ZERR_NONE) {
1156 free_subscription(subs);
1157 if (retval == ZSRV_CLASSXISTS) {
1160 free_subscriptions(subs2);
1166 realm_get_realm_by_name(subs->dest.recip->string + 1);
1168 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1170 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1172 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1173 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1174 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1176 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1177 sub->dest.classname->string, sub->dest.inst->string,
1178 sub->dest.recip->string, remrealm->name));
1180 LIST_INSERT(&remrealm->remsubs, sub);
1185 LIST_INSERT(head, subs);
1190 /* Called from bdump_recv_loop to decapsulate realm subs */
1192 subscr_realm(realm, notice)
1198 newsubs = extract_subscriptions(notice);
1201 syslog(LOG_WARNING, "empty subs in subscr_realm");
1205 return(subscr_add_raw(realm->client, realm, newsubs));
1208 /* Like realm_sendit, this only takes one item from subs */
1210 subscr_unsub_sendit(who, subs, realm)
1221 Destlist *subsp, *subsn;
1223 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1224 subsn = subsp->next;
1225 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1227 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1228 subsp->dest.classname->string, subsp->dest.inst->string,
1229 subsp->dest.recip->string, realm->name));
1232 free_subscription(subsp);
1237 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1238 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1242 list[0] = subs->dest.classname->string;
1243 list[1] = subs->dest.inst->string;
1246 unotice.z_class = ZEPHYR_CTL_CLASS;
1247 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1248 unotice.z_opcode = REALM_UNSUBSCRIBE;
1249 unotice.z_recipient = "";
1250 unotice.z_kind = ACKED;
1252 unotice.z_sender = "";
1253 unotice.z_port = srv_addr.sin_port;
1254 unotice.z_num_other_fields = 0;
1255 unotice.z_default_format = "";
1257 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1258 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1259 error_message(retval));
1265 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1266 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1267 error_message(retval));
1271 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1275 /* Called from bump_send_loop by way of realm_send_realms */
1277 subscr_send_realm_subs(realm)
1281 Destlist *subs, *next;
1283 char *list[7 * NUM_FIELDS];
1288 zdbug((LOG_DEBUG, "send_realm_subs"));
1291 strcpy(buf, realm->name);
1294 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1295 "", ADMIN_NEWREALM, "", "", list, num);
1296 if (retval != ZERR_NONE) {
1297 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1304 for (subs=realm->subs; subs; subs = next) {
1307 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1308 subs->dest.inst->string, subs->dest.recip->string));
1310 /* for each subscription */
1311 list[i * NUM_FIELDS] = subs->dest.classname->string;
1312 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1313 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1316 /* we only put 7 in each packet, so we don't run out of room */
1317 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1318 ZEPHYR_CTL_CLASS, "",
1319 REALM_SUBSCRIBE, "", "", list,
1321 if (retval != ZERR_NONE) {
1322 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1323 error_message(retval));
1330 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1331 "", REALM_SUBSCRIBE, "", "", list,
1333 if (retval != ZERR_NONE) {
1334 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1335 error_message(retval));
1344 subscr_realm_subs(realm)
1348 Destlist *subs, *next;
1350 char *text[2 + NUM_FIELDS];
1351 unsigned short num = 0;
1360 zdbug((LOG_DEBUG, "realm_subs"));
1363 if (!realm->remsubs)
1366 for (subs=realm->remsubs; subs; subs = next) {
1369 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1370 subs->dest.inst->string, subs->dest.recip->string));
1374 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1375 &num, sizeof(u_short))) != ZERR_NONE)
1377 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1378 error_message(retval));
1382 text[0] = "0.0.0.0";
1384 text[2] = subs->dest.classname->string;
1385 text[3] = subs->dest.inst->string;
1386 text[4] = subs->dest.recip->string;
1388 /* format snotice */
1389 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1390 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1392 snotice.z_class = ZEPHYR_CTL_CLASS;
1394 snotice.z_recipient = "";
1395 snotice.z_kind = ACKED;
1396 snotice.z_num_other_fields = 0;
1397 snotice.z_default_format = "";
1398 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1399 resubmit them as the sender. */
1400 clientp = triplet_lookup(&subs->dest);
1402 snotice.z_sender = "";
1404 snotice.z_sender = (*clientp)->principal->string;
1405 snotice.z_default_format = "";
1407 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1408 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1410 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1411 error_message(retval));
1415 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1416 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1417 error_message(retval));
1421 realm_handoff(&snotice, 1, NULL, realm, 0);
1428 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1430 subscr_check_foreign_subs(notice, who, server, realm, newsubs)
1432 struct sockaddr_in *who;
1437 Destlist *subs, *subs2, *next;
1447 for (subs = newsubs; subs; subs = subs->next)
1453 sender = make_string(notice->z_sender, 0);
1455 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1457 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1458 free_string(sender);
1462 /* grab the client information from the incoming message */
1463 cp = notice->z_message;
1472 for (subs = newsubs; subs; subs = next) {
1475 if (subs->dest.recip->string[0] != '\0') {
1476 rlm = realm_which_realm(who);
1477 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1478 subs->dest.recip->string,
1479 sender->string, rlm->name);
1482 acl = class_get_acl(subs->dest.classname);
1484 rlm = realm_which_realm(who);
1485 if (rlm && server == me_server) {
1486 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1487 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1488 sender->string, rlm->name,
1489 subs->dest.classname->string);
1490 free_subscriptions(newsubs);
1491 free_string(sender);
1493 return ZSRV_CLASSRESTRICTED;
1496 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1497 syslog(LOG_WARNING, "subscr unauth %s class %s",
1498 sender->string, subs->dest.classname->string);
1499 continue; /* the for loop */
1501 if (wildcard_instance == subs->dest.inst) {
1502 if (!access_check(sender->string, acl, INSTWILD)) {
1504 "subscr unauth %s class %s wild inst",
1505 sender->string, subs->dest.classname->string);
1511 /* okay to subscribe. save for return trip */
1512 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1513 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1514 text[found*NUM_FIELDS + 4] = "";
1517 retval = triplet_register(realm->client, &subs->dest, realm);
1519 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1520 subs->dest.inst->string, subs->dest.recip->string));
1523 if (retval != ZERR_NONE) {
1524 if (retval == ZSRV_CLASSXISTS) {
1527 free_subscriptions(newsubs); /* subs->next XXX */
1528 free_string(sender);
1533 LIST_INSERT(&realm->subs, subs);
1535 /* don't send confirmation if we're not the initial server contacted */
1536 if (!(server_which_server(who) || found == 0)) {
1538 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1539 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1540 snotice.z_port = srv_addr.sin_port;
1541 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1542 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1543 error_message(retval));
1544 free_string(sender);
1548 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1549 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1550 error_message(retval));
1551 free_string(sender);
1556 realm_handoff(&snotice, 1, who, realm, 0);
1559 free_string(sender);
1564 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1565 Code_t subscr_foreign_user(notice, who, server, realm)
1567 struct sockaddr_in *who;
1571 Destlist *newsubs, *temp;
1576 struct sockaddr_in newwho;
1577 char *cp, *tp0, *tp1;
1578 char rlm_recipient[REALM_SZ + 1];
1581 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1584 tp0 = cp = notice->z_message;
1586 newwho.sin_addr.s_addr = inet_addr(cp);
1587 if (newwho.sin_addr.s_addr == -1) {
1588 syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1597 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1600 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1601 error_message(status));
1607 snotice.z_message = cp;
1608 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1610 newsubs = extract_subscriptions(&snotice);
1612 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1616 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1617 /* this was approved by the other realm, add subscriptions */
1619 if (!strcmp(tp0, "0.0.0.0")) {
1620 /* skip bogus ADD reply from subscr_realm_subs */
1621 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1625 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1626 client = client_find(&newwho.sin_addr, snotice.z_port);
1627 if (client == (Client *)0) {
1628 syslog(LOG_WARNING, "no client at %s/%d",
1629 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1630 free_subscriptions(newsubs);
1634 /* translate the recipient to represent the foreign realm */
1635 sprintf(rlm_recipient, "@%s", realm->name);
1636 for (temp = newsubs; temp; temp = temp->next) {
1638 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1640 temp->dest.recip = make_string(rlm_recipient, 0);
1643 status = subscr_add_raw(client, (Realm *)0, newsubs);
1644 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1645 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1646 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1648 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",