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(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(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 static Code_t add_subscriptions(Client *who, Destlist *subs_queue,
88 ZNotice_t *notice, Server *server);
89 static Destlist *extract_subscriptions(ZNotice_t *notice);
90 static void free_subscriptions(Destlist *subs);
91 static void free_subscription(Destlist *sub);
92 static char **subscr_marshal_subs(ZNotice_t *notice, int auth,
93 struct sockaddr_in *who,
95 static Destlist *subscr_copy_def_subs(char *person);
96 static Code_t subscr_realm_sendit(Client *who, Destlist *subs,
97 ZNotice_t *notice, ZRealm *realm);
98 static void subscr_unsub_realms(Destlist *newsubs);
99 static void subscr_unsub_sendit(Client *who, Destlist *subs,
101 static int cl_match (Destlist*, Client *);
103 static int defaults_read = 0; /* set to 1 if the default subs
105 static ZNotice_t default_notice; /* contains default subscriptions */
107 String *wildcard_instance;
110 /* WARNING: make sure this is the same as the number of strings you */
111 /* plan to hand back to the user in response to a subscription check, */
112 /* else you will lose. See subscr_sendlist() */
116 * subscribe the client to types described in notice.
120 subscr_subscribe(Client *who,
126 subs = extract_subscriptions(notice);
127 return add_subscriptions(who, subs, notice, server);
131 add_subscriptions(Client *who,
140 ZRealm *realm = NULL;
143 return ZERR_NONE; /* no subscr -> no error */
145 sender = make_string(notice->z_sender, 0);
147 /* Loop over the new subscriptions. */
148 for (; subs; subs = next) {
151 zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
152 subs->dest.inst->string, subs->dest.recip->string));
154 /* check the recipient for a realm which isn't ours */
156 if (subs->dest.recip->string[0] == '@' &&
157 strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
158 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
160 if (subs->dest.recip != empty && subs->dest.recip != sender
161 && subs->dest.recip->string[0] != '@') {
162 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
163 sender->string, subs->dest.recip->string);
164 free_subscription(subs); /* free this one - denied */
165 continue; /* the for loop */
167 acl = class_get_acl(subs->dest.classname);
169 if (!access_check(sender->string, acl, SUBSCRIBE)) {
170 syslog(LOG_WARNING, "subscr unauth %s class %s",
171 sender->string, subs->dest.classname->string);
172 free_subscription(subs); /* free this one - denied */
173 continue; /* the for loop */
175 if (wildcard_instance == subs->dest.inst) {
176 if (!access_check(sender->string, acl, INSTWILD)) {
178 "subscr unauth %s class %s wild inst",
179 sender->string, subs->dest.classname->string);
180 free_subscription(subs); /* free this one - denied */
181 continue; /* the for loop */
186 if (realm && !bdumping) {
187 retval = subscr_realm_sendit(who, subs, notice, realm);
188 if (retval != ZERR_NONE) {
189 free_subscription(subs);
190 continue; /* the for loop */
192 /* Indicates we leaked traffic back to our realm */
193 free_subscription(subs); /* free this one, wil get from
197 retval = triplet_register(who, &subs->dest, NULL);
198 if (retval != ZERR_NONE) {
199 if (retval == ZSRV_CLASSXISTS) {
200 free_subscription(subs); /* free this one */
202 free_subscriptions(subs);
207 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
208 LIST_INSERT(&who->subs, subs);
218 * add default subscriptions to the client's subscription chain.
222 subscr_def_subs(Client *who)
226 subs = subscr_copy_def_subs(who->principal->string);
227 return add_subscriptions(who, subs, &default_notice, NULL);
234 zdbug((LOG_DEBUG, "subscr_reset()"));
236 free(default_notice.z_message);
237 default_notice.z_message = NULL;
242 subscr_copy_def_subs(char *person)
246 char *def_sub_area, *cp;
247 Destlist *subs, *sub;
249 if (!defaults_read) {
251 zdbug((LOG_DEBUG, "reading default subscription file"));
253 fd = open(subs_file, O_RDONLY, 0666);
255 syslog(LOG_ERR, "can't open %s:%m", subs_file);
258 retval = fstat(fd, &statbuf);
260 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
264 def_sub_area = (char *) malloc(statbuf.st_size + 1);
266 syslog(LOG_ERR, "no mem copy_def_subs");
270 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
271 if (retval != statbuf.st_size) {
272 syslog(LOG_ERR, "short read in copy_def_subs");
278 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
281 def_subs_area now points to a buffer full of subscription info.
282 Each line of the stuff is of the form:
285 Commas and newlines may not appear as part of the class,
286 instance, or recipient. XXX!
289 /* split up the subscription info */
290 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
291 if (*cp == '\n' || *cp == ',')
294 default_notice.z_message = def_sub_area;
295 default_notice.z_message_len = statbuf.st_size + 1;
296 default_notice.z_auth = 1;
300 /* needed later for access_check() */
301 default_notice.z_sender = person;
302 subs = extract_subscriptions(&default_notice);
303 /* replace any non-* recipients with "person" */
305 for (sub = subs; sub; sub = sub->next) {
306 /* if not a wildcard, replace it with person */
307 if (strcmp(sub->dest.recip->string, "*")) {
308 free_string(sub->dest.recip);
309 sub->dest.recip = make_string(person, 0);
310 } else { /* replace with null recipient */
311 free_string(sub->dest.recip);
312 sub->dest.recip = dup_string(empty);
319 * Cancel a specific set of subscriptions.
323 subscr_cancel(struct sockaddr_in *sin,
328 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
334 zdbug((LOG_DEBUG,"subscr_cancel"));
336 who = client_find(&sin->sin_addr, notice->z_port);
343 cancel_subs = extract_subscriptions(notice);
345 return ZERR_NONE; /* no subscr -> no error */
347 for (subs = cancel_subs; subs; subs = cancel_next) {
348 cancel_next = subs->next;
349 for (client_subs = who->subs; client_subs; client_subs = client_next) {
350 client_next = client_subs->next;
351 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
352 LIST_DELETE(client_subs);
353 retval = triplet_deregister(who, &client_subs->dest, NULL);
354 if (retval == ZSRV_EMPTYCLASS &&
355 client_subs->dest.recip->string[0] == '@') {
357 realm_get_realm_by_name(client_subs->dest.recip->string
360 subscr_unsub_sendit(who, client_subs, realm);
363 free_subscription(client_subs);
370 free_subscriptions(cancel_subs);
374 zdbug((LOG_DEBUG, "found & removed"));
379 zdbug((LOG_DEBUG, "not found"));
386 subscr_realm_cancel(struct sockaddr_in *sin,
391 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
401 cancel_subs = extract_subscriptions(notice);
403 return ZERR_NONE; /* no subscr -> no error */
405 for (subs = cancel_subs; subs; subs = next) {
407 for (client_subs = realm->subs; client_subs; client_subs = next2) {
408 next2 = client_subs->next;
409 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
410 LIST_DELETE(client_subs);
411 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
412 free_subscription(client_subs);
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 *client)
441 Destlist *subs, *next;
446 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
447 inet_ntoa(client->addr.sin_addr)));
452 for (subs = client->subs; subs; subs = next) {
455 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
457 retval = triplet_deregister(client, &subs->dest, NULL);
458 if (retval == ZSRV_EMPTYCLASS &&
459 subs->dest.recip->string[0] == '@') {
460 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
462 subscr_unsub_sendit(client, subs, realm);
465 free_subscription(subs);
472 * Send the requester a list of his current subscriptions
476 subscr_sendlist(ZNotice_t *notice,
478 struct sockaddr_in *who)
482 struct sockaddr_in send_to_who;
486 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
487 /* we are talking to an old client; use the old-style
488 acknowledgement-message */
489 old_compat_subscr_sendlist(notice, auth, who);
492 #endif /* OLD_COMPAT */
494 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
495 /* we are talking to a new old client; use the new-old-style
496 acknowledgement-message */
497 new_old_compat_subscr_sendlist(notice, auth, who);
500 #endif /* NEW_COMPAT */
501 answer = subscr_marshal_subs(notice, auth, who, &found);
503 send_to_who.sin_port = notice->z_port; /* Return port */
505 retval = ZSetDestAddr(&send_to_who);
506 if (retval != ZERR_NONE) {
507 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
508 error_message(retval));
514 /* XXX for now, don't do authentication */
517 notice->z_kind = ACKED;
519 /* use xmit_frag() to send each piece of the notice */
521 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
522 if (retval != ZERR_NONE)
523 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
529 subscr_marshal_subs(ZNotice_t *notice,
531 struct sockaddr_in *who,
534 char **answer = NULL;
538 Destlist *subs = NULL, *sub;
543 zdbug((LOG_DEBUG, "subscr_marshal"));
547 /* Note that the following code is an incredible crock! */
549 /* We cannot send multiple packets as acknowledgements to the client,
550 since the hostmanager will ignore the later packets. So we need
551 to send directly to the client. */
553 /* Make our own copy so we can send directly back to the client */
556 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
557 /* If the client has requested his current subscriptions,
558 the message field of the notice contains the port number
559 of the client for which the sender desires the subscription
560 list. The port field is the port of the sender. */
562 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
563 if (retval != ZERR_NONE) {
564 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
565 error_message(retval));
569 client = client_find(&who->sin_addr, htons(temp));
573 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
575 zdbug((LOG_DEBUG, "gimmedefs"));
577 /* subscr_copy_def_subs allocates new pointer rings, so
578 it must be freed when finished.
579 the string areas pointed to are static, however.*/
580 subs = subscr_copy_def_subs(notice->z_sender);
583 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
590 /* check authenticity here. The user must be authentic to get
591 a list of subscriptions. If he is not subscribed to
592 anything, this if-clause fails, and he gets a response
593 indicating no subscriptions.
594 if retrieving default subscriptions, don't care about
597 if (!auth && !defsubs)
600 if (client && (strcmp(client->principal->string,
601 notice->z_sender) != 0)) {
603 "subscr_marshal: %s requests subs for %s at %s/%d",
604 notice->z_sender, client->principal->string,
605 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
610 for (sub = subs; sub; sub = sub->next)
613 /* found is now the number of subscriptions */
615 /* coalesce the subscription information into a list of char *'s */
616 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
617 if (answer == NULL) {
618 syslog(LOG_ERR, "subscr no mem(answer)");
622 for (sub = subs; sub; sub = sub->next) {
623 answer[i * NUM_FIELDS] = sub->dest.classname->string;
624 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
625 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
631 free_subscriptions(subs);
637 new_old_compat_subscr_sendlist(notice, auth, who)
640 struct sockaddr_in *who;
645 int packlen, found, count, initfound, zerofound;
648 struct sockaddr_in send_to_who;
651 new_compat_count_subscr++;
653 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
655 reply.z_kind = SERVACK;
656 reply.z_authent_len = 0; /* save some space */
660 send_to_who.sin_port = notice->z_port; /* Return port */
662 retval = ZSetDestAddr(&send_to_who);
663 if (retval != ZERR_NONE) {
664 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
665 error_message(retval));
669 /* retrieve the subscriptions */
670 answer = subscr_marshal_subs(notice, auth, who, &found);
672 /* note that when there are no subscriptions, found == 0, so
673 we needn't worry about answer being NULL since
674 ZFormatSmallRawNoticeList won't reference the pointer */
676 /* send 5 at a time until we are finished */
677 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
678 i = 0; /* pkt # counter */
680 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
683 zerofound = (found == 0);
684 while (found > 0 || zerofound) {
685 packlen = sizeof(reppacket);
686 sprintf(buf, "%d/%d", ++i, count);
687 reply.z_opcode = buf;
688 retval = ZFormatSmallRawNoticeList(&reply,
689 answer + (initfound - found)
691 ((found > 5) ? 5 : found)
693 reppacket, &packlen);
694 if (retval != ZERR_NONE) {
695 syslog(LOG_ERR, "subscr_sendlist format: %s",
696 error_message(retval));
701 retval = ZSendPacket(reppacket, packlen, 0);
702 if (retval != ZERR_NONE) {
703 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
704 error_message(retval));
713 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
718 #endif /* NEW_COMPAT */
722 old_compat_subscr_sendlist(notice, auth, who)
725 struct sockaddr_in *who;
727 Client *client = client_find(&who->sin_addr, notice->z_port);
732 int packlen, i, found = 0;
733 char **answer = NULL;
735 old_compat_count_subscr++;
737 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
738 if (client && client->subs) {
740 /* check authenticity here. The user must be authentic to get
741 a list of subscriptions. If he is not subscribed to
742 anything, the above test fails, and he gets a response
743 indicating no subscriptions */
746 clt_ack(notice, who, AUTH_FAILED);
750 for (subs = client->subs; subs; subs = subs->next)
752 /* found is now the number of subscriptions */
754 /* coalesce the subscription information into a list of char *'s */
755 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
757 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
761 for (subs = client->subs; subs; subs = subs->next) {
762 answer[i*NUM_FIELDS] = subs->dest.classname->string;
763 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
764 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
770 /* note that when there are no subscriptions, found == 0, so
771 we needn't worry about answer being NULL */
774 reply.z_kind = SERVACK;
775 reply.z_authent_len = 0; /* save some space */
778 /* if it's too long, chop off one at a time till it fits */
779 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
782 &packlen)) != ZERR_PKTLEN) {
784 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
786 if (retval != ZERR_NONE) {
787 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
788 error_message(retval));
793 retval = ZSetDestAddr(who);
794 if (retval != ZERR_NONE) {
795 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
796 error_message(retval));
801 retval = ZSendPacket(reppacket, packlen, 0);
802 if (retval != ZERR_NONE) {
803 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
804 error_message(retval));
810 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
815 #endif /* OLD_COMPAT */
818 * Send the client's subscriptions to another server
821 /* version is currently unused; if necessary later versions may key off it
822 to determine what to send to the peer (protocol changes) */
826 subscr_send_subs(Client *client)
837 #endif /* HAVE_KRB4 */
840 char *list[7 * NUM_FIELDS];
845 zdbug((LOG_DEBUG, "send_subs"));
847 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
852 #ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
853 if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
854 bufp = malloc(Z_keylen(client->session_keyblock));
856 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
859 des_ecb_encrypt(Z_keydata(client->session_keyblock), bufp, serv_ksched.s, DES_ENCRYPT);
860 retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
863 bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
866 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
869 *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
870 *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
871 memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
873 retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
876 #endif /* HAVE_KRB4 */
877 #else /* HAVE_KRB5 */
880 memcpy(cblock, client->session_key, sizeof(C_Block));
881 #else /* NOENCRYPTION */
882 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
883 #endif /* NOENCRYPTION */
885 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
886 #endif /* HAVE_KRB4 */
887 #endif /* HAVE_KRB5 */
889 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
890 if (retval != ZERR_NONE) {
892 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
897 zdbug((LOG_DEBUG, "cblock %s", buf));
900 #endif /* HAVE_KRB4 || HAVE_KRB5*/
901 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
902 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
903 client->principal->string, "", list, num);
904 if (retval != ZERR_NONE) {
905 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
912 for (subs = client->subs; subs; subs = subs->next) {
913 /* for each subscription */
914 list[i * NUM_FIELDS] = subs->dest.classname->string;
915 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
916 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
919 /* we only put 7 in each packet, so we don't run out of room */
920 retval = bdump_send_list_tcp(ACKED, &client->addr,
921 ZEPHYR_CTL_CLASS, "",
922 CLIENT_SUBSCRIBE, "", "", list,
924 if (retval != ZERR_NONE) {
925 syslog(LOG_ERR, "subscr_send_subs subs: %s",
926 error_message(retval));
933 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
934 "", CLIENT_SUBSCRIBE, "", "", list,
936 if (retval != ZERR_NONE) {
937 syslog(LOG_ERR, "subscr_send_subs subs: %s",
938 error_message(retval));
947 * free the memory allocated for the list of subscriptions.
951 * free the memory allocated for one subscription.
955 free_subscription(Destlist *sub)
957 free_string(sub->dest.classname);
958 free_string(sub->dest.inst);
959 free_string(sub->dest.recip);
964 free_subscriptions(Destlist *subs)
968 for (; subs; subs = next) {
970 free_subscription (subs);
974 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
975 if (cp >= notice->z_message + notice->z_message_len) { \
976 syslog(LOG_WARNING, "malformed subscription %d", \
982 * Parse the message body, returning a linked list of subscriptions, or
983 * NULL if there are no subscriptions there.
987 extract_subscriptions(ZNotice_t *notice)
989 Destlist *subs = NULL, *sub;
990 char *recip, *class_name, *classinst;
991 char *cp = notice->z_message;
993 /* parse the data area for the subscriptions */
994 while (cp < notice->z_message + notice->z_message_len) {
996 if (*cp == '\0') /* we've exhausted the subscriptions */
1003 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
1004 class_name, classinst, cp));
1006 cp += (strlen(cp) + 1);
1007 if (cp > notice->z_message + notice->z_message_len) {
1008 syslog(LOG_WARNING, "malformed sub 3");
1011 sub = (Destlist *) malloc(sizeof(Destlist));
1013 syslog(LOG_WARNING, "ex_subs: no mem 2");
1016 sub->dest.classname = make_string(class_name, 1);
1017 sub->dest.inst = make_string(classinst, 1);
1018 /* Nuke @REALM if REALM is us. */
1019 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
1020 sub->dest.recip = make_string("", 0);
1022 sub->dest.recip = make_string(recip, 0);
1023 LIST_INSERT(&subs, sub);
1029 * print subscriptions in subs onto fp.
1030 * assumed to be called with SIGFPE blocked
1031 * (true if called from signal handler)
1035 subscr_dump_subs(FILE *fp,
1040 if (!subs) /* no subscriptions to dump */
1043 for (; subs; subs = subs->next) {
1045 dump_quote(subs->dest.classname->string, fp);
1047 dump_quote(subs->dest.inst->string, fp);
1049 dump_quote(subs->dest.recip->string, fp);
1054 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1055 if (cp >= notice->z_message + notice->z_message_len) { \
1056 syslog(LOG_WARNING, "malformed subscription %d", \
1058 return (ZERR_NONE); \
1061 /* As it exists, this function expects to take only the first sub from the
1062 * Destlist. At some point, it and the calling code should be replaced */
1064 subscr_realm_sendit(Client *who,
1075 char addr[16]; /* xxx.xxx.xxx.xxx max */
1079 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1083 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1084 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1087 /* convert the address to a string of the form x.x.x.x/port */
1088 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1089 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1090 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1092 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1093 error_message(retval));
1099 text[2] = subs->dest.classname->string;
1100 text[3] = subs->dest.inst->string;
1101 text[4] = subs->dest.recip->string;
1103 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1104 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1106 /* format snotice */
1107 memset (&snotice, 0, sizeof(snotice));
1108 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1109 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1110 snotice.z_port = srv_addr.sin_port;
1112 snotice.z_class = ZEPHYR_CTL_CLASS;
1114 snotice.z_recipient = "";
1115 snotice.z_kind = ACKED;
1116 snotice.z_num_other_fields = 0;
1117 snotice.z_default_format = "";
1118 snotice.z_sender = who->principal->string;
1119 snotice.z_recipient = notice->z_recipient;
1120 snotice.z_default_format = notice->z_default_format;
1122 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1123 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1125 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1126 error_message(retval));
1132 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1133 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1134 error_message(retval));
1140 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1142 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1148 /* Called from subscr_realm and subscr_foreign_user */
1150 subscr_add_raw(Client *client,
1154 Destlist *subs, *subs2, *subs3, **head;
1158 zdbug((LOG_DEBUG, "subscr_add_raw"));
1160 head = (realm) ? &realm->subs : &client->subs;
1162 /* Loop over the new subscriptions. */
1163 for (subs = newsubs; subs; subs = subs2) {
1166 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1168 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1170 retval = triplet_register(client, &subs->dest, realm);
1171 if (retval != ZERR_NONE) {
1172 free_subscription(subs);
1173 if (retval == ZSRV_CLASSXISTS) {
1176 free_subscriptions(subs2);
1182 realm_get_realm_by_name(subs->dest.recip->string + 1);
1184 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1186 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1188 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1189 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1190 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1192 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1193 sub->dest.classname->string, sub->dest.inst->string,
1194 sub->dest.recip->string, remrealm->name));
1196 LIST_INSERT(&remrealm->remsubs, sub);
1201 LIST_INSERT(head, subs);
1206 /* Called from bdump_recv_loop to decapsulate realm subs */
1208 subscr_realm(ZRealm *realm,
1213 newsubs = extract_subscriptions(notice);
1216 syslog(LOG_WARNING, "empty subs in subscr_realm");
1220 return(subscr_add_raw(realm->client, realm, newsubs));
1223 /* Like realm_sendit, this only takes one item from subs */
1225 subscr_unsub_sendit(Client *who,
1235 Destlist *subsp, *subsn;
1237 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1238 subsn = subsp->next;
1239 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1241 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1242 subsp->dest.classname->string, subsp->dest.inst->string,
1243 subsp->dest.recip->string, realm->name));
1246 free_subscription(subsp);
1251 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1252 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1256 list[0] = subs->dest.classname->string;
1257 list[1] = subs->dest.inst->string;
1260 unotice.z_class = ZEPHYR_CTL_CLASS;
1261 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1262 unotice.z_opcode = REALM_UNSUBSCRIBE;
1263 unotice.z_recipient = "";
1264 unotice.z_kind = ACKED;
1266 unotice.z_sender = "";
1267 unotice.z_port = srv_addr.sin_port;
1268 unotice.z_num_other_fields = 0;
1269 unotice.z_default_format = "";
1271 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1272 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1273 error_message(retval));
1279 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1280 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1281 error_message(retval));
1285 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1289 /* Called from bump_send_loop by way of realm_send_realms */
1291 subscr_send_realm_subs(ZRealm *realm)
1294 Destlist *subs, *next;
1296 char *list[7 * NUM_FIELDS];
1301 zdbug((LOG_DEBUG, "send_realm_subs"));
1304 strcpy(buf, realm->name);
1307 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1308 "", ADMIN_NEWREALM, "", "", list, num);
1309 if (retval != ZERR_NONE) {
1310 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1317 for (subs=realm->subs; subs; subs = next) {
1320 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1321 subs->dest.inst->string, subs->dest.recip->string));
1323 /* for each subscription */
1324 list[i * NUM_FIELDS] = subs->dest.classname->string;
1325 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1326 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1329 /* we only put 7 in each packet, so we don't run out of room */
1330 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1331 ZEPHYR_CTL_CLASS, "",
1332 REALM_SUBSCRIBE, "", "", list,
1334 if (retval != ZERR_NONE) {
1335 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1336 error_message(retval));
1343 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1344 "", REALM_SUBSCRIBE, "", "", list,
1346 if (retval != ZERR_NONE) {
1347 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1348 error_message(retval));
1357 subscr_realm_subs(ZRealm *realm)
1360 Destlist *subs, *next;
1362 char *text[2 + NUM_FIELDS];
1363 unsigned short num = 0;
1372 zdbug((LOG_DEBUG, "realm_subs"));
1375 if (!realm->remsubs)
1378 for (subs=realm->remsubs; subs; subs = next) {
1381 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1382 subs->dest.inst->string, subs->dest.recip->string));
1386 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1387 &num, sizeof(u_short))) != ZERR_NONE)
1389 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1390 error_message(retval));
1394 text[0] = "0.0.0.0";
1396 text[2] = subs->dest.classname->string;
1397 text[3] = subs->dest.inst->string;
1398 text[4] = subs->dest.recip->string;
1400 /* format snotice */
1401 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1402 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1404 snotice.z_class = ZEPHYR_CTL_CLASS;
1406 snotice.z_recipient = "";
1407 snotice.z_kind = ACKED;
1408 snotice.z_num_other_fields = 0;
1409 snotice.z_default_format = "";
1410 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1411 resubmit them as the sender. */
1412 clientp = triplet_lookup(&subs->dest);
1414 snotice.z_sender = "";
1416 snotice.z_sender = (*clientp)->principal->string;
1417 snotice.z_default_format = "";
1419 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1420 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1422 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1423 error_message(retval));
1427 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1428 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1429 error_message(retval));
1433 realm_handoff(&snotice, 1, NULL, realm, 0);
1440 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1442 subscr_check_foreign_subs(ZNotice_t *notice,
1443 struct sockaddr_in *who,
1448 Destlist *subs, *subs2, *next;
1458 for (subs = newsubs; subs; subs = subs->next)
1464 sender = make_string(notice->z_sender, 0);
1466 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1468 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1469 free_string(sender);
1473 /* grab the client information from the incoming message */
1474 cp = notice->z_message;
1483 for (subs = newsubs; subs; subs = next) {
1486 if (subs->dest.recip->string[0] != '\0') {
1487 rlm = realm_which_realm(who);
1488 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1489 subs->dest.recip->string,
1490 sender->string, rlm->name);
1493 acl = class_get_acl(subs->dest.classname);
1495 rlm = realm_which_realm(who);
1496 if (rlm && server == me_server) {
1497 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1498 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1499 sender->string, rlm->name,
1500 subs->dest.classname->string);
1501 free_subscriptions(newsubs);
1502 free_string(sender);
1504 return ZSRV_CLASSRESTRICTED;
1507 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1508 syslog(LOG_WARNING, "subscr unauth %s class %s",
1509 sender->string, subs->dest.classname->string);
1510 continue; /* the for loop */
1512 if (wildcard_instance == subs->dest.inst) {
1513 if (!access_check(sender->string, acl, INSTWILD)) {
1515 "subscr unauth %s class %s wild inst",
1516 sender->string, subs->dest.classname->string);
1522 /* okay to subscribe. save for return trip */
1523 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1524 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1525 text[found*NUM_FIELDS + 4] = "";
1528 retval = triplet_register(realm->client, &subs->dest, realm);
1530 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1531 subs->dest.inst->string, subs->dest.recip->string));
1534 if (retval != ZERR_NONE) {
1535 if (retval == ZSRV_CLASSXISTS) {
1538 free_subscriptions(newsubs); /* subs->next XXX */
1539 free_string(sender);
1544 LIST_INSERT(&realm->subs, subs);
1546 /* don't send confirmation if we're not the initial server contacted */
1547 if (!(server_which_server(who) || found == 0)) {
1549 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1550 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1551 snotice.z_port = srv_addr.sin_port;
1552 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1553 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1554 error_message(retval));
1555 free_string(sender);
1559 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1560 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1561 error_message(retval));
1562 free_string(sender);
1567 realm_handoff(&snotice, 1, who, realm, 0);
1570 free_string(sender);
1575 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1576 Code_t subscr_foreign_user(ZNotice_t *notice,
1577 struct sockaddr_in *who,
1581 Destlist *newsubs, *temp;
1586 struct sockaddr_in newwho;
1587 char *cp, *tp0, *tp1;
1588 char rlm_recipient[REALM_SZ + 1];
1591 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1594 tp0 = cp = notice->z_message;
1596 newwho.sin_addr.s_addr = inet_addr(cp);
1597 if (newwho.sin_addr.s_addr == -1) {
1598 syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1607 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1610 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1611 error_message(status));
1617 snotice.z_message = cp;
1618 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1620 newsubs = extract_subscriptions(&snotice);
1622 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1626 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1627 /* this was approved by the other realm, add subscriptions */
1629 if (!strcmp(tp0, "0.0.0.0")) {
1630 /* skip bogus ADD reply from subscr_realm_subs */
1631 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1635 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1636 client = client_find(&newwho.sin_addr, snotice.z_port);
1637 if (client == (Client *)0) {
1638 syslog(LOG_WARNING, "no client at %s/%d",
1639 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1640 free_subscriptions(newsubs);
1644 /* translate the recipient to represent the foreign realm */
1645 sprintf(rlm_recipient, "@%s", realm->name);
1646 for (temp = newsubs; temp; temp = temp->next) {
1648 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1650 temp->dest.recip = make_string(rlm_recipient, 0);
1653 status = subscr_add_raw(client, (ZRealm *)0, newsubs);
1654 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1655 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1656 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1658 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",