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: subscr.c,v 1.58 2001/03/01 00:47:05 zacheiss Exp $";
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 && server && server == me_server) {
190 retval = subscr_realm_sendit(who, subs, notice, realm);
191 if (retval != ZERR_NONE) {
192 free_subscriptions(subs);
196 free_subscription(subs); /* free this one, will get from ADD */
199 retval = triplet_register(who, &subs->dest, NULL);
200 if (retval != ZERR_NONE) {
201 if (retval == ZSRV_CLASSXISTS) {
202 free_subscription(subs); /* free this one */
204 free_subscriptions(subs);
209 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
210 LIST_INSERT(&who->subs, subs);
220 * add default subscriptions to the client's subscription chain.
229 subs = subscr_copy_def_subs(who->principal->string);
230 return add_subscriptions(who, subs, &default_notice, NULL);
237 zdbug((LOG_DEBUG, "subscr_reset()"));
239 free(default_notice.z_message);
240 default_notice.z_message = NULL;
245 subscr_copy_def_subs(person)
250 char *def_sub_area, *cp;
251 Destlist *subs, *sub;
253 if (!defaults_read) {
255 zdbug((LOG_DEBUG, "reading default subscription file"));
257 fd = open(subs_file, O_RDONLY, 0666);
259 syslog(LOG_ERR, "can't open %s:%m", subs_file);
262 retval = fstat(fd, &statbuf);
264 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
268 def_sub_area = (char *) malloc(statbuf.st_size + 1);
270 syslog(LOG_ERR, "no mem copy_def_subs");
274 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
275 if (retval != statbuf.st_size) {
276 syslog(LOG_ERR, "short read in copy_def_subs");
282 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
285 def_subs_area now points to a buffer full of subscription info.
286 Each line of the stuff is of the form:
289 Commas and newlines may not appear as part of the class,
290 instance, or recipient. XXX!
293 /* split up the subscription info */
294 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
295 if (*cp == '\n' || *cp == ',')
298 default_notice.z_message = def_sub_area;
299 default_notice.z_message_len = statbuf.st_size + 1;
300 default_notice.z_auth = 1;
304 /* needed later for access_check() */
305 default_notice.z_sender = person;
306 subs = extract_subscriptions(&default_notice);
307 /* replace any non-* recipients with "person" */
309 for (sub = subs; sub; sub = sub->next) {
310 /* if not a wildcard, replace it with person */
311 if (strcmp(sub->dest.recip->string, "*")) {
312 free_string(sub->dest.recip);
313 sub->dest.recip = make_string(person, 0);
314 } else { /* replace with null recipient */
315 free_string(sub->dest.recip);
316 sub->dest.recip = dup_string(empty);
323 * Cancel a specific set of subscriptions.
327 subscr_cancel(sin, notice)
328 struct sockaddr_in *sin;
333 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
339 zdbug((LOG_DEBUG,"subscr_cancel"));
341 who = client_find(&sin->sin_addr, notice->z_port);
348 cancel_subs = extract_subscriptions(notice);
350 return ZERR_NONE; /* no subscr -> no error */
352 for (subs = cancel_subs; subs; subs = cancel_next) {
353 cancel_next = subs->next;
354 for (client_subs = who->subs; client_subs; client_subs = client_next) {
355 client_next = client_subs->next;
356 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
357 LIST_DELETE(client_subs);
358 retval = triplet_deregister(who, &client_subs->dest, NULL);
359 if (retval == ZSRV_EMPTYCLASS &&
360 client_subs->dest.recip->string[0] == '@') {
362 realm_get_realm_by_name(client_subs->dest.recip->string
365 subscr_unsub_sendit(who, client_subs, realm);
368 free_subscription(client_subs);
375 free_subscriptions(cancel_subs);
379 zdbug((LOG_DEBUG, "found & removed"));
384 zdbug((LOG_DEBUG, "not found"));
391 subscr_realm_cancel(sin, notice, realm)
392 struct sockaddr_in *sin;
397 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
407 cancel_subs = extract_subscriptions(notice);
409 return ZERR_NONE; /* no subscr -> no error */
411 for (subs = cancel_subs; subs; subs = next) {
413 for (client_subs = realm->subs; client_subs; client_subs = next2) {
414 next2 = client_subs->next;
415 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
416 LIST_DELETE(client_subs);
417 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
418 free_subscription(client_subs);
425 free_subscriptions(cancel_subs);
429 zdbug((LOG_DEBUG, "found & removed"));
434 zdbug((LOG_DEBUG, "not found"));
441 * Cancel all the subscriptions for this client.
445 subscr_cancel_client(client)
448 Destlist *subs, *next;
453 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
454 inet_ntoa(client->addr.sin_addr)));
459 for (subs = client->subs; subs; subs = next) {
462 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
464 retval = triplet_deregister(client, &subs->dest, NULL);
465 if (retval == ZSRV_EMPTYCLASS &&
466 subs->dest.recip->string[0] == '@') {
467 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
469 subscr_unsub_sendit(client, subs, realm);
472 free_subscription(subs);
479 * Send the requester a list of his current subscriptions
483 subscr_sendlist(notice, auth, who)
486 struct sockaddr_in *who;
490 struct sockaddr_in send_to_who;
494 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
495 /* we are talking to an old client; use the old-style
496 acknowledgement-message */
497 old_compat_subscr_sendlist(notice, auth, who);
500 #endif /* OLD_COMPAT */
502 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
503 /* we are talking to a new old client; use the new-old-style
504 acknowledgement-message */
505 new_old_compat_subscr_sendlist(notice, auth, who);
508 #endif /* NEW_COMPAT */
509 answer = subscr_marshal_subs(notice, auth, who, &found);
511 send_to_who.sin_port = notice->z_port; /* Return port */
513 retval = ZSetDestAddr(&send_to_who);
514 if (retval != ZERR_NONE) {
515 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
516 error_message(retval));
522 /* XXX for now, don't do authentication */
525 notice->z_kind = ACKED;
527 /* use xmit_frag() to send each piece of the notice */
529 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
530 if (retval != ZERR_NONE)
531 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
537 subscr_marshal_subs(notice, auth, who, found)
540 struct sockaddr_in *who;
543 char **answer = NULL;
547 Destlist *subs = NULL, *sub;
552 zdbug((LOG_DEBUG, "subscr_marshal"));
556 /* Note that the following code is an incredible crock! */
558 /* We cannot send multiple packets as acknowledgements to the client,
559 since the hostmanager will ignore the later packets. So we need
560 to send directly to the client. */
562 /* Make our own copy so we can send directly back to the client */
565 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
566 /* If the client has requested his current subscriptions,
567 the message field of the notice contains the port number
568 of the client for which the sender desires the subscription
569 list. The port field is the port of the sender. */
571 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
572 if (retval != ZERR_NONE) {
573 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
574 error_message(retval));
578 client = client_find(&who->sin_addr, htons(temp));
582 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
584 zdbug((LOG_DEBUG, "gimmedefs"));
586 /* subscr_copy_def_subs allocates new pointer rings, so
587 it must be freed when finished.
588 the string areas pointed to are static, however.*/
589 subs = subscr_copy_def_subs(notice->z_sender);
592 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
599 /* check authenticity here. The user must be authentic to get
600 a list of subscriptions. If he is not subscribed to
601 anything, this if-clause fails, and he gets a response
602 indicating no subscriptions.
603 if retrieving default subscriptions, don't care about
606 if (!auth && !defsubs)
609 if (client && (strcmp(client->principal->string,
610 notice->z_sender) != 0)) {
612 "subscr_marshal: %s requests subs for %s at %s/%d",
613 notice->z_sender, client->principal->string,
614 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
619 for (sub = subs; sub; sub = sub->next)
622 /* found is now the number of subscriptions */
624 /* coalesce the subscription information into a list of char *'s */
625 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
626 if (answer == NULL) {
627 syslog(LOG_ERR, "subscr no mem(answer)");
631 for (sub = subs; sub; sub = sub->next) {
632 answer[i * NUM_FIELDS] = sub->dest.classname->string;
633 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
634 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
640 free_subscriptions(subs);
646 new_old_compat_subscr_sendlist(notice, auth, who)
649 struct sockaddr_in *who;
654 int packlen, found, count, initfound, zerofound;
657 struct sockaddr_in send_to_who;
660 new_compat_count_subscr++;
662 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
664 reply.z_kind = SERVACK;
665 reply.z_authent_len = 0; /* save some space */
669 send_to_who.sin_port = notice->z_port; /* Return port */
671 retval = ZSetDestAddr(&send_to_who);
672 if (retval != ZERR_NONE) {
673 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
674 error_message(retval));
678 /* retrieve the subscriptions */
679 answer = subscr_marshal_subs(notice, auth, who, &found);
681 /* note that when there are no subscriptions, found == 0, so
682 we needn't worry about answer being NULL since
683 ZFormatSmallRawNoticeList won't reference the pointer */
685 /* send 5 at a time until we are finished */
686 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
687 i = 0; /* pkt # counter */
689 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
692 zerofound = (found == 0);
693 while (found > 0 || zerofound) {
694 packlen = sizeof(reppacket);
695 sprintf(buf, "%d/%d", ++i, count);
696 reply.z_opcode = buf;
697 retval = ZFormatSmallRawNoticeList(&reply,
698 answer + (initfound - found)
700 ((found > 5) ? 5 : found)
702 reppacket, &packlen);
703 if (retval != ZERR_NONE) {
704 syslog(LOG_ERR, "subscr_sendlist format: %s",
705 error_message(retval));
710 retval = ZSendPacket(reppacket, packlen, 0);
711 if (retval != ZERR_NONE) {
712 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
713 error_message(retval));
722 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
727 #endif /* NEW_COMPAT */
731 old_compat_subscr_sendlist(notice, auth, who)
734 struct sockaddr_in *who;
736 Client *client = client_find(&who->sin_addr, notice->z_port);
741 int packlen, i, found = 0;
742 char **answer = NULL;
744 old_compat_count_subscr++;
746 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
747 if (client && client->subs) {
749 /* check authenticity here. The user must be authentic to get
750 a list of subscriptions. If he is not subscribed to
751 anything, the above test fails, and he gets a response
752 indicating no subscriptions */
755 clt_ack(notice, who, AUTH_FAILED);
759 for (subs = client->subs; subs; subs = subs->next)
761 /* found is now the number of subscriptions */
763 /* coalesce the subscription information into a list of char *'s */
764 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
766 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
770 for (subs = client->subs; subs; subs = subs->next) {
771 answer[i*NUM_FIELDS] = subs->dest.classname->string;
772 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
773 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
779 /* note that when there are no subscriptions, found == 0, so
780 we needn't worry about answer being NULL */
783 reply.z_kind = SERVACK;
784 reply.z_authent_len = 0; /* save some space */
787 /* if it's too long, chop off one at a time till it fits */
788 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
791 &packlen)) != ZERR_PKTLEN) {
793 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
795 if (retval != ZERR_NONE) {
796 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
797 error_message(retval));
802 retval = ZSetDestAddr(who);
803 if (retval != ZERR_NONE) {
804 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
805 error_message(retval));
810 retval = ZSendPacket(reppacket, packlen, 0);
811 if (retval != ZERR_NONE) {
812 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
813 error_message(retval));
819 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
824 #endif /* OLD_COMPAT */
827 * Send the client's subscriptions to another server
830 /* version is currently unused; if necessary later versions may key off it
831 to determine what to send to the peer (protocol changes) */
835 subscr_send_subs(client)
843 #endif /* HAVE_KRB4 */
845 char *list[7 * NUM_FIELDS];
850 zdbug((LOG_DEBUG, "send_subs"));
852 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
858 memcpy(cblock, client->session_key, sizeof(C_Block));
860 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
863 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
864 if (retval != ZERR_NONE) {
866 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
871 zdbug((LOG_DEBUG, "cblock %s", buf));
874 #endif /* HAVE_KRB4 */
875 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
876 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
877 client->principal->string, "", list, num);
878 if (retval != ZERR_NONE) {
879 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
886 for (subs = client->subs; subs; subs = subs->next) {
887 /* for each subscription */
888 list[i * NUM_FIELDS] = subs->dest.classname->string;
889 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
890 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
893 /* we only put 7 in each packet, so we don't run out of room */
894 retval = bdump_send_list_tcp(ACKED, &client->addr,
895 ZEPHYR_CTL_CLASS, "",
896 CLIENT_SUBSCRIBE, "", "", list,
898 if (retval != ZERR_NONE) {
899 syslog(LOG_ERR, "subscr_send_subs subs: %s",
900 error_message(retval));
907 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
908 "", CLIENT_SUBSCRIBE, "", "", list,
910 if (retval != ZERR_NONE) {
911 syslog(LOG_ERR, "subscr_send_subs subs: %s",
912 error_message(retval));
921 * free the memory allocated for the list of subscriptions.
925 * free the memory allocated for one subscription.
929 free_subscription(Destlist *sub)
931 free_string(sub->dest.classname);
932 free_string(sub->dest.inst);
933 free_string(sub->dest.recip);
938 free_subscriptions(subs)
943 for (; subs; subs = next) {
945 free_subscription (subs);
949 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
950 if (cp >= notice->z_message + notice->z_message_len) { \
951 syslog(LOG_WARNING, "malformed subscription %d", \
957 * Parse the message body, returning a linked list of subscriptions, or
958 * NULL if there are no subscriptions there.
962 extract_subscriptions(notice)
965 Destlist *subs = NULL, *sub;
966 char *recip, *class_name, *classinst;
967 char *cp = notice->z_message;
969 /* parse the data area for the subscriptions */
970 while (cp < notice->z_message + notice->z_message_len) {
972 if (*cp == '\0') /* we've exhausted the subscriptions */
979 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
980 class_name, classinst, cp));
982 cp += (strlen(cp) + 1);
983 if (cp > notice->z_message + notice->z_message_len) {
984 syslog(LOG_WARNING, "malformed sub 3");
987 sub = (Destlist *) malloc(sizeof(Destlist));
989 syslog(LOG_WARNING, "ex_subs: no mem 2");
992 sub->dest.classname = make_string(class_name, 1);
993 sub->dest.inst = make_string(classinst, 1);
994 /* Nuke @REALM if REALM is us. */
995 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
996 sub->dest.recip = make_string("", 0);
998 sub->dest.recip = make_string(recip, 0);
999 LIST_INSERT(&subs, sub);
1005 * print subscriptions in subs onto fp.
1006 * assumed to be called with SIGFPE blocked
1007 * (true if called from signal handler)
1011 subscr_dump_subs(fp, subs)
1017 if (!subs) /* no subscriptions to dump */
1020 for (; subs; subs = subs->next) {
1022 dump_quote(subs->dest.classname->string, fp);
1024 dump_quote(subs->dest.inst->string, fp);
1026 dump_quote(subs->dest.recip->string, fp);
1031 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1032 if (cp >= notice->z_message + notice->z_message_len) { \
1033 syslog(LOG_WARNING, "malformed subscription %d", \
1035 return (ZERR_NONE); \
1038 /* As it exists, this function expects to take only the first sub from the
1039 * Destlist. At some point, it and the calling code should be replaced */
1041 subscr_realm_sendit(who, subs, notice, realm)
1053 char addr[16]; /* xxx.xxx.xxx.xxx max */
1057 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1061 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1062 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1065 /* convert the address to a string of the form x.x.x.x/port */
1066 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1067 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1068 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1070 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1071 error_message(retval));
1077 text[2] = subs->dest.classname->string;
1078 text[3] = subs->dest.inst->string;
1079 text[4] = subs->dest.recip->string;
1081 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1082 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1084 /* format snotice */
1085 memset (&snotice, 0, sizeof(snotice));
1086 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1087 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1088 snotice.z_port = srv_addr.sin_port;
1090 snotice.z_class = ZEPHYR_CTL_CLASS;
1092 snotice.z_recipient = "";
1093 snotice.z_kind = ACKED;
1094 snotice.z_num_other_fields = 0;
1095 snotice.z_default_format = "";
1096 snotice.z_sender = who->principal->string;
1097 snotice.z_recipient = notice->z_recipient;
1098 snotice.z_default_format = notice->z_default_format;
1100 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1101 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1103 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1104 error_message(retval));
1110 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1111 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1112 error_message(retval));
1118 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1120 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1126 /* Called from subscr_realm and subscr_foreign_user */
1128 subscr_add_raw(client, realm, newsubs)
1133 Destlist *subs, *subs2, *subs3, **head;
1137 zdbug((LOG_DEBUG, "subscr_add_raw"));
1139 head = (realm) ? &realm->subs : &client->subs;
1141 /* Loop over the new subscriptions. */
1142 for (subs = newsubs; subs; subs = subs2) {
1145 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1147 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1149 retval = triplet_register(client, &subs->dest, realm);
1150 if (retval != ZERR_NONE) {
1151 free_subscription(subs);
1152 if (retval == ZSRV_CLASSXISTS) {
1155 free_subscriptions(subs2);
1161 realm_get_realm_by_name(subs->dest.recip->string + 1);
1163 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1165 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1167 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1168 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1169 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1171 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1172 sub->dest.classname->string, sub->dest.inst->string,
1173 sub->dest.recip->string, remrealm->name));
1175 LIST_INSERT(&remrealm->remsubs, sub);
1180 LIST_INSERT(head, subs);
1185 /* Called from bdump_recv_loop to decapsulate realm subs */
1187 subscr_realm(realm, notice)
1193 newsubs = extract_subscriptions(notice);
1196 syslog(LOG_WARNING, "empty subs in subscr_realm");
1200 return(subscr_add_raw(realm->client, realm, newsubs));
1203 /* Like realm_sendit, this only takes one item from subs */
1205 subscr_unsub_sendit(who, subs, realm)
1216 Destlist *subsp, *subsn;
1218 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1219 subsn = subsp->next;
1220 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1222 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1223 subsp->dest.classname->string, subsp->dest.inst->string,
1224 subsp->dest.recip->string, realm->name));
1227 free_subscription(subsp);
1232 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1233 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1237 list[0] = subs->dest.classname->string;
1238 list[1] = subs->dest.inst->string;
1241 unotice.z_class = ZEPHYR_CTL_CLASS;
1242 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1243 unotice.z_opcode = REALM_UNSUBSCRIBE;
1244 unotice.z_recipient = "";
1245 unotice.z_kind = ACKED;
1247 unotice.z_sender = "";
1248 unotice.z_port = srv_addr.sin_port;
1249 unotice.z_num_other_fields = 0;
1250 unotice.z_default_format = "";
1252 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1253 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1254 error_message(retval));
1260 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1261 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1262 error_message(retval));
1266 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1270 /* Called from bump_send_loop by way of realm_send_realms */
1272 subscr_send_realm_subs(realm)
1276 Destlist *subs, *next;
1278 char *list[7 * NUM_FIELDS];
1283 zdbug((LOG_DEBUG, "send_realm_subs"));
1286 strcpy(buf, realm->name);
1289 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1290 "", ADMIN_NEWREALM, "", "", list, num);
1291 if (retval != ZERR_NONE) {
1292 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1299 for (subs=realm->subs; subs; subs = next) {
1302 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1303 subs->dest.inst->string, subs->dest.recip->string));
1305 /* for each subscription */
1306 list[i * NUM_FIELDS] = subs->dest.classname->string;
1307 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1308 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1311 /* we only put 7 in each packet, so we don't run out of room */
1312 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1313 ZEPHYR_CTL_CLASS, "",
1314 REALM_SUBSCRIBE, "", "", list,
1316 if (retval != ZERR_NONE) {
1317 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1318 error_message(retval));
1325 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1326 "", REALM_SUBSCRIBE, "", "", list,
1328 if (retval != ZERR_NONE) {
1329 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1330 error_message(retval));
1339 subscr_realm_subs(realm)
1343 Destlist *subs, *next;
1345 char *text[2 + NUM_FIELDS];
1346 unsigned short num = 0;
1355 zdbug((LOG_DEBUG, "realm_subs"));
1358 if (!realm->remsubs)
1361 for (subs=realm->remsubs; subs; subs = next) {
1364 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1365 subs->dest.inst->string, subs->dest.recip->string));
1369 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1370 &num, sizeof(u_short))) != ZERR_NONE)
1372 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1373 error_message(retval));
1377 text[0] = "0.0.0.0";
1379 text[2] = subs->dest.classname->string;
1380 text[3] = subs->dest.inst->string;
1381 text[4] = subs->dest.recip->string;
1383 /* format snotice */
1384 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1385 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1387 snotice.z_class = ZEPHYR_CTL_CLASS;
1389 snotice.z_recipient = "";
1390 snotice.z_kind = ACKED;
1391 snotice.z_num_other_fields = 0;
1392 snotice.z_default_format = "";
1393 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1394 resubmit them as the sender. */
1395 clientp = triplet_lookup(&subs->dest);
1397 snotice.z_sender = "";
1399 snotice.z_sender = (*clientp)->principal->string;
1400 snotice.z_default_format = "";
1402 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1403 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1405 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1406 error_message(retval));
1410 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1411 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1412 error_message(retval));
1416 realm_handoff(&snotice, 1, NULL, realm, 0);
1423 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1425 subscr_check_foreign_subs(notice, who, server, realm, newsubs)
1427 struct sockaddr_in *who;
1432 Destlist *subs, *subs2, *next;
1442 for (subs = newsubs; subs; subs = subs->next)
1448 sender = make_string(notice->z_sender, 0);
1450 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1452 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1453 free_string(sender);
1457 /* grab the client information from the incoming message */
1458 cp = notice->z_message;
1467 for (subs = newsubs; subs; subs = next) {
1469 acl = class_get_acl(subs->dest.classname);
1472 rlm = realm_which_realm(who);
1473 if (rlm && server == me_server) {
1474 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1475 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1476 sender->string, rlm->name,
1477 subs->dest.classname->string);
1481 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1482 syslog(LOG_WARNING, "subscr unauth %s class %s",
1483 sender->string, subs->dest.classname->string);
1484 continue; /* the for loop */
1486 if (wildcard_instance == subs->dest.inst) {
1487 if (!access_check(sender->string, acl, INSTWILD)) {
1489 "subscr unauth %s class %s wild inst",
1490 sender->string, subs->dest.classname->string);
1496 /* okay to subscribe. save for return trip */
1497 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1498 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1499 text[found*NUM_FIELDS + 4] = "";
1502 retval = triplet_register(realm->client, &subs->dest, realm);
1504 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1505 subs->dest.inst->string, subs->dest.recip->string));
1508 if (retval != ZERR_NONE) {
1509 if (retval == ZSRV_CLASSXISTS) {
1512 free_subscriptions(newsubs); /* subs->next XXX */
1513 free_string(sender);
1518 LIST_INSERT(&realm->subs, subs);
1520 /* don't send confirmation if we're not the initial server contacted */
1521 if (!(server_which_server(who) || found == 0)) {
1523 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1524 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1525 snotice.z_port = srv_addr.sin_port;
1526 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1527 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1528 error_message(retval));
1529 free_string(sender);
1533 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1534 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1535 error_message(retval));
1536 free_string(sender);
1541 realm_handoff(&snotice, 1, who, realm, 0);
1544 free_string(sender);
1549 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1550 Code_t subscr_foreign_user(notice, who, server, realm)
1552 struct sockaddr_in *who;
1556 Destlist *newsubs, *temp;
1561 struct sockaddr_in newwho;
1562 char *cp, *tp0, *tp1;
1563 char rlm_recipient[REALM_SZ + 1];
1566 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1569 tp0 = cp = notice->z_message;
1571 newwho.sin_addr.s_addr = inet_addr(cp);
1572 if (newwho.sin_addr.s_addr == -1) {
1573 syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1582 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1585 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1586 error_message(status));
1592 snotice.z_message = cp;
1593 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1595 newsubs = extract_subscriptions(&snotice);
1597 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1601 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1602 /* this was approved by the other realm, add subscriptions */
1604 if (!strcmp(tp0, "0.0.0.0")) {
1605 /* skip bogus ADD reply from subscr_realm_subs */
1606 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1610 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1611 client = client_find(&newwho.sin_addr, snotice.z_port);
1612 if (client == (Client *)0) {
1613 syslog(LOG_WARNING, "no client at %s/%d",
1614 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1615 free_subscriptions(newsubs);
1619 /* translate the recipient to represent the foreign realm */
1620 sprintf(rlm_recipient, "@%s", realm->name);
1621 for (temp = newsubs; temp; temp = temp->next) {
1623 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1625 temp->dest.recip = make_string(rlm_recipient, 0);
1628 status = subscr_add_raw(client, (Realm *)0, newsubs);
1629 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1630 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1631 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1633 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",