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, ZRealm *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)
143 ZRealm *realm = NULL;
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 retval = subscr_realm_sendit(who, subs, notice, realm);
191 if (retval != ZERR_NONE) {
192 free_subscription(subs);
193 continue; /* the for loop */
195 /* Indicates we leaked traffic back to our realm */
196 free_subscription(subs); /* free this one, wil get from
200 retval = triplet_register(who, &subs->dest, NULL);
201 if (retval != ZERR_NONE) {
202 if (retval == ZSRV_CLASSXISTS) {
203 free_subscription(subs); /* free this one */
205 free_subscriptions(subs);
210 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
211 LIST_INSERT(&who->subs, subs);
221 * add default subscriptions to the client's subscription chain.
230 subs = subscr_copy_def_subs(who->principal->string);
231 return add_subscriptions(who, subs, &default_notice, NULL);
238 zdbug((LOG_DEBUG, "subscr_reset()"));
240 free(default_notice.z_message);
241 default_notice.z_message = NULL;
246 subscr_copy_def_subs(person)
251 char *def_sub_area, *cp;
252 Destlist *subs, *sub;
254 if (!defaults_read) {
256 zdbug((LOG_DEBUG, "reading default subscription file"));
258 fd = open(subs_file, O_RDONLY, 0666);
260 syslog(LOG_ERR, "can't open %s:%m", subs_file);
263 retval = fstat(fd, &statbuf);
265 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
269 def_sub_area = (char *) malloc(statbuf.st_size + 1);
271 syslog(LOG_ERR, "no mem copy_def_subs");
275 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
276 if (retval != statbuf.st_size) {
277 syslog(LOG_ERR, "short read in copy_def_subs");
283 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
286 def_subs_area now points to a buffer full of subscription info.
287 Each line of the stuff is of the form:
290 Commas and newlines may not appear as part of the class,
291 instance, or recipient. XXX!
294 /* split up the subscription info */
295 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
296 if (*cp == '\n' || *cp == ',')
299 default_notice.z_message = def_sub_area;
300 default_notice.z_message_len = statbuf.st_size + 1;
301 default_notice.z_auth = 1;
305 /* needed later for access_check() */
306 default_notice.z_sender = person;
307 subs = extract_subscriptions(&default_notice);
308 /* replace any non-* recipients with "person" */
310 for (sub = subs; sub; sub = sub->next) {
311 /* if not a wildcard, replace it with person */
312 if (strcmp(sub->dest.recip->string, "*")) {
313 free_string(sub->dest.recip);
314 sub->dest.recip = make_string(person, 0);
315 } else { /* replace with null recipient */
316 free_string(sub->dest.recip);
317 sub->dest.recip = dup_string(empty);
324 * Cancel a specific set of subscriptions.
328 subscr_cancel(sin, notice)
329 struct sockaddr_in *sin;
334 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
340 zdbug((LOG_DEBUG,"subscr_cancel"));
342 who = client_find(&sin->sin_addr, notice->z_port);
349 cancel_subs = extract_subscriptions(notice);
351 return ZERR_NONE; /* no subscr -> no error */
353 for (subs = cancel_subs; subs; subs = cancel_next) {
354 cancel_next = subs->next;
355 for (client_subs = who->subs; client_subs; client_subs = client_next) {
356 client_next = client_subs->next;
357 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
358 LIST_DELETE(client_subs);
359 retval = triplet_deregister(who, &client_subs->dest, NULL);
360 if (retval == ZSRV_EMPTYCLASS &&
361 client_subs->dest.recip->string[0] == '@') {
363 realm_get_realm_by_name(client_subs->dest.recip->string
366 subscr_unsub_sendit(who, client_subs, realm);
369 free_subscription(client_subs);
376 free_subscriptions(cancel_subs);
380 zdbug((LOG_DEBUG, "found & removed"));
385 zdbug((LOG_DEBUG, "not found"));
392 subscr_realm_cancel(sin, notice, realm)
393 struct sockaddr_in *sin;
398 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
408 cancel_subs = extract_subscriptions(notice);
410 return ZERR_NONE; /* no subscr -> no error */
412 for (subs = cancel_subs; subs; subs = next) {
414 for (client_subs = realm->subs; client_subs; client_subs = next2) {
415 next2 = client_subs->next;
416 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
417 LIST_DELETE(client_subs);
418 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
419 free_subscription(client_subs);
426 free_subscriptions(cancel_subs);
430 zdbug((LOG_DEBUG, "found & removed"));
435 zdbug((LOG_DEBUG, "not found"));
442 * Cancel all the subscriptions for this client.
446 subscr_cancel_client(client)
449 Destlist *subs, *next;
454 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
455 inet_ntoa(client->addr.sin_addr)));
460 for (subs = client->subs; subs; subs = next) {
463 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
465 retval = triplet_deregister(client, &subs->dest, NULL);
466 if (retval == ZSRV_EMPTYCLASS &&
467 subs->dest.recip->string[0] == '@') {
468 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
470 subscr_unsub_sendit(client, subs, realm);
473 free_subscription(subs);
480 * Send the requester a list of his current subscriptions
484 subscr_sendlist(notice, auth, who)
487 struct sockaddr_in *who;
491 struct sockaddr_in send_to_who;
495 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
496 /* we are talking to an old client; use the old-style
497 acknowledgement-message */
498 old_compat_subscr_sendlist(notice, auth, who);
501 #endif /* OLD_COMPAT */
503 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
504 /* we are talking to a new old client; use the new-old-style
505 acknowledgement-message */
506 new_old_compat_subscr_sendlist(notice, auth, who);
509 #endif /* NEW_COMPAT */
510 answer = subscr_marshal_subs(notice, auth, who, &found);
512 send_to_who.sin_port = notice->z_port; /* Return port */
514 retval = ZSetDestAddr(&send_to_who);
515 if (retval != ZERR_NONE) {
516 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
517 error_message(retval));
523 /* XXX for now, don't do authentication */
526 notice->z_kind = ACKED;
528 /* use xmit_frag() to send each piece of the notice */
530 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
531 if (retval != ZERR_NONE)
532 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
538 subscr_marshal_subs(notice, auth, who, found)
541 struct sockaddr_in *who;
544 char **answer = NULL;
548 Destlist *subs = NULL, *sub;
553 zdbug((LOG_DEBUG, "subscr_marshal"));
557 /* Note that the following code is an incredible crock! */
559 /* We cannot send multiple packets as acknowledgements to the client,
560 since the hostmanager will ignore the later packets. So we need
561 to send directly to the client. */
563 /* Make our own copy so we can send directly back to the client */
566 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
567 /* If the client has requested his current subscriptions,
568 the message field of the notice contains the port number
569 of the client for which the sender desires the subscription
570 list. The port field is the port of the sender. */
572 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
573 if (retval != ZERR_NONE) {
574 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
575 error_message(retval));
579 client = client_find(&who->sin_addr, htons(temp));
583 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
585 zdbug((LOG_DEBUG, "gimmedefs"));
587 /* subscr_copy_def_subs allocates new pointer rings, so
588 it must be freed when finished.
589 the string areas pointed to are static, however.*/
590 subs = subscr_copy_def_subs(notice->z_sender);
593 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
600 /* check authenticity here. The user must be authentic to get
601 a list of subscriptions. If he is not subscribed to
602 anything, this if-clause fails, and he gets a response
603 indicating no subscriptions.
604 if retrieving default subscriptions, don't care about
607 if (!auth && !defsubs)
610 if (client && (strcmp(client->principal->string,
611 notice->z_sender) != 0)) {
613 "subscr_marshal: %s requests subs for %s at %s/%d",
614 notice->z_sender, client->principal->string,
615 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
620 for (sub = subs; sub; sub = sub->next)
623 /* found is now the number of subscriptions */
625 /* coalesce the subscription information into a list of char *'s */
626 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
627 if (answer == NULL) {
628 syslog(LOG_ERR, "subscr no mem(answer)");
632 for (sub = subs; sub; sub = sub->next) {
633 answer[i * NUM_FIELDS] = sub->dest.classname->string;
634 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
635 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
641 free_subscriptions(subs);
647 new_old_compat_subscr_sendlist(notice, auth, who)
650 struct sockaddr_in *who;
655 int packlen, found, count, initfound, zerofound;
658 struct sockaddr_in send_to_who;
661 new_compat_count_subscr++;
663 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
665 reply.z_kind = SERVACK;
666 reply.z_authent_len = 0; /* save some space */
670 send_to_who.sin_port = notice->z_port; /* Return port */
672 retval = ZSetDestAddr(&send_to_who);
673 if (retval != ZERR_NONE) {
674 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
675 error_message(retval));
679 /* retrieve the subscriptions */
680 answer = subscr_marshal_subs(notice, auth, who, &found);
682 /* note that when there are no subscriptions, found == 0, so
683 we needn't worry about answer being NULL since
684 ZFormatSmallRawNoticeList won't reference the pointer */
686 /* send 5 at a time until we are finished */
687 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
688 i = 0; /* pkt # counter */
690 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
693 zerofound = (found == 0);
694 while (found > 0 || zerofound) {
695 packlen = sizeof(reppacket);
696 sprintf(buf, "%d/%d", ++i, count);
697 reply.z_opcode = buf;
698 retval = ZFormatSmallRawNoticeList(&reply,
699 answer + (initfound - found)
701 ((found > 5) ? 5 : found)
703 reppacket, &packlen);
704 if (retval != ZERR_NONE) {
705 syslog(LOG_ERR, "subscr_sendlist format: %s",
706 error_message(retval));
711 retval = ZSendPacket(reppacket, packlen, 0);
712 if (retval != ZERR_NONE) {
713 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
714 error_message(retval));
723 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
728 #endif /* NEW_COMPAT */
732 old_compat_subscr_sendlist(notice, auth, who)
735 struct sockaddr_in *who;
737 Client *client = client_find(&who->sin_addr, notice->z_port);
742 int packlen, i, found = 0;
743 char **answer = NULL;
745 old_compat_count_subscr++;
747 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
748 if (client && client->subs) {
750 /* check authenticity here. The user must be authentic to get
751 a list of subscriptions. If he is not subscribed to
752 anything, the above test fails, and he gets a response
753 indicating no subscriptions */
756 clt_ack(notice, who, AUTH_FAILED);
760 for (subs = client->subs; subs; subs = subs->next)
762 /* found is now the number of subscriptions */
764 /* coalesce the subscription information into a list of char *'s */
765 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
767 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
771 for (subs = client->subs; subs; subs = subs->next) {
772 answer[i*NUM_FIELDS] = subs->dest.classname->string;
773 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
774 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
780 /* note that when there are no subscriptions, found == 0, so
781 we needn't worry about answer being NULL */
784 reply.z_kind = SERVACK;
785 reply.z_authent_len = 0; /* save some space */
788 /* if it's too long, chop off one at a time till it fits */
789 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
792 &packlen)) != ZERR_PKTLEN) {
794 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
796 if (retval != ZERR_NONE) {
797 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
798 error_message(retval));
803 retval = ZSetDestAddr(who);
804 if (retval != ZERR_NONE) {
805 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
806 error_message(retval));
811 retval = ZSendPacket(reppacket, packlen, 0);
812 if (retval != ZERR_NONE) {
813 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
814 error_message(retval));
820 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
825 #endif /* OLD_COMPAT */
828 * Send the client's subscriptions to another server
831 /* version is currently unused; if necessary later versions may key off it
832 to determine what to send to the peer (protocol changes) */
836 subscr_send_subs(client)
848 #endif /* HAVE_KRB4 */
851 char *list[7 * NUM_FIELDS];
856 zdbug((LOG_DEBUG, "send_subs"));
858 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
863 #ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
864 if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
865 bufp = malloc(Z_keylen(client->session_keyblock));
867 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
870 des_ecb_encrypt(Z_keydata(client->session_keyblock), bufp, serv_ksched.s, DES_ENCRYPT);
871 retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
874 bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
877 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
880 *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
881 *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
882 memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
884 retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
887 #endif /* HAVE_KRB4 */
888 #else /* HAVE_KRB5 */
891 memcpy(cblock, client->session_key, sizeof(C_Block));
892 #else /* NOENCRYPTION */
893 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
894 #endif /* NOENCRYPTION */
896 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
897 #endif /* HAVE_KRB4 */
898 #endif /* HAVE_KRB5 */
900 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
901 if (retval != ZERR_NONE) {
903 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
908 zdbug((LOG_DEBUG, "cblock %s", buf));
911 #endif /* HAVE_KRB4 || HAVE_KRB5*/
912 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
913 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
914 client->principal->string, "", list, num);
915 if (retval != ZERR_NONE) {
916 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
923 for (subs = client->subs; subs; subs = subs->next) {
924 /* for each subscription */
925 list[i * NUM_FIELDS] = subs->dest.classname->string;
926 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
927 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
930 /* we only put 7 in each packet, so we don't run out of room */
931 retval = bdump_send_list_tcp(ACKED, &client->addr,
932 ZEPHYR_CTL_CLASS, "",
933 CLIENT_SUBSCRIBE, "", "", list,
935 if (retval != ZERR_NONE) {
936 syslog(LOG_ERR, "subscr_send_subs subs: %s",
937 error_message(retval));
944 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
945 "", CLIENT_SUBSCRIBE, "", "", list,
947 if (retval != ZERR_NONE) {
948 syslog(LOG_ERR, "subscr_send_subs subs: %s",
949 error_message(retval));
958 * free the memory allocated for the list of subscriptions.
962 * free the memory allocated for one subscription.
966 free_subscription(Destlist *sub)
968 free_string(sub->dest.classname);
969 free_string(sub->dest.inst);
970 free_string(sub->dest.recip);
975 free_subscriptions(subs)
980 for (; subs; subs = next) {
982 free_subscription (subs);
986 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
987 if (cp >= notice->z_message + notice->z_message_len) { \
988 syslog(LOG_WARNING, "malformed subscription %d", \
994 * Parse the message body, returning a linked list of subscriptions, or
995 * NULL if there are no subscriptions there.
999 extract_subscriptions(notice)
1002 Destlist *subs = NULL, *sub;
1003 char *recip, *class_name, *classinst;
1004 char *cp = notice->z_message;
1006 /* parse the data area for the subscriptions */
1007 while (cp < notice->z_message + notice->z_message_len) {
1009 if (*cp == '\0') /* we've exhausted the subscriptions */
1016 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
1017 class_name, classinst, cp));
1019 cp += (strlen(cp) + 1);
1020 if (cp > notice->z_message + notice->z_message_len) {
1021 syslog(LOG_WARNING, "malformed sub 3");
1024 sub = (Destlist *) malloc(sizeof(Destlist));
1026 syslog(LOG_WARNING, "ex_subs: no mem 2");
1029 sub->dest.classname = make_string(class_name, 1);
1030 sub->dest.inst = make_string(classinst, 1);
1031 /* Nuke @REALM if REALM is us. */
1032 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
1033 sub->dest.recip = make_string("", 0);
1035 sub->dest.recip = make_string(recip, 0);
1036 LIST_INSERT(&subs, sub);
1042 * print subscriptions in subs onto fp.
1043 * assumed to be called with SIGFPE blocked
1044 * (true if called from signal handler)
1048 subscr_dump_subs(fp, subs)
1054 if (!subs) /* no subscriptions to dump */
1057 for (; subs; subs = subs->next) {
1059 dump_quote(subs->dest.classname->string, fp);
1061 dump_quote(subs->dest.inst->string, fp);
1063 dump_quote(subs->dest.recip->string, fp);
1068 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1069 if (cp >= notice->z_message + notice->z_message_len) { \
1070 syslog(LOG_WARNING, "malformed subscription %d", \
1072 return (ZERR_NONE); \
1075 /* As it exists, this function expects to take only the first sub from the
1076 * Destlist. At some point, it and the calling code should be replaced */
1078 subscr_realm_sendit(who, subs, notice, realm)
1090 char addr[16]; /* xxx.xxx.xxx.xxx max */
1094 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1098 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1099 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1102 /* convert the address to a string of the form x.x.x.x/port */
1103 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1104 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1105 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1107 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1108 error_message(retval));
1114 text[2] = subs->dest.classname->string;
1115 text[3] = subs->dest.inst->string;
1116 text[4] = subs->dest.recip->string;
1118 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1119 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1121 /* format snotice */
1122 memset (&snotice, 0, sizeof(snotice));
1123 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1124 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1125 snotice.z_port = srv_addr.sin_port;
1127 snotice.z_class = ZEPHYR_CTL_CLASS;
1129 snotice.z_recipient = "";
1130 snotice.z_kind = ACKED;
1131 snotice.z_num_other_fields = 0;
1132 snotice.z_default_format = "";
1133 snotice.z_sender = who->principal->string;
1134 snotice.z_recipient = notice->z_recipient;
1135 snotice.z_default_format = notice->z_default_format;
1137 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1138 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1140 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1141 error_message(retval));
1147 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1148 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1149 error_message(retval));
1155 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1157 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1163 /* Called from subscr_realm and subscr_foreign_user */
1165 subscr_add_raw(client, realm, newsubs)
1170 Destlist *subs, *subs2, *subs3, **head;
1174 zdbug((LOG_DEBUG, "subscr_add_raw"));
1176 head = (realm) ? &realm->subs : &client->subs;
1178 /* Loop over the new subscriptions. */
1179 for (subs = newsubs; subs; subs = subs2) {
1182 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1184 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1186 retval = triplet_register(client, &subs->dest, realm);
1187 if (retval != ZERR_NONE) {
1188 free_subscription(subs);
1189 if (retval == ZSRV_CLASSXISTS) {
1192 free_subscriptions(subs2);
1198 realm_get_realm_by_name(subs->dest.recip->string + 1);
1200 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1202 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1204 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1205 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1206 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1208 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1209 sub->dest.classname->string, sub->dest.inst->string,
1210 sub->dest.recip->string, remrealm->name));
1212 LIST_INSERT(&remrealm->remsubs, sub);
1217 LIST_INSERT(head, subs);
1222 /* Called from bdump_recv_loop to decapsulate realm subs */
1224 subscr_realm(realm, notice)
1230 newsubs = extract_subscriptions(notice);
1233 syslog(LOG_WARNING, "empty subs in subscr_realm");
1237 return(subscr_add_raw(realm->client, realm, newsubs));
1240 /* Like realm_sendit, this only takes one item from subs */
1242 subscr_unsub_sendit(who, subs, realm)
1253 Destlist *subsp, *subsn;
1255 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1256 subsn = subsp->next;
1257 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1259 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1260 subsp->dest.classname->string, subsp->dest.inst->string,
1261 subsp->dest.recip->string, realm->name));
1264 free_subscription(subsp);
1269 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1270 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1274 list[0] = subs->dest.classname->string;
1275 list[1] = subs->dest.inst->string;
1278 unotice.z_class = ZEPHYR_CTL_CLASS;
1279 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1280 unotice.z_opcode = REALM_UNSUBSCRIBE;
1281 unotice.z_recipient = "";
1282 unotice.z_kind = ACKED;
1284 unotice.z_sender = "";
1285 unotice.z_port = srv_addr.sin_port;
1286 unotice.z_num_other_fields = 0;
1287 unotice.z_default_format = "";
1289 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1290 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1291 error_message(retval));
1297 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1298 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1299 error_message(retval));
1303 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1307 /* Called from bump_send_loop by way of realm_send_realms */
1309 subscr_send_realm_subs(realm)
1313 Destlist *subs, *next;
1315 char *list[7 * NUM_FIELDS];
1320 zdbug((LOG_DEBUG, "send_realm_subs"));
1323 strcpy(buf, realm->name);
1326 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1327 "", ADMIN_NEWREALM, "", "", list, num);
1328 if (retval != ZERR_NONE) {
1329 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1336 for (subs=realm->subs; subs; subs = next) {
1339 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1340 subs->dest.inst->string, subs->dest.recip->string));
1342 /* for each subscription */
1343 list[i * NUM_FIELDS] = subs->dest.classname->string;
1344 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1345 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1348 /* we only put 7 in each packet, so we don't run out of room */
1349 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1350 ZEPHYR_CTL_CLASS, "",
1351 REALM_SUBSCRIBE, "", "", list,
1353 if (retval != ZERR_NONE) {
1354 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1355 error_message(retval));
1362 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1363 "", REALM_SUBSCRIBE, "", "", list,
1365 if (retval != ZERR_NONE) {
1366 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1367 error_message(retval));
1376 subscr_realm_subs(realm)
1380 Destlist *subs, *next;
1382 char *text[2 + NUM_FIELDS];
1383 unsigned short num = 0;
1392 zdbug((LOG_DEBUG, "realm_subs"));
1395 if (!realm->remsubs)
1398 for (subs=realm->remsubs; subs; subs = next) {
1401 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1402 subs->dest.inst->string, subs->dest.recip->string));
1406 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1407 &num, sizeof(u_short))) != ZERR_NONE)
1409 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1410 error_message(retval));
1414 text[0] = "0.0.0.0";
1416 text[2] = subs->dest.classname->string;
1417 text[3] = subs->dest.inst->string;
1418 text[4] = subs->dest.recip->string;
1420 /* format snotice */
1421 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1422 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1424 snotice.z_class = ZEPHYR_CTL_CLASS;
1426 snotice.z_recipient = "";
1427 snotice.z_kind = ACKED;
1428 snotice.z_num_other_fields = 0;
1429 snotice.z_default_format = "";
1430 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1431 resubmit them as the sender. */
1432 clientp = triplet_lookup(&subs->dest);
1434 snotice.z_sender = "";
1436 snotice.z_sender = (*clientp)->principal->string;
1437 snotice.z_default_format = "";
1439 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1440 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1442 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1443 error_message(retval));
1447 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1448 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1449 error_message(retval));
1453 realm_handoff(&snotice, 1, NULL, realm, 0);
1460 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1462 subscr_check_foreign_subs(notice, who, server, realm, newsubs)
1464 struct sockaddr_in *who;
1469 Destlist *subs, *subs2, *next;
1479 for (subs = newsubs; subs; subs = subs->next)
1485 sender = make_string(notice->z_sender, 0);
1487 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1489 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1490 free_string(sender);
1494 /* grab the client information from the incoming message */
1495 cp = notice->z_message;
1504 for (subs = newsubs; subs; subs = next) {
1507 if (subs->dest.recip->string[0] != '\0') {
1508 rlm = realm_which_realm(who);
1509 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1510 subs->dest.recip->string,
1511 sender->string, rlm->name);
1514 acl = class_get_acl(subs->dest.classname);
1516 rlm = realm_which_realm(who);
1517 if (rlm && server == me_server) {
1518 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1519 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1520 sender->string, rlm->name,
1521 subs->dest.classname->string);
1522 free_subscriptions(newsubs);
1523 free_string(sender);
1525 return ZSRV_CLASSRESTRICTED;
1528 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1529 syslog(LOG_WARNING, "subscr unauth %s class %s",
1530 sender->string, subs->dest.classname->string);
1531 continue; /* the for loop */
1533 if (wildcard_instance == subs->dest.inst) {
1534 if (!access_check(sender->string, acl, INSTWILD)) {
1536 "subscr unauth %s class %s wild inst",
1537 sender->string, subs->dest.classname->string);
1543 /* okay to subscribe. save for return trip */
1544 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1545 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1546 text[found*NUM_FIELDS + 4] = "";
1549 retval = triplet_register(realm->client, &subs->dest, realm);
1551 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1552 subs->dest.inst->string, subs->dest.recip->string));
1555 if (retval != ZERR_NONE) {
1556 if (retval == ZSRV_CLASSXISTS) {
1559 free_subscriptions(newsubs); /* subs->next XXX */
1560 free_string(sender);
1565 LIST_INSERT(&realm->subs, subs);
1567 /* don't send confirmation if we're not the initial server contacted */
1568 if (!(server_which_server(who) || found == 0)) {
1570 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1571 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1572 snotice.z_port = srv_addr.sin_port;
1573 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1574 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1575 error_message(retval));
1576 free_string(sender);
1580 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1581 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1582 error_message(retval));
1583 free_string(sender);
1588 realm_handoff(&snotice, 1, who, realm, 0);
1591 free_string(sender);
1596 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1597 Code_t subscr_foreign_user(notice, who, server, realm)
1599 struct sockaddr_in *who;
1603 Destlist *newsubs, *temp;
1608 struct sockaddr_in newwho;
1609 char *cp, *tp0, *tp1;
1610 char rlm_recipient[REALM_SZ + 1];
1613 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1616 tp0 = cp = notice->z_message;
1618 newwho.sin_addr.s_addr = inet_addr(cp);
1619 if (newwho.sin_addr.s_addr == -1) {
1620 syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1629 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1632 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1633 error_message(status));
1639 snotice.z_message = cp;
1640 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1642 newsubs = extract_subscriptions(&snotice);
1644 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1648 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1649 /* this was approved by the other realm, add subscriptions */
1651 if (!strcmp(tp0, "0.0.0.0")) {
1652 /* skip bogus ADD reply from subscr_realm_subs */
1653 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1657 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1658 client = client_find(&newwho.sin_addr, snotice.z_port);
1659 if (client == (Client *)0) {
1660 syslog(LOG_WARNING, "no client at %s/%d",
1661 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1662 free_subscriptions(newsubs);
1666 /* translate the recipient to represent the foreign realm */
1667 sprintf(rlm_recipient, "@%s", realm->name);
1668 for (temp = newsubs; temp; temp = temp->next) {
1670 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1672 temp->dest.recip = make_string(rlm_recipient, 0);
1675 status = subscr_add_raw(client, (ZRealm *)0, newsubs);
1676 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1677 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1678 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1680 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",