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();
69 /* for compatibility when sending subscription information to old clients */
72 #define OLD_ZEPHYR_VERSION "ZEPH0.0"
73 #define OLD_CLIENT_INCOMPSUBS "INCOMP"
74 static void old_compat_subscr_sendlist(ZNotice_t *notice, int auth,
75 struct sockaddr_in *who);
76 extern int old_compat_count_subscr; /* counter of old use */
77 #endif /* OLD_COMPAT */
79 #define NEW_OLD_ZEPHYR_VERSION "ZEPH0.1"
80 static void new_old_compat_subscr_sendlist(ZNotice_t *notice, int auth,
81 struct sockaddr_in *who);
82 extern int new_compat_count_subscr; /* counter of old use */
83 #endif /* NEW_COMPAT */
85 static Code_t add_subscriptions(Client *who, Destlist *subs_queue,
86 ZNotice_t *notice, Server *server);
87 static Destlist *extract_subscriptions(ZNotice_t *notice);
88 static void free_subscriptions(Destlist *subs);
89 static void free_subscription(Destlist *sub);
90 static char **subscr_marshal_subs(ZNotice_t *notice, int auth,
91 struct sockaddr_in *who,
93 static Destlist *subscr_copy_def_subs(char *person);
94 static Code_t subscr_realm_sendit(Client *who, Destlist *subs,
95 ZNotice_t *notice, ZRealm *realm);
96 static void subscr_unsub_sendit(Client *who, Destlist *subs,
99 static int defaults_read = 0; /* set to 1 if the default subs
101 static ZNotice_t default_notice; /* contains default subscriptions */
103 String *wildcard_instance;
106 /* WARNING: make sure this is the same as the number of strings you */
107 /* plan to hand back to the user in response to a subscription check, */
108 /* else you will lose. See subscr_sendlist() */
112 * subscribe the client to types described in notice.
116 subscr_subscribe(Client *who,
122 subs = extract_subscriptions(notice);
123 return add_subscriptions(who, subs, notice, server);
127 add_subscriptions(Client *who,
136 ZRealm *realm = NULL;
139 return ZERR_NONE; /* no subscr -> no error */
141 sender = make_string(notice->z_sender, 0);
143 /* Loop over the new subscriptions. */
144 for (; subs; subs = next) {
147 zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
148 subs->dest.inst->string, subs->dest.recip->string));
150 /* check the recipient for a realm which isn't ours */
152 if (subs->dest.recip->string[0] == '@' &&
153 strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
154 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
156 if (subs->dest.recip != empty && subs->dest.recip != sender
157 && subs->dest.recip->string[0] != '@') {
158 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
159 sender->string, subs->dest.recip->string);
160 free_subscription(subs); /* free this one - denied */
161 continue; /* the for loop */
163 acl = class_get_acl(subs->dest.classname);
165 if (!access_check(sender->string, acl, SUBSCRIBE)) {
166 syslog(LOG_WARNING, "subscr unauth %s class %s",
167 sender->string, subs->dest.classname->string);
168 free_subscription(subs); /* free this one - denied */
169 continue; /* the for loop */
171 if (wildcard_instance == subs->dest.inst) {
172 if (!access_check(sender->string, acl, INSTWILD)) {
174 "subscr unauth %s class %s wild inst",
175 sender->string, subs->dest.classname->string);
176 free_subscription(subs); /* free this one - denied */
177 continue; /* the for loop */
182 if (realm && !bdumping) {
183 retval = subscr_realm_sendit(who, subs, notice, realm);
184 if (retval != ZERR_NONE) {
185 free_subscription(subs);
186 continue; /* the for loop */
188 /* Indicates we leaked traffic back to our realm */
189 free_subscription(subs); /* free this one, wil get from
193 retval = triplet_register(who, &subs->dest, NULL);
194 if (retval != ZERR_NONE) {
195 if (retval == ZSRV_CLASSXISTS) {
196 free_subscription(subs); /* free this one */
198 free_subscriptions(subs);
203 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
204 Destlist_insert(&who->subs, subs);
214 * add default subscriptions to the client's subscription chain.
218 subscr_def_subs(Client *who)
222 subs = subscr_copy_def_subs(who->principal->string);
223 return add_subscriptions(who, subs, &default_notice, NULL);
230 zdbug((LOG_DEBUG, "subscr_reset()"));
232 free(default_notice.z_message);
233 default_notice.z_message = NULL;
238 subscr_copy_def_subs(char *person)
242 char *def_sub_area, *cp;
243 Destlist *subs, *sub;
245 if (!defaults_read) {
247 zdbug((LOG_DEBUG, "reading default subscription file"));
249 fd = open(subs_file, O_RDONLY, 0666);
251 syslog(LOG_ERR, "can't open %s:%m", subs_file);
254 retval = fstat(fd, &statbuf);
256 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
260 def_sub_area = (char *) malloc(statbuf.st_size + 1);
262 syslog(LOG_ERR, "no mem copy_def_subs");
266 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
267 if (retval != statbuf.st_size) {
268 syslog(LOG_ERR, "short read in copy_def_subs");
274 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
277 def_subs_area now points to a buffer full of subscription info.
278 Each line of the stuff is of the form:
281 Commas and newlines may not appear as part of the class,
282 instance, or recipient. XXX!
285 /* split up the subscription info */
286 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
287 if (*cp == '\n' || *cp == ',')
290 default_notice.z_message = def_sub_area;
291 default_notice.z_message_len = statbuf.st_size + 1;
292 default_notice.z_auth = 1;
296 /* needed later for access_check() */
297 default_notice.z_sender = person;
298 subs = extract_subscriptions(&default_notice);
299 /* replace any non-* recipients with "person" */
301 for (sub = subs; sub; sub = sub->next) {
302 /* if not a wildcard, replace it with person */
303 if (strcmp(sub->dest.recip->string, "*")) {
304 free_string(sub->dest.recip);
305 sub->dest.recip = make_string(person, 0);
306 } else { /* replace with null recipient */
307 free_string(sub->dest.recip);
308 sub->dest.recip = dup_string(empty);
315 * Cancel a specific set of subscriptions.
319 subscr_cancel(struct sockaddr_in *sin,
324 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
329 zdbug((LOG_DEBUG,"subscr_cancel"));
331 who = client_find(&sin->sin_addr, notice->z_port);
338 cancel_subs = extract_subscriptions(notice);
340 return ZERR_NONE; /* no subscr -> no error */
342 for (subs = cancel_subs; subs; subs = cancel_next) {
343 cancel_next = subs->next;
344 for (client_subs = who->subs; client_subs; client_subs = client_next) {
345 client_next = client_subs->next;
346 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
347 Destlist_delete(client_subs);
348 retval = triplet_deregister(who, &client_subs->dest, NULL);
349 if (retval == ZSRV_EMPTYCLASS &&
350 client_subs->dest.recip->string[0] == '@') {
352 realm_get_realm_by_name(client_subs->dest.recip->string
355 subscr_unsub_sendit(who, client_subs, realm);
358 free_subscription(client_subs);
365 free_subscriptions(cancel_subs);
369 zdbug((LOG_DEBUG, "found & removed"));
374 zdbug((LOG_DEBUG, "not found"));
381 subscr_realm_cancel(struct sockaddr_in *sin,
385 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
395 cancel_subs = extract_subscriptions(notice);
397 return ZERR_NONE; /* no subscr -> no error */
399 for (subs = cancel_subs; subs; subs = next) {
401 for (client_subs = realm->subs; client_subs; client_subs = next2) {
402 next2 = client_subs->next;
403 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
404 Destlist_delete(client_subs);
405 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
406 free_subscription(client_subs);
413 free_subscriptions(cancel_subs);
417 zdbug((LOG_DEBUG, "found & removed"));
422 zdbug((LOG_DEBUG, "not found"));
429 * Cancel all the subscriptions for this client.
433 subscr_cancel_client(Client *client)
435 Destlist *subs, *next;
440 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
441 inet_ntoa(client->addr.sin_addr)));
446 for (subs = client->subs; subs; subs = next) {
449 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
451 retval = triplet_deregister(client, &subs->dest, NULL);
452 if (retval == ZSRV_EMPTYCLASS &&
453 subs->dest.recip->string[0] == '@') {
454 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
456 subscr_unsub_sendit(client, subs, realm);
459 free_subscription(subs);
466 * Send the requester a list of his current subscriptions
470 subscr_sendlist(ZNotice_t *notice,
472 struct sockaddr_in *who)
476 struct sockaddr_in send_to_who;
480 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
481 /* we are talking to an old client; use the old-style
482 acknowledgement-message */
483 old_compat_subscr_sendlist(notice, auth, who);
486 #endif /* OLD_COMPAT */
488 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
489 /* we are talking to a new old client; use the new-old-style
490 acknowledgement-message */
491 new_old_compat_subscr_sendlist(notice, auth, who);
494 #endif /* NEW_COMPAT */
495 answer = subscr_marshal_subs(notice, auth, who, &found);
497 send_to_who.sin_port = notice->z_port; /* Return port */
499 retval = ZSetDestAddr(&send_to_who);
500 if (retval != ZERR_NONE) {
501 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
502 error_message(retval));
508 /* XXX for now, don't do authentication */
511 notice->z_kind = ACKED;
513 /* use xmit_frag() to send each piece of the notice */
515 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
516 if (retval != ZERR_NONE)
517 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
523 subscr_marshal_subs(ZNotice_t *notice,
525 struct sockaddr_in *who,
528 char **answer = NULL;
532 Destlist *subs = NULL, *sub;
537 zdbug((LOG_DEBUG, "subscr_marshal"));
541 /* Note that the following code is an incredible crock! */
543 /* We cannot send multiple packets as acknowledgements to the client,
544 since the hostmanager will ignore the later packets. So we need
545 to send directly to the client. */
547 /* Make our own copy so we can send directly back to the client */
550 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
551 /* If the client has requested his current subscriptions,
552 the message field of the notice contains the port number
553 of the client for which the sender desires the subscription
554 list. The port field is the port of the sender. */
556 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
557 if (retval != ZERR_NONE) {
558 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
559 error_message(retval));
563 client = client_find(&who->sin_addr, htons(temp));
567 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
569 zdbug((LOG_DEBUG, "gimmedefs"));
571 /* subscr_copy_def_subs allocates new pointer rings, so
572 it must be freed when finished.
573 the string areas pointed to are static, however.*/
574 subs = subscr_copy_def_subs(notice->z_sender);
577 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
584 /* check authenticity here. The user must be authentic to get
585 a list of subscriptions. If he is not subscribed to
586 anything, this if-clause fails, and he gets a response
587 indicating no subscriptions.
588 if retrieving default subscriptions, don't care about
591 if (!auth && !defsubs)
594 if (client && (strcmp(client->principal->string,
595 notice->z_sender) != 0)) {
597 "subscr_marshal: %s requests subs for %s at %s/%d",
598 notice->z_sender, client->principal->string,
599 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
604 for (sub = subs; sub; sub = sub->next)
607 /* found is now the number of subscriptions */
609 /* coalesce the subscription information into a list of char *'s */
610 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
611 if (answer == NULL) {
612 syslog(LOG_ERR, "subscr no mem(answer)");
616 for (sub = subs; sub; sub = sub->next) {
617 answer[i * NUM_FIELDS] = sub->dest.classname->string;
618 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
619 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
625 free_subscriptions(subs);
631 new_old_compat_subscr_sendlist(notice, auth, who)
634 struct sockaddr_in *who;
639 int packlen, found, count, initfound, zerofound;
642 struct sockaddr_in send_to_who;
645 new_compat_count_subscr++;
647 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
649 reply.z_kind = SERVACK;
650 reply.z_authent_len = 0; /* save some space */
654 send_to_who.sin_port = notice->z_port; /* Return port */
656 retval = ZSetDestAddr(&send_to_who);
657 if (retval != ZERR_NONE) {
658 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
659 error_message(retval));
663 /* retrieve the subscriptions */
664 answer = subscr_marshal_subs(notice, auth, who, &found);
666 /* note that when there are no subscriptions, found == 0, so
667 we needn't worry about answer being NULL since
668 ZFormatSmallRawNoticeList won't reference the pointer */
670 /* send 5 at a time until we are finished */
671 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
672 i = 0; /* pkt # counter */
674 zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
677 zerofound = (found == 0);
678 while (found > 0 || zerofound) {
679 packlen = sizeof(reppacket);
680 sprintf(buf, "%d/%d", ++i, count);
681 reply.z_opcode = buf;
682 retval = ZFormatSmallRawNoticeList(&reply,
683 answer + (initfound - found)
685 ((found > 5) ? 5 : found)
687 reppacket, &packlen);
688 if (retval != ZERR_NONE) {
689 syslog(LOG_ERR, "subscr_sendlist format: %s",
690 error_message(retval));
695 retval = ZSendPacket(reppacket, packlen, 0);
696 if (retval != ZERR_NONE) {
697 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
698 error_message(retval));
707 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
712 #endif /* NEW_COMPAT */
716 old_compat_subscr_sendlist(notice, auth, who)
719 struct sockaddr_in *who;
721 Client *client = client_find(&who->sin_addr, notice->z_port);
726 int packlen, i, found = 0;
727 char **answer = NULL;
729 old_compat_count_subscr++;
731 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
732 if (client && client->subs) {
734 /* check authenticity here. The user must be authentic to get
735 a list of subscriptions. If he is not subscribed to
736 anything, the above test fails, and he gets a response
737 indicating no subscriptions */
740 clt_ack(notice, who, AUTH_FAILED);
744 for (subs = client->subs; subs; subs = subs->next)
746 /* found is now the number of subscriptions */
748 /* coalesce the subscription information into a list of char *'s */
749 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
751 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
755 for (subs = client->subs; subs; subs = subs->next) {
756 answer[i*NUM_FIELDS] = subs->dest.classname->string;
757 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
758 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
764 /* note that when there are no subscriptions, found == 0, so
765 we needn't worry about answer being NULL */
768 reply.z_kind = SERVACK;
769 reply.z_authent_len = 0; /* save some space */
772 /* if it's too long, chop off one at a time till it fits */
773 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
776 &packlen)) != ZERR_PKTLEN) {
778 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
780 if (retval != ZERR_NONE) {
781 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
782 error_message(retval));
787 retval = ZSetDestAddr(who);
788 if (retval != ZERR_NONE) {
789 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
790 error_message(retval));
795 retval = ZSendPacket(reppacket, packlen, 0);
796 if (retval != ZERR_NONE) {
797 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
798 error_message(retval));
804 zdbug((LOG_DEBUG,"subscr_sendlist acked"));
809 #endif /* OLD_COMPAT */
812 * Send the client's subscriptions to another server
815 /* version is currently unused; if necessary later versions may key off it
816 to determine what to send to the peer (protocol changes) */
820 subscr_send_subs(Client *client)
831 #endif /* HAVE_KRB4 */
834 char *list[7 * NUM_FIELDS];
839 zdbug((LOG_DEBUG, "send_subs"));
841 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
846 #ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
847 if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
848 bufp = malloc(Z_keylen(client->session_keyblock));
850 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
853 des_ecb_encrypt((C_Block *)Z_keydata(client->session_keyblock), (C_Block *)bufp, serv_ksched.s, DES_ENCRYPT);
854 retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
857 bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
860 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
863 *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
864 *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
865 memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
867 retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
870 #endif /* HAVE_KRB4 */
871 #else /* HAVE_KRB5 */
873 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
875 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
876 #endif /* HAVE_KRB4 */
877 #endif /* HAVE_KRB5 */
879 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
880 if (retval != ZERR_NONE) {
882 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
887 zdbug((LOG_DEBUG, "cblock %s", buf));
890 #endif /* HAVE_KRB4 || HAVE_KRB5*/
891 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
892 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
893 client->principal->string, "", list, num);
894 if (retval != ZERR_NONE) {
895 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
902 for (subs = client->subs; subs; subs = subs->next) {
903 /* for each subscription */
904 list[i * NUM_FIELDS] = subs->dest.classname->string;
905 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
906 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
909 /* we only put 7 in each packet, so we don't run out of room */
910 retval = bdump_send_list_tcp(ACKED, &client->addr,
911 ZEPHYR_CTL_CLASS, "",
912 CLIENT_SUBSCRIBE, "", "", list,
914 if (retval != ZERR_NONE) {
915 syslog(LOG_ERR, "subscr_send_subs subs: %s",
916 error_message(retval));
923 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
924 "", CLIENT_SUBSCRIBE, "", "", list,
926 if (retval != ZERR_NONE) {
927 syslog(LOG_ERR, "subscr_send_subs subs: %s",
928 error_message(retval));
937 * free the memory allocated for the list of subscriptions.
941 * free the memory allocated for one subscription.
945 free_subscription(Destlist *sub)
947 free_string(sub->dest.classname);
948 free_string(sub->dest.inst);
949 free_string(sub->dest.recip);
954 free_subscriptions(Destlist *subs)
958 for (; subs; subs = next) {
960 free_subscription (subs);
964 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
965 if (cp >= notice->z_message + notice->z_message_len) { \
966 syslog(LOG_WARNING, "malformed subscription %d", \
972 * Parse the message body, returning a linked list of subscriptions, or
973 * NULL if there are no subscriptions there.
977 extract_subscriptions(ZNotice_t *notice)
979 Destlist *subs = NULL, *sub;
980 char *recip, *class_name, *classinst;
981 char *cp = notice->z_message;
983 /* parse the data area for the subscriptions */
984 while (cp < notice->z_message + notice->z_message_len) {
986 if (*cp == '\0') /* we've exhausted the subscriptions */
993 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
994 class_name, classinst, cp));
996 cp += (strlen(cp) + 1);
997 if (cp > notice->z_message + notice->z_message_len) {
998 syslog(LOG_WARNING, "malformed sub 3");
1001 sub = (Destlist *) malloc(sizeof(Destlist));
1003 syslog(LOG_WARNING, "ex_subs: no mem 2");
1006 sub->dest.classname = make_string(class_name, 1);
1007 sub->dest.inst = make_string(classinst, 1);
1008 /* Nuke @REALM if REALM is us. */
1009 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
1010 sub->dest.recip = make_string("", 0);
1012 sub->dest.recip = make_string(recip, 0);
1013 Destlist_insert(&subs, sub);
1019 * print subscriptions in subs onto fp.
1020 * assumed to be called with SIGFPE blocked
1021 * (true if called from signal handler)
1025 subscr_dump_subs(FILE *fp,
1028 if (!subs) /* no subscriptions to dump */
1031 for (; subs; subs = subs->next) {
1033 dump_quote(subs->dest.classname->string, fp);
1035 dump_quote(subs->dest.inst->string, fp);
1037 dump_quote(subs->dest.recip->string, fp);
1042 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
1043 if (cp >= notice->z_message + notice->z_message_len) { \
1044 syslog(LOG_WARNING, "malformed subscription %d", \
1046 return (ZERR_NONE); \
1049 /* As it exists, this function expects to take only the first sub from the
1050 * Destlist. At some point, it and the calling code should be replaced */
1052 subscr_realm_sendit(Client *who,
1062 char addr[16]; /* xxx.xxx.xxx.xxx max */
1066 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1070 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1071 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1074 /* convert the address to a string of the form x.x.x.x/port */
1075 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1076 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1077 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1079 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1080 error_message(retval));
1086 text[2] = subs->dest.classname->string;
1087 text[3] = subs->dest.inst->string;
1088 text[4] = subs->dest.recip->string;
1090 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1091 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1093 /* format snotice */
1094 memset (&snotice, 0, sizeof(snotice));
1095 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1096 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1097 snotice.z_port = srv_addr.sin_port;
1099 snotice.z_class = ZEPHYR_CTL_CLASS;
1101 snotice.z_recipient = "";
1102 snotice.z_kind = ACKED;
1103 snotice.z_num_other_fields = 0;
1104 snotice.z_default_format = "";
1105 snotice.z_sender = who->principal->string;
1106 snotice.z_recipient = notice->z_recipient;
1107 snotice.z_default_format = notice->z_default_format;
1109 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1110 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1112 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1113 error_message(retval));
1119 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1120 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1121 error_message(retval));
1127 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1129 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1135 /* Called from subscr_realm and subscr_foreign_user */
1137 subscr_add_raw(Client *client,
1141 Destlist *subs, *subs2, **head;
1145 zdbug((LOG_DEBUG, "subscr_add_raw"));
1147 head = (realm) ? &realm->subs : &client->subs;
1149 /* Loop over the new subscriptions. */
1150 for (subs = newsubs; subs; subs = subs2) {
1153 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1155 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1157 retval = triplet_register(client, &subs->dest, realm);
1158 if (retval != ZERR_NONE) {
1159 free_subscription(subs);
1160 if (retval == ZSRV_CLASSXISTS) {
1163 free_subscriptions(subs2);
1169 realm_get_realm_by_name(subs->dest.recip->string + 1);
1171 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1173 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1175 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1176 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1177 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1179 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1180 sub->dest.classname->string, sub->dest.inst->string,
1181 sub->dest.recip->string, remrealm->name));
1183 Destlist_insert(&remrealm->remsubs, sub);
1188 Destlist_insert(head, subs);
1193 /* Called from bdump_recv_loop to decapsulate realm subs */
1195 subscr_realm(ZRealm *realm,
1200 newsubs = extract_subscriptions(notice);
1203 syslog(LOG_WARNING, "empty subs in subscr_realm");
1207 return(subscr_add_raw(realm->client, realm, newsubs));
1210 /* Like realm_sendit, this only takes one item from subs */
1212 subscr_unsub_sendit(Client *who,
1221 Destlist *subsp, *subsn;
1223 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1224 subsn = subsp->next;
1225 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1227 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1228 subsp->dest.classname->string, subsp->dest.inst->string,
1229 subsp->dest.recip->string, realm->name));
1231 Destlist_delete(subsp);
1232 free_subscription(subsp);
1237 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1238 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1242 list[0] = subs->dest.classname->string;
1243 list[1] = subs->dest.inst->string;
1246 unotice.z_class = ZEPHYR_CTL_CLASS;
1247 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1248 unotice.z_opcode = REALM_UNSUBSCRIBE;
1249 unotice.z_recipient = "";
1250 unotice.z_kind = ACKED;
1252 unotice.z_sender = "";
1253 unotice.z_port = srv_addr.sin_port;
1254 unotice.z_num_other_fields = 0;
1255 unotice.z_default_format = "";
1257 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1258 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1259 error_message(retval));
1265 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1266 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1267 error_message(retval));
1271 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1275 /* Called from bump_send_loop by way of realm_send_realms */
1277 subscr_send_realm_subs(ZRealm *realm)
1280 Destlist *subs, *next;
1282 char *list[7 * NUM_FIELDS];
1287 zdbug((LOG_DEBUG, "send_realm_subs"));
1290 strcpy(buf, realm->name);
1293 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1294 "", ADMIN_NEWREALM, "", "", list, num);
1295 if (retval != ZERR_NONE) {
1296 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1303 for (subs=realm->subs; subs; subs = next) {
1306 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1307 subs->dest.inst->string, subs->dest.recip->string));
1309 /* for each subscription */
1310 list[i * NUM_FIELDS] = subs->dest.classname->string;
1311 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1312 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1315 /* we only put 7 in each packet, so we don't run out of room */
1316 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1317 ZEPHYR_CTL_CLASS, "",
1318 REALM_SUBSCRIBE, "", "", list,
1320 if (retval != ZERR_NONE) {
1321 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1322 error_message(retval));
1329 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1330 "", REALM_SUBSCRIBE, "", "", list,
1332 if (retval != ZERR_NONE) {
1333 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1334 error_message(retval));
1343 subscr_realm_subs(ZRealm *realm)
1345 Destlist *subs, *next;
1346 char *text[2 + NUM_FIELDS];
1347 unsigned short num = 0;
1356 zdbug((LOG_DEBUG, "realm_subs"));
1359 if (!realm->remsubs)
1362 for (subs=realm->remsubs; subs; subs = next) {
1365 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1366 subs->dest.inst->string, subs->dest.recip->string));
1370 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1371 &num, sizeof(u_short))) != ZERR_NONE)
1373 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1374 error_message(retval));
1378 text[0] = "0.0.0.0";
1380 text[2] = subs->dest.classname->string;
1381 text[3] = subs->dest.inst->string;
1382 text[4] = subs->dest.recip->string;
1384 /* format snotice */
1385 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1386 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1388 snotice.z_class = ZEPHYR_CTL_CLASS;
1390 snotice.z_recipient = "";
1391 snotice.z_kind = ACKED;
1392 snotice.z_num_other_fields = 0;
1393 snotice.z_default_format = "";
1394 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1395 resubmit them as the sender. */
1396 clientp = triplet_lookup(&subs->dest);
1398 snotice.z_sender = "";
1400 snotice.z_sender = (*clientp)->principal->string;
1401 snotice.z_default_format = "";
1403 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1404 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1406 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1407 error_message(retval));
1411 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1412 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1413 error_message(retval));
1417 realm_handoff(&snotice, 1, NULL, realm, 0);
1424 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1426 subscr_check_foreign_subs(ZNotice_t *notice,
1427 struct sockaddr_in *who,
1432 Destlist *subs, *next;
1442 for (subs = newsubs; subs; subs = subs->next)
1448 sender = make_string(notice->z_sender, 0);
1450 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1452 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1453 free_string(sender);
1457 /* grab the client information from the incoming message */
1458 cp = notice->z_message;
1467 for (subs = newsubs; subs; subs = next) {
1470 if (subs->dest.recip->string[0] != '\0') {
1471 rlm = realm_which_realm(who);
1472 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1473 subs->dest.recip->string,
1474 sender->string, rlm->name);
1477 acl = class_get_acl(subs->dest.classname);
1479 rlm = realm_which_realm(who);
1480 if (rlm && server == me_server) {
1481 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1482 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1483 sender->string, rlm->name,
1484 subs->dest.classname->string);
1485 free_subscriptions(newsubs);
1486 free_string(sender);
1488 return ZSRV_CLASSRESTRICTED;
1491 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1492 syslog(LOG_WARNING, "subscr unauth %s class %s",
1493 sender->string, subs->dest.classname->string);
1494 continue; /* the for loop */
1496 if (wildcard_instance == subs->dest.inst) {
1497 if (!access_check(sender->string, acl, INSTWILD)) {
1499 "subscr unauth %s class %s wild inst",
1500 sender->string, subs->dest.classname->string);
1506 /* okay to subscribe. save for return trip */
1507 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1508 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1509 text[found*NUM_FIELDS + 4] = "";
1512 retval = triplet_register(realm->client, &subs->dest, realm);
1514 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1515 subs->dest.inst->string, subs->dest.recip->string));
1518 if (retval != ZERR_NONE) {
1519 if (retval == ZSRV_CLASSXISTS) {
1522 free_subscriptions(newsubs); /* subs->next XXX */
1523 free_string(sender);
1528 Destlist_insert(&realm->subs, subs);
1530 /* don't send confirmation if we're not the initial server contacted */
1531 if (!(server_which_server(who) || found == 0)) {
1533 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1534 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1535 snotice.z_port = srv_addr.sin_port;
1536 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1537 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1538 error_message(retval));
1539 free_string(sender);
1543 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1544 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1545 error_message(retval));
1546 free_string(sender);
1551 realm_handoff(&snotice, 1, who, realm, 0);
1554 free_string(sender);
1559 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1560 Code_t subscr_foreign_user(ZNotice_t *notice,
1561 struct sockaddr_in *who,
1565 Destlist *newsubs, *temp;
1569 struct sockaddr_in newwho;
1570 char *cp, *tp0, *tp1;
1571 char rlm_recipient[REALM_SZ + 1];
1574 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1577 tp0 = cp = notice->z_message;
1579 newwho.sin_addr.s_addr = inet_addr(cp);
1580 if (newwho.sin_addr.s_addr == -1) {
1581 syslog(LOG_ERR, "malformed addr from %s", notice->z_sender);
1590 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1593 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1594 error_message(status));
1600 snotice.z_message = cp;
1601 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1603 newsubs = extract_subscriptions(&snotice);
1605 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1609 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1610 /* this was approved by the other realm, add subscriptions */
1612 if (!strcmp(tp0, "0.0.0.0")) {
1613 /* skip bogus ADD reply from subscr_realm_subs */
1614 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1618 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1619 client = client_find(&newwho.sin_addr, snotice.z_port);
1620 if (client == (Client *)0) {
1621 syslog(LOG_WARNING, "no client at %s/%d",
1622 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1623 free_subscriptions(newsubs);
1627 /* translate the recipient to represent the foreign realm */
1628 sprintf(rlm_recipient, "@%s", realm->name);
1629 for (temp = newsubs; temp; temp = temp->next) {
1631 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1633 temp->dest.recip = make_string(rlm_recipient, 0);
1636 status = subscr_add_raw(client, (ZRealm *)0, newsubs);
1637 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1638 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1639 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1641 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",