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_sendit(Client *who, Destlist *subs,
101 static int defaults_read = 0; /* set to 1 if the default subs
103 static ZNotice_t default_notice; /* contains default subscriptions */
105 String *wildcard_instance;
108 /* WARNING: make sure this is the same as the number of strings you */
109 /* plan to hand back to the user in response to a subscription check, */
110 /* else you will lose. See subscr_sendlist() */
114 * subscribe the client to types described in notice.
118 subscr_subscribe(Client *who,
124 subs = extract_subscriptions(notice);
125 return add_subscriptions(who, subs, notice, server);
129 add_subscriptions(Client *who,
138 ZRealm *realm = NULL;
141 return ZERR_NONE; /* no subscr -> no error */
143 sender = make_string(notice->z_sender, 0);
145 /* Loop over the new subscriptions. */
146 for (; subs; subs = next) {
149 zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
150 subs->dest.inst->string, subs->dest.recip->string));
152 /* check the recipient for a realm which isn't ours */
154 if (subs->dest.recip->string[0] == '@' &&
155 strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
156 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
158 if (subs->dest.recip != empty && subs->dest.recip != sender
159 && subs->dest.recip->string[0] != '@') {
160 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
161 sender->string, subs->dest.recip->string);
162 free_subscription(subs); /* free this one - denied */
163 continue; /* the for loop */
165 acl = class_get_acl(subs->dest.classname);
167 if (!access_check(sender->string, acl, SUBSCRIBE)) {
168 syslog(LOG_WARNING, "subscr unauth %s class %s",
169 sender->string, subs->dest.classname->string);
170 free_subscription(subs); /* free this one - denied */
171 continue; /* the for loop */
173 if (wildcard_instance == subs->dest.inst) {
174 if (!access_check(sender->string, acl, INSTWILD)) {
176 "subscr unauth %s class %s wild inst",
177 sender->string, subs->dest.classname->string);
178 free_subscription(subs); /* free this one - denied */
179 continue; /* the for loop */
184 if (realm && !bdumping) {
185 retval = subscr_realm_sendit(who, subs, notice, realm);
186 if (retval != ZERR_NONE) {
187 free_subscription(subs);
188 continue; /* the for loop */
190 /* Indicates we leaked traffic back to our realm */
191 free_subscription(subs); /* free this one, wil get from
195 retval = triplet_register(who, &subs->dest, NULL);
196 if (retval != ZERR_NONE) {
197 if (retval == ZSRV_CLASSXISTS) {
198 free_subscription(subs); /* free this one */
200 free_subscriptions(subs);
205 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
206 Destlist_insert(&who->subs, subs);
216 * add default subscriptions to the client's subscription chain.
220 subscr_def_subs(Client *who)
224 subs = subscr_copy_def_subs(who->principal->string);
225 return add_subscriptions(who, subs, &default_notice, NULL);
232 zdbug((LOG_DEBUG, "subscr_reset()"));
234 free(default_notice.z_message);
235 default_notice.z_message = NULL;
240 subscr_copy_def_subs(char *person)
244 char *def_sub_area, *cp;
245 Destlist *subs, *sub;
247 if (!defaults_read) {
249 zdbug((LOG_DEBUG, "reading default subscription file"));
251 fd = open(subs_file, O_RDONLY, 0666);
253 syslog(LOG_ERR, "can't open %s:%m", subs_file);
256 retval = fstat(fd, &statbuf);
258 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
262 def_sub_area = (char *) malloc(statbuf.st_size + 1);
264 syslog(LOG_ERR, "no mem copy_def_subs");
268 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
269 if (retval != statbuf.st_size) {
270 syslog(LOG_ERR, "short read in copy_def_subs");
276 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
279 def_subs_area now points to a buffer full of subscription info.
280 Each line of the stuff is of the form:
283 Commas and newlines may not appear as part of the class,
284 instance, or recipient. XXX!
287 /* split up the subscription info */
288 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
289 if (*cp == '\n' || *cp == ',')
292 default_notice.z_message = def_sub_area;
293 default_notice.z_message_len = statbuf.st_size + 1;
294 default_notice.z_auth = 1;
298 /* needed later for access_check() */
299 default_notice.z_sender = person;
300 subs = extract_subscriptions(&default_notice);
301 /* replace any non-* recipients with "person" */
303 for (sub = subs; sub; sub = sub->next) {
304 /* if not a wildcard, replace it with person */
305 if (strcmp(sub->dest.recip->string, "*")) {
306 free_string(sub->dest.recip);
307 sub->dest.recip = make_string(person, 0);
308 } else { /* replace with null recipient */
309 free_string(sub->dest.recip);
310 sub->dest.recip = dup_string(empty);
317 * Cancel a specific set of subscriptions.
321 subscr_cancel(struct sockaddr_in *sin,
326 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
331 zdbug((LOG_DEBUG,"subscr_cancel"));
333 who = client_find(&sin->sin_addr, notice->z_port);
340 cancel_subs = extract_subscriptions(notice);
342 return ZERR_NONE; /* no subscr -> no error */
344 for (subs = cancel_subs; subs; subs = cancel_next) {
345 cancel_next = subs->next;
346 for (client_subs = who->subs; client_subs; client_subs = client_next) {
347 client_next = client_subs->next;
348 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
349 Destlist_delete(client_subs);
350 retval = triplet_deregister(who, &client_subs->dest, NULL);
351 if (retval == ZSRV_EMPTYCLASS &&
352 client_subs->dest.recip->string[0] == '@') {
354 realm_get_realm_by_name(client_subs->dest.recip->string
357 subscr_unsub_sendit(who, client_subs, realm);
360 free_subscription(client_subs);
367 free_subscriptions(cancel_subs);
371 zdbug((LOG_DEBUG, "found & removed"));
376 zdbug((LOG_DEBUG, "not found"));
383 subscr_realm_cancel(struct sockaddr_in *sin,
387 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
397 cancel_subs = extract_subscriptions(notice);
399 return ZERR_NONE; /* no subscr -> no error */
401 for (subs = cancel_subs; subs; subs = next) {
403 for (client_subs = realm->subs; client_subs; client_subs = next2) {
404 next2 = client_subs->next;
405 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
406 Destlist_delete(client_subs);
407 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
408 free_subscription(client_subs);
415 free_subscriptions(cancel_subs);
419 zdbug((LOG_DEBUG, "found & removed"));
424 zdbug((LOG_DEBUG, "not found"));
431 * Cancel all the subscriptions for this client.
435 subscr_cancel_client(Client *client)
437 Destlist *subs, *next;
442 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
443 inet_ntoa(client->addr.sin_addr)));
448 for (subs = client->subs; subs; subs = next) {
451 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
453 retval = triplet_deregister(client, &subs->dest, NULL);
454 if (retval == ZSRV_EMPTYCLASS &&
455 subs->dest.recip->string[0] == '@') {
456 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
458 subscr_unsub_sendit(client, subs, realm);
461 free_subscription(subs);
468 * Send the requester a list of his current subscriptions
472 subscr_sendlist(ZNotice_t *notice,
474 struct sockaddr_in *who)
478 struct sockaddr_in send_to_who;
482 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
483 /* we are talking to an old client; use the old-style
484 acknowledgement-message */
485 old_compat_subscr_sendlist(notice, auth, who);
488 #endif /* OLD_COMPAT */
490 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
491 /* we are talking to a new old client; use the new-old-style
492 acknowledgement-message */
493 new_old_compat_subscr_sendlist(notice, auth, who);
496 #endif /* NEW_COMPAT */
497 answer = subscr_marshal_subs(notice, auth, who, &found);
499 send_to_who.sin_port = notice->z_port; /* Return port */
501 retval = ZSetDestAddr(&send_to_who);
502 if (retval != ZERR_NONE) {
503 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
504 error_message(retval));
510 /* XXX for now, don't do authentication */
513 notice->z_kind = ACKED;
515 /* use xmit_frag() to send each piece of the notice */
517 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
518 if (retval != ZERR_NONE)
519 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
525 subscr_marshal_subs(ZNotice_t *notice,
527 struct sockaddr_in *who,
530 char **answer = NULL;
534 Destlist *subs = NULL, *sub;
539 zdbug((LOG_DEBUG, "subscr_marshal"));
543 /* Note that the following code is an incredible crock! */
545 /* We cannot send multiple packets as acknowledgements to the client,
546 since the hostmanager will ignore the later packets. So we need
547 to send directly to the client. */
549 /* Make our own copy so we can send directly back to the client */
552 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
553 /* If the client has requested his current subscriptions,
554 the message field of the notice contains the port number
555 of the client for which the sender desires the subscription
556 list. The port field is the port of the sender. */
558 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
559 if (retval != ZERR_NONE) {
560 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
561 error_message(retval));
565 client = client_find(&who->sin_addr, htons(temp));
569 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
571 zdbug((LOG_DEBUG, "gimmedefs"));
573 /* subscr_copy_def_subs allocates new pointer rings, so
574 it must be freed when finished.
575 the string areas pointed to are static, however.*/
576 subs = subscr_copy_def_subs(notice->z_sender);
579 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
586 /* check authenticity here. The user must be authentic to get
587 a list of subscriptions. If he is not subscribed to
588 anything, this if-clause fails, and he gets a response
589 indicating no subscriptions.
590 if retrieving default subscriptions, don't care about
593 if (!auth && !defsubs)
596 if (client && (strcmp(client->principal->string,
597 notice->z_sender) != 0)) {
599 "subscr_marshal: %s requests subs for %s at %s/%d",
600 notice->z_sender, client->principal->string,
601 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
606 for (sub = subs; sub; sub = sub->next)
609 /* found is now the number of subscriptions */
611 /* coalesce the subscription information into a list of char *'s */
612 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
613 if (answer == NULL) {
614 syslog(LOG_ERR, "subscr no mem(answer)");
618 for (sub = subs; sub; sub = sub->next) {
619 answer[i * NUM_FIELDS] = sub->dest.classname->string;
620 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
621 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
627 free_subscriptions(subs);
633 new_old_compat_subscr_sendlist(notice, auth, who)
636 struct sockaddr_in *who;
641 int packlen, found, count, initfound, zerofound;
644 struct sockaddr_in send_to_who;
647 new_compat_count_subscr++;
649 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
651 reply.z_kind = SERVACK;
652 reply.z_authent_len = 0; /* save some space */
656 send_to_who.sin_port = notice->z_port; /* Return port */
658 retval = ZSetDestAddr(&send_to_who);
659 if (retval != ZERR_NONE) {
660 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
661 error_message(retval));
665 /* retrieve the subscriptions */
666 answer = subscr_marshal_subs(notice, auth, who, &found);
668 /* note that when there are no subscriptions, found == 0, so
669 we needn't worry about answer being NULL since
670 ZFormatSmallRawNoticeList won't reference the pointer */
672 /* send 5 at a time until we are finished */
673 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
674 i = 0; /* pkt # counter */
676 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
679 zerofound = (found == 0);
680 while (found > 0 || zerofound) {
681 packlen = sizeof(reppacket);
682 sprintf(buf, "%d/%d", ++i, count);
683 reply.z_opcode = buf;
684 retval = ZFormatSmallRawNoticeList(&reply,
685 answer + (initfound - found)
687 ((found > 5) ? 5 : found)
689 reppacket, &packlen);
690 if (retval != ZERR_NONE) {
691 syslog(LOG_ERR, "subscr_sendlist format: %s",
692 error_message(retval));
697 retval = ZSendPacket(reppacket, packlen, 0);
698 if (retval != ZERR_NONE) {
699 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
700 error_message(retval));
709 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
714 #endif /* NEW_COMPAT */
718 old_compat_subscr_sendlist(notice, auth, who)
721 struct sockaddr_in *who;
723 Client *client = client_find(&who->sin_addr, notice->z_port);
728 int packlen, i, found = 0;
729 char **answer = NULL;
731 old_compat_count_subscr++;
733 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
734 if (client && client->subs) {
736 /* check authenticity here. The user must be authentic to get
737 a list of subscriptions. If he is not subscribed to
738 anything, the above test fails, and he gets a response
739 indicating no subscriptions */
742 clt_ack(notice, who, AUTH_FAILED);
746 for (subs = client->subs; subs; subs = subs->next)
748 /* found is now the number of subscriptions */
750 /* coalesce the subscription information into a list of char *'s */
751 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
753 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
757 for (subs = client->subs; subs; subs = subs->next) {
758 answer[i*NUM_FIELDS] = subs->dest.classname->string;
759 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
760 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
766 /* note that when there are no subscriptions, found == 0, so
767 we needn't worry about answer being NULL */
770 reply.z_kind = SERVACK;
771 reply.z_authent_len = 0; /* save some space */
774 /* if it's too long, chop off one at a time till it fits */
775 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
778 &packlen)) != ZERR_PKTLEN) {
780 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
782 if (retval != ZERR_NONE) {
783 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
784 error_message(retval));
789 retval = ZSetDestAddr(who);
790 if (retval != ZERR_NONE) {
791 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
792 error_message(retval));
797 retval = ZSendPacket(reppacket, packlen, 0);
798 if (retval != ZERR_NONE) {
799 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
800 error_message(retval));
806 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
811 #endif /* OLD_COMPAT */
814 * Send the client's subscriptions to another server
817 /* version is currently unused; if necessary later versions may key off it
818 to determine what to send to the peer (protocol changes) */
822 subscr_send_subs(Client *client)
833 #endif /* HAVE_KRB4 */
836 char *list[7 * NUM_FIELDS];
841 zdbug((LOG_DEBUG, "send_subs"));
843 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
848 #ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
849 if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
850 bufp = malloc(Z_keylen(client->session_keyblock));
852 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
855 des_ecb_encrypt(Z_keydata(client->session_keyblock), bufp, serv_ksched.s, DES_ENCRYPT);
856 retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
859 bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
862 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
865 *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
866 *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
867 memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
869 retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
872 #endif /* HAVE_KRB4 */
873 #else /* HAVE_KRB5 */
876 memcpy(cblock, client->session_key, sizeof(C_Block));
877 #else /* NOENCRYPTION */
878 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
879 #endif /* NOENCRYPTION */
881 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
882 #endif /* HAVE_KRB4 */
883 #endif /* HAVE_KRB5 */
885 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
886 if (retval != ZERR_NONE) {
888 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
893 zdbug((LOG_DEBUG, "cblock %s", buf));
896 #endif /* HAVE_KRB4 || HAVE_KRB5*/
897 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
898 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
899 client->principal->string, "", list, num);
900 if (retval != ZERR_NONE) {
901 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
908 for (subs = client->subs; subs; subs = subs->next) {
909 /* for each subscription */
910 list[i * NUM_FIELDS] = subs->dest.classname->string;
911 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
912 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
915 /* we only put 7 in each packet, so we don't run out of room */
916 retval = bdump_send_list_tcp(ACKED, &client->addr,
917 ZEPHYR_CTL_CLASS, "",
918 CLIENT_SUBSCRIBE, "", "", list,
920 if (retval != ZERR_NONE) {
921 syslog(LOG_ERR, "subscr_send_subs subs: %s",
922 error_message(retval));
929 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
930 "", CLIENT_SUBSCRIBE, "", "", list,
932 if (retval != ZERR_NONE) {
933 syslog(LOG_ERR, "subscr_send_subs subs: %s",
934 error_message(retval));
943 * free the memory allocated for the list of subscriptions.
947 * free the memory allocated for one subscription.
951 free_subscription(Destlist *sub)
953 free_string(sub->dest.classname);
954 free_string(sub->dest.inst);
955 free_string(sub->dest.recip);
960 free_subscriptions(Destlist *subs)
964 for (; subs; subs = next) {
966 free_subscription (subs);
970 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
971 if (cp >= notice->z_message + notice->z_message_len) { \
972 syslog(LOG_WARNING, "malformed subscription %d", \
978 * Parse the message body, returning a linked list of subscriptions, or
979 * NULL if there are no subscriptions there.
983 extract_subscriptions(ZNotice_t *notice)
985 Destlist *subs = NULL, *sub;
986 char *recip, *class_name, *classinst;
987 char *cp = notice->z_message;
989 /* parse the data area for the subscriptions */
990 while (cp < notice->z_message + notice->z_message_len) {
992 if (*cp == '\0') /* we've exhausted the subscriptions */
999 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
1000 class_name, classinst, cp));
1002 cp += (strlen(cp) + 1);
1003 if (cp > notice->z_message + notice->z_message_len) {
1004 syslog(LOG_WARNING, "malformed sub 3");
1007 sub = (Destlist *) malloc(sizeof(Destlist));
1009 syslog(LOG_WARNING, "ex_subs: no mem 2");
1012 sub->dest.classname = make_string(class_name, 1);
1013 sub->dest.inst = make_string(classinst, 1);
1014 /* Nuke @REALM if REALM is us. */
1015 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
1016 sub->dest.recip = make_string("", 0);
1018 sub->dest.recip = make_string(recip, 0);
1019 Destlist_insert(&subs, sub);
1025 * print subscriptions in subs onto fp.
1026 * assumed to be called with SIGFPE blocked
1027 * (true if called from signal handler)
1031 subscr_dump_subs(FILE *fp,
1034 if (!subs) /* no subscriptions to dump */
1037 for (; subs; subs = subs->next) {
1039 dump_quote(subs->dest.classname->string, fp);
1041 dump_quote(subs->dest.inst->string, fp);
1043 dump_quote(subs->dest.recip->string, fp);
1048 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1049 if (cp >= notice->z_message + notice->z_message_len) { \
1050 syslog(LOG_WARNING, "malformed subscription %d", \
1052 return (ZERR_NONE); \
1055 /* As it exists, this function expects to take only the first sub from the
1056 * Destlist. At some point, it and the calling code should be replaced */
1058 subscr_realm_sendit(Client *who,
1068 char addr[16]; /* xxx.xxx.xxx.xxx max */
1072 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1076 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1077 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1080 /* convert the address to a string of the form x.x.x.x/port */
1081 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1082 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1083 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1085 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1086 error_message(retval));
1092 text[2] = subs->dest.classname->string;
1093 text[3] = subs->dest.inst->string;
1094 text[4] = subs->dest.recip->string;
1096 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1097 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1099 /* format snotice */
1100 memset (&snotice, 0, sizeof(snotice));
1101 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1102 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1103 snotice.z_port = srv_addr.sin_port;
1105 snotice.z_class = ZEPHYR_CTL_CLASS;
1107 snotice.z_recipient = "";
1108 snotice.z_kind = ACKED;
1109 snotice.z_num_other_fields = 0;
1110 snotice.z_default_format = "";
1111 snotice.z_sender = who->principal->string;
1112 snotice.z_recipient = notice->z_recipient;
1113 snotice.z_default_format = notice->z_default_format;
1115 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1116 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1118 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1119 error_message(retval));
1125 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1126 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1127 error_message(retval));
1133 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1135 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1141 /* Called from subscr_realm and subscr_foreign_user */
1143 subscr_add_raw(Client *client,
1147 Destlist *subs, *subs2, **head;
1151 zdbug((LOG_DEBUG, "subscr_add_raw"));
1153 head = (realm) ? &realm->subs : &client->subs;
1155 /* Loop over the new subscriptions. */
1156 for (subs = newsubs; subs; subs = subs2) {
1159 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1161 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1163 retval = triplet_register(client, &subs->dest, realm);
1164 if (retval != ZERR_NONE) {
1165 free_subscription(subs);
1166 if (retval == ZSRV_CLASSXISTS) {
1169 free_subscriptions(subs2);
1175 realm_get_realm_by_name(subs->dest.recip->string + 1);
1177 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1179 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1181 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1182 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1183 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1185 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1186 sub->dest.classname->string, sub->dest.inst->string,
1187 sub->dest.recip->string, remrealm->name));
1189 Destlist_insert(&remrealm->remsubs, sub);
1194 Destlist_insert(head, subs);
1199 /* Called from bdump_recv_loop to decapsulate realm subs */
1201 subscr_realm(ZRealm *realm,
1206 newsubs = extract_subscriptions(notice);
1209 syslog(LOG_WARNING, "empty subs in subscr_realm");
1213 return(subscr_add_raw(realm->client, realm, newsubs));
1216 /* Like realm_sendit, this only takes one item from subs */
1218 subscr_unsub_sendit(Client *who,
1227 Destlist *subsp, *subsn;
1229 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1230 subsn = subsp->next;
1231 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1233 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1234 subsp->dest.classname->string, subsp->dest.inst->string,
1235 subsp->dest.recip->string, realm->name));
1237 Destlist_delete(subsp);
1238 free_subscription(subsp);
1243 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1244 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1248 list[0] = subs->dest.classname->string;
1249 list[1] = subs->dest.inst->string;
1252 unotice.z_class = ZEPHYR_CTL_CLASS;
1253 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1254 unotice.z_opcode = REALM_UNSUBSCRIBE;
1255 unotice.z_recipient = "";
1256 unotice.z_kind = ACKED;
1258 unotice.z_sender = "";
1259 unotice.z_port = srv_addr.sin_port;
1260 unotice.z_num_other_fields = 0;
1261 unotice.z_default_format = "";
1263 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1264 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1265 error_message(retval));
1271 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1272 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1273 error_message(retval));
1277 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1281 /* Called from bump_send_loop by way of realm_send_realms */
1283 subscr_send_realm_subs(ZRealm *realm)
1286 Destlist *subs, *next;
1288 char *list[7 * NUM_FIELDS];
1293 zdbug((LOG_DEBUG, "send_realm_subs"));
1296 strcpy(buf, realm->name);
1299 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1300 "", ADMIN_NEWREALM, "", "", list, num);
1301 if (retval != ZERR_NONE) {
1302 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1309 for (subs=realm->subs; subs; subs = next) {
1312 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1313 subs->dest.inst->string, subs->dest.recip->string));
1315 /* for each subscription */
1316 list[i * NUM_FIELDS] = subs->dest.classname->string;
1317 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1318 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1321 /* we only put 7 in each packet, so we don't run out of room */
1322 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1323 ZEPHYR_CTL_CLASS, "",
1324 REALM_SUBSCRIBE, "", "", list,
1326 if (retval != ZERR_NONE) {
1327 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1328 error_message(retval));
1335 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1336 "", REALM_SUBSCRIBE, "", "", list,
1338 if (retval != ZERR_NONE) {
1339 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1340 error_message(retval));
1349 subscr_realm_subs(ZRealm *realm)
1351 Destlist *subs, *next;
1352 char *text[2 + NUM_FIELDS];
1353 unsigned short num = 0;
1362 zdbug((LOG_DEBUG, "realm_subs"));
1365 if (!realm->remsubs)
1368 for (subs=realm->remsubs; subs; subs = next) {
1371 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1372 subs->dest.inst->string, subs->dest.recip->string));
1376 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1377 &num, sizeof(u_short))) != ZERR_NONE)
1379 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1380 error_message(retval));
1384 text[0] = "0.0.0.0";
1386 text[2] = subs->dest.classname->string;
1387 text[3] = subs->dest.inst->string;
1388 text[4] = subs->dest.recip->string;
1390 /* format snotice */
1391 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1392 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1394 snotice.z_class = ZEPHYR_CTL_CLASS;
1396 snotice.z_recipient = "";
1397 snotice.z_kind = ACKED;
1398 snotice.z_num_other_fields = 0;
1399 snotice.z_default_format = "";
1400 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1401 resubmit them as the sender. */
1402 clientp = triplet_lookup(&subs->dest);
1404 snotice.z_sender = "";
1406 snotice.z_sender = (*clientp)->principal->string;
1407 snotice.z_default_format = "";
1409 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1410 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1412 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1413 error_message(retval));
1417 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1418 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1419 error_message(retval));
1423 realm_handoff(&snotice, 1, NULL, realm, 0);
1430 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1432 subscr_check_foreign_subs(ZNotice_t *notice,
1433 struct sockaddr_in *who,
1438 Destlist *subs, *next;
1448 for (subs = newsubs; subs; subs = subs->next)
1454 sender = make_string(notice->z_sender, 0);
1456 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1458 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1459 free_string(sender);
1463 /* grab the client information from the incoming message */
1464 cp = notice->z_message;
1473 for (subs = newsubs; subs; subs = next) {
1476 if (subs->dest.recip->string[0] != '\0') {
1477 rlm = realm_which_realm(who);
1478 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1479 subs->dest.recip->string,
1480 sender->string, rlm->name);
1483 acl = class_get_acl(subs->dest.classname);
1485 rlm = realm_which_realm(who);
1486 if (rlm && server == me_server) {
1487 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1488 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1489 sender->string, rlm->name,
1490 subs->dest.classname->string);
1491 free_subscriptions(newsubs);
1492 free_string(sender);
1494 return ZSRV_CLASSRESTRICTED;
1497 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1498 syslog(LOG_WARNING, "subscr unauth %s class %s",
1499 sender->string, subs->dest.classname->string);
1500 continue; /* the for loop */
1502 if (wildcard_instance == subs->dest.inst) {
1503 if (!access_check(sender->string, acl, INSTWILD)) {
1505 "subscr unauth %s class %s wild inst",
1506 sender->string, subs->dest.classname->string);
1512 /* okay to subscribe. save for return trip */
1513 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1514 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1515 text[found*NUM_FIELDS + 4] = "";
1518 retval = triplet_register(realm->client, &subs->dest, realm);
1520 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1521 subs->dest.inst->string, subs->dest.recip->string));
1524 if (retval != ZERR_NONE) {
1525 if (retval == ZSRV_CLASSXISTS) {
1528 free_subscriptions(newsubs); /* subs->next XXX */
1529 free_string(sender);
1534 Destlist_insert(&realm->subs, subs);
1536 /* don't send confirmation if we're not the initial server contacted */
1537 if (!(server_which_server(who) || found == 0)) {
1539 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1540 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1541 snotice.z_port = srv_addr.sin_port;
1542 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1543 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1544 error_message(retval));
1545 free_string(sender);
1549 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1550 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1551 error_message(retval));
1552 free_string(sender);
1557 realm_handoff(&snotice, 1, who, realm, 0);
1560 free_string(sender);
1565 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1566 Code_t subscr_foreign_user(ZNotice_t *notice,
1567 struct sockaddr_in *who,
1571 Destlist *newsubs, *temp;
1575 struct sockaddr_in newwho;
1576 char *cp, *tp0, *tp1;
1577 char rlm_recipient[REALM_SZ + 1];
1580 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1583 tp0 = cp = notice->z_message;
1585 newwho.sin_addr.s_addr = inet_addr(cp);
1586 if (newwho.sin_addr.s_addr == -1) {
1587 syslog(LOG_ERR, "malformed addr from %s", notice->z_sender);
1596 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1599 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1600 error_message(status));
1606 snotice.z_message = cp;
1607 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1609 newsubs = extract_subscriptions(&snotice);
1611 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1615 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1616 /* this was approved by the other realm, add subscriptions */
1618 if (!strcmp(tp0, "0.0.0.0")) {
1619 /* skip bogus ADD reply from subscr_realm_subs */
1620 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1624 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1625 client = client_find(&newwho.sin_addr, snotice.z_port);
1626 if (client == (Client *)0) {
1627 syslog(LOG_WARNING, "no client at %s/%d",
1628 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1629 free_subscriptions(newsubs);
1633 /* translate the recipient to represent the foreign realm */
1634 sprintf(rlm_recipient, "@%s", realm->name);
1635 for (temp = newsubs; temp; temp = temp->next) {
1637 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1639 temp->dest.recip = make_string(rlm_recipient, 0);
1642 status = subscr_add_raw(client, (ZRealm *)0, newsubs);
1643 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1644 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1645 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1647 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",