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();
64 #if defined(HAVE_KRB4) || defined(HAVE_OPENSSL)
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) {
146 /* check the recipient for a realm which isn't ours */
148 if (subs->dest.recip->string[0] == '@' &&
149 strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
150 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
152 if (subs->dest.recip != empty && subs->dest.recip != sender
153 && subs->dest.recip->string[0] != '@') {
154 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
155 sender->string, subs->dest.recip->string);
156 free_subscription(subs); /* free this one - denied */
157 continue; /* the for loop */
159 acl = class_get_acl(subs->dest.classname);
161 if (!access_check(sender->string, acl, SUBSCRIBE)) {
162 syslog(LOG_WARNING, "subscr unauth %s class %s",
163 sender->string, subs->dest.classname->string);
164 free_subscription(subs); /* free this one - denied */
165 continue; /* the for loop */
167 if (wildcard_instance == subs->dest.inst) {
168 if (!access_check(sender->string, acl, INSTWILD)) {
170 "subscr unauth %s class %s wild inst",
171 sender->string, subs->dest.classname->string);
172 free_subscription(subs); /* free this one - denied */
173 continue; /* the for loop */
178 if (realm && !bdumping) {
179 retval = subscr_realm_sendit(who, subs, notice, realm);
180 if (retval != ZERR_NONE) {
181 free_subscription(subs);
182 continue; /* the for loop */
184 /* Indicates we leaked traffic back to our realm */
185 free_subscription(subs); /* free this one, wil get from
189 retval = triplet_register(who, &subs->dest, NULL);
190 if (retval != ZERR_NONE) {
191 if (retval == ZSRV_CLASSXISTS) {
192 free_subscription(subs); /* free this one */
194 free_subscriptions(subs);
199 /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
200 Destlist_insert(&who->subs, subs);
210 * add default subscriptions to the client's subscription chain.
214 subscr_def_subs(Client *who)
218 subs = subscr_copy_def_subs(who->principal->string);
219 return add_subscriptions(who, subs, &default_notice, NULL);
225 free(default_notice.z_message);
226 default_notice.z_message = NULL;
231 subscr_copy_def_subs(char *person)
235 char *def_sub_area, *cp;
236 Destlist *subs, *sub;
238 if (!defaults_read) {
239 fd = open(subs_file, O_RDONLY, 0666);
241 syslog(LOG_ERR, "can't open %s:%m", subs_file);
244 retval = fstat(fd, &statbuf);
246 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
250 def_sub_area = (char *) malloc(statbuf.st_size + 1);
252 syslog(LOG_ERR, "no mem copy_def_subs");
256 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
257 if (retval != statbuf.st_size) {
258 syslog(LOG_ERR, "short read in copy_def_subs");
264 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
267 def_subs_area now points to a buffer full of subscription info.
268 Each line of the stuff is of the form:
271 Commas and newlines may not appear as part of the class,
272 instance, or recipient. XXX!
275 /* split up the subscription info */
276 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
277 if (*cp == '\n' || *cp == ',')
280 default_notice.z_message = def_sub_area;
281 default_notice.z_message_len = statbuf.st_size + 1;
282 default_notice.z_auth = 1;
286 /* needed later for access_check() */
287 default_notice.z_sender = person;
288 subs = extract_subscriptions(&default_notice);
289 /* replace any non-* recipients with "person" */
291 for (sub = subs; sub; sub = sub->next) {
292 /* if not a wildcard, replace it with person */
293 if (strcmp(sub->dest.recip->string, "*")) {
294 free_string(sub->dest.recip);
295 sub->dest.recip = make_string(person, 0);
296 } else { /* replace with null recipient */
297 free_string(sub->dest.recip);
298 sub->dest.recip = dup_string(empty);
305 * Cancel a specific set of subscriptions.
309 subscr_cancel(struct sockaddr_in *sin,
314 Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
318 who = client_find(&sin->sin_addr, notice->z_port);
325 cancel_subs = extract_subscriptions(notice);
327 return ZERR_NONE; /* no subscr -> no error */
329 for (subs = cancel_subs; subs; subs = cancel_next) {
330 cancel_next = subs->next;
331 for (client_subs = who->subs; client_subs; client_subs = client_next) {
332 client_next = client_subs->next;
333 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
334 Destlist_delete(client_subs);
335 retval = triplet_deregister(who, &client_subs->dest, NULL);
336 if (retval == ZSRV_EMPTYCLASS &&
337 client_subs->dest.recip->string[0] == '@') {
339 realm_get_realm_by_name(client_subs->dest.recip->string
342 subscr_unsub_sendit(who, client_subs, realm);
345 free_subscription(client_subs);
352 free_subscriptions(cancel_subs);
362 subscr_realm_cancel(struct sockaddr_in *sin,
366 Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
376 cancel_subs = extract_subscriptions(notice);
378 return ZERR_NONE; /* no subscr -> no error */
380 for (subs = cancel_subs; subs; subs = next) {
382 for (client_subs = realm->subs; client_subs; client_subs = next2) {
383 next2 = client_subs->next;
384 if (ZDest_eq(&client_subs->dest, &subs->dest)) {
385 Destlist_delete(client_subs);
386 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
387 free_subscription(client_subs);
394 free_subscriptions(cancel_subs);
404 * Cancel all the subscriptions for this client.
408 subscr_cancel_client(Client *client)
410 Destlist *subs, *next;
417 for (subs = client->subs; subs; subs = next) {
419 retval = triplet_deregister(client, &subs->dest, NULL);
420 if (retval == ZSRV_EMPTYCLASS &&
421 subs->dest.recip->string[0] == '@') {
422 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
424 subscr_unsub_sendit(client, subs, realm);
427 free_subscription(subs);
434 * Send the requester a list of his current subscriptions
438 subscr_sendlist(ZNotice_t *notice,
440 struct sockaddr_in *who)
444 struct sockaddr_in send_to_who;
448 if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
449 /* we are talking to an old client; use the old-style
450 acknowledgement-message */
451 old_compat_subscr_sendlist(notice, auth, who);
454 #endif /* OLD_COMPAT */
456 if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
457 /* we are talking to a new old client; use the new-old-style
458 acknowledgement-message */
459 new_old_compat_subscr_sendlist(notice, auth, who);
462 #endif /* NEW_COMPAT */
463 answer = subscr_marshal_subs(notice, auth, who, &found);
465 send_to_who.sin_port = notice->z_port; /* Return port */
467 retval = ZSetDestAddr(&send_to_who);
468 if (retval != ZERR_NONE) {
469 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
470 error_message(retval));
476 /* XXX for now, don't do authentication */
479 notice->z_kind = ACKED;
481 /* use xmit_frag() to send each piece of the notice */
483 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
484 if (retval != ZERR_NONE)
485 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
491 subscr_marshal_subs(ZNotice_t *notice,
493 struct sockaddr_in *who,
496 char **answer = NULL;
500 Destlist *subs = NULL, *sub;
506 /* Note that the following code is an incredible crock! */
508 /* We cannot send multiple packets as acknowledgements to the client,
509 since the hostmanager will ignore the later packets. So we need
510 to send directly to the client. */
512 /* Make our own copy so we can send directly back to the client */
515 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
516 /* If the client has requested his current subscriptions,
517 the message field of the notice contains the port number
518 of the client for which the sender desires the subscription
519 list. The port field is the port of the sender. */
521 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
522 if (retval != ZERR_NONE) {
523 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
524 error_message(retval));
528 client = client_find(&who->sin_addr, htons(temp));
532 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
533 /* subscr_copy_def_subs allocates new pointer rings, so
534 it must be freed when finished.
535 the string areas pointed to are static, however.*/
536 subs = subscr_copy_def_subs(notice->z_sender);
539 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
546 /* check authenticity here. The user must be authentic to get
547 a list of subscriptions. If he is not subscribed to
548 anything, this if-clause fails, and he gets a response
549 indicating no subscriptions.
550 if retrieving default subscriptions, don't care about
553 if (!auth && !defsubs)
556 if (client && (strcmp(client->principal->string,
557 notice->z_sender) != 0)) {
559 "subscr_marshal: %s requests subs for %s at %s/%d",
560 notice->z_sender, client->principal->string,
561 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
566 for (sub = subs; sub; sub = sub->next)
569 /* found is now the number of subscriptions */
571 /* coalesce the subscription information into a list of char *'s */
572 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
573 if (answer == NULL) {
574 syslog(LOG_ERR, "subscr no mem(answer)");
578 for (sub = subs; sub; sub = sub->next) {
579 answer[i * NUM_FIELDS] = sub->dest.classname->string;
580 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
581 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
587 free_subscriptions(subs);
593 new_old_compat_subscr_sendlist(notice, auth, who)
596 struct sockaddr_in *who;
601 int packlen, found, count, initfound, zerofound;
604 struct sockaddr_in send_to_who;
607 new_compat_count_subscr++;
609 syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
611 reply.z_kind = SERVACK;
612 reply.z_authent_len = 0; /* save some space */
616 send_to_who.sin_port = notice->z_port; /* Return port */
618 retval = ZSetDestAddr(&send_to_who);
619 if (retval != ZERR_NONE) {
620 syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
621 error_message(retval));
625 /* retrieve the subscriptions */
626 answer = subscr_marshal_subs(notice, auth, who, &found);
628 /* note that when there are no subscriptions, found == 0, so
629 we needn't worry about answer being NULL since
630 ZFormatSmallRawNoticeList won't reference the pointer */
632 /* send 5 at a time until we are finished */
633 count = found?((found-1) / 5 + 1):1; /* total # to be sent */
634 i = 0; /* pkt # counter */
636 zerofound = (found == 0);
637 while (found > 0 || zerofound) {
638 packlen = sizeof(reppacket);
639 sprintf(buf, "%d/%d", ++i, count);
640 reply.z_opcode = buf;
641 retval = ZFormatSmallRawNoticeList(&reply,
642 answer + (initfound - found)
644 ((found > 5) ? 5 : found)
646 reppacket, &packlen);
647 if (retval != ZERR_NONE) {
648 syslog(LOG_ERR, "subscr_sendlist format: %s",
649 error_message(retval));
654 retval = ZSendPacket(reppacket, packlen, 0);
655 if (retval != ZERR_NONE) {
656 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
657 error_message(retval));
668 #endif /* NEW_COMPAT */
672 old_compat_subscr_sendlist(notice, auth, who)
675 struct sockaddr_in *who;
677 Client *client = client_find(&who->sin_addr, notice->z_port);
682 int packlen, i, found = 0;
683 char **answer = NULL;
685 old_compat_count_subscr++;
687 syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
688 if (client && client->subs) {
690 /* check authenticity here. The user must be authentic to get
691 a list of subscriptions. If he is not subscribed to
692 anything, the above test fails, and he gets a response
693 indicating no subscriptions */
696 clt_ack(notice, who, AUTH_FAILED);
700 for (subs = client->subs; subs; subs = subs->next)
702 /* found is now the number of subscriptions */
704 /* coalesce the subscription information into a list of char *'s */
705 answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
707 syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
711 for (subs = client->subs; subs; subs = subs->next) {
712 answer[i*NUM_FIELDS] = subs->dest.classname->string;
713 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
714 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
720 /* note that when there are no subscriptions, found == 0, so
721 we needn't worry about answer being NULL */
724 reply.z_kind = SERVACK;
725 reply.z_authent_len = 0; /* save some space */
728 /* if it's too long, chop off one at a time till it fits */
729 while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
732 &packlen)) != ZERR_PKTLEN) {
734 reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
736 if (retval != ZERR_NONE) {
737 syslog(LOG_ERR, "old_subscr_sendlist format: %s",
738 error_message(retval));
743 retval = ZSetDestAddr(who);
744 if (retval != ZERR_NONE) {
745 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
746 error_message(retval));
751 retval = ZSendPacket(reppacket, packlen, 0);
752 if (retval != ZERR_NONE) {
753 syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
754 error_message(retval));
762 #endif /* OLD_COMPAT */
765 * Send the client's subscriptions to another server
768 /* version is currently unused; if necessary later versions may key off it
769 to determine what to send to the peer (protocol changes) */
773 subscr_send_subs(Client *client)
784 #endif /* HAVE_KRB4 */
787 char *list[7 * NUM_FIELDS];
791 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
796 #ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
797 if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
798 bufp = malloc(Z_keylen(client->session_keyblock));
800 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
803 des_ecb_encrypt((C_Block *)Z_keydata(client->session_keyblock), (C_Block *)bufp, serv_ksched.s, DES_ENCRYPT);
804 retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
807 bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
810 syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
813 *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
814 *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
815 memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
817 retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
820 #endif /* HAVE_KRB4 */
821 #else /* HAVE_KRB5 */
823 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
825 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
826 #endif /* HAVE_KRB4 */
827 #endif /* HAVE_KRB5 */
829 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
830 if (retval != ZERR_NONE) {
834 #endif /* HAVE_KRB4 || HAVE_KRB5*/
835 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
836 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
837 client->principal->string, "", list, num);
838 if (retval != ZERR_NONE) {
839 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
846 for (subs = client->subs; subs; subs = subs->next) {
847 /* for each subscription */
848 list[i * NUM_FIELDS] = subs->dest.classname->string;
849 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
850 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
853 /* we only put 7 in each packet, so we don't run out of room */
854 retval = bdump_send_list_tcp(ACKED, &client->addr,
855 ZEPHYR_CTL_CLASS, "",
856 CLIENT_SUBSCRIBE, "", "", list,
858 if (retval != ZERR_NONE) {
859 syslog(LOG_ERR, "subscr_send_subs subs: %s",
860 error_message(retval));
867 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
868 "", CLIENT_SUBSCRIBE, "", "", list,
870 if (retval != ZERR_NONE) {
871 syslog(LOG_ERR, "subscr_send_subs subs: %s",
872 error_message(retval));
881 * free the memory allocated for the list of subscriptions.
885 * free the memory allocated for one subscription.
889 free_subscription(Destlist *sub)
891 free_string(sub->dest.classname);
892 free_string(sub->dest.inst);
893 free_string(sub->dest.recip);
898 free_subscriptions(Destlist *subs)
902 for (; subs; subs = next) {
904 free_subscription (subs);
908 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
909 if (cp >= notice->z_message + notice->z_message_len) { \
910 syslog(LOG_WARNING, "malformed subscription %d", \
916 * Parse the message body, returning a linked list of subscriptions, or
917 * NULL if there are no subscriptions there.
921 extract_subscriptions(ZNotice_t *notice)
923 Destlist *subs = NULL, *sub;
924 char *recip, *class_name, *classinst;
925 char *cp = notice->z_message;
927 /* parse the data area for the subscriptions */
928 while (cp < notice->z_message + notice->z_message_len) {
930 if (*cp == '\0') /* we've exhausted the subscriptions */
936 cp += (strlen(cp) + 1);
937 if (cp > notice->z_message + notice->z_message_len) {
938 syslog(LOG_WARNING, "malformed sub 3");
941 sub = (Destlist *) malloc(sizeof(Destlist));
943 syslog(LOG_WARNING, "ex_subs: no mem 2");
946 sub->dest.classname = make_string(class_name, 1);
947 sub->dest.inst = make_string(classinst, 1);
948 /* Nuke @REALM if REALM is us. */
949 if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
950 sub->dest.recip = make_string("", 0);
952 sub->dest.recip = make_string(recip, 0);
953 Destlist_insert(&subs, sub);
959 * print subscriptions in subs onto fp.
960 * assumed to be called with SIGFPE blocked
961 * (true if called from signal handler)
965 subscr_dump_subs(FILE *fp,
968 if (!subs) /* no subscriptions to dump */
971 for (; subs; subs = subs->next) {
973 dump_quote(subs->dest.classname->string, fp);
975 dump_quote(subs->dest.inst->string, fp);
977 dump_quote(subs->dest.recip->string, fp);
982 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
983 if (cp >= notice->z_message + notice->z_message_len) { \
984 syslog(LOG_WARNING, "malformed subscription %d", \
986 return (ZERR_NONE); \
989 /* As it exists, this function expects to take only the first sub from the
990 * Destlist. At some point, it and the calling code should be replaced */
992 subscr_realm_sendit(Client *who,
1002 char addr[16]; /* xxx.xxx.xxx.xxx max */
1005 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1006 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1009 /* convert the address to a string of the form x.x.x.x/port */
1010 strcpy(addr, inet_ntoa(who->addr.sin_addr));
1011 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1012 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
1014 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1015 error_message(retval));
1021 text[2] = subs->dest.classname->string;
1022 text[3] = subs->dest.inst->string;
1023 text[4] = subs->dest.recip->string;
1025 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
1026 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
1028 /* format snotice */
1029 memset (&snotice, 0, sizeof(snotice));
1030 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1031 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1032 snotice.z_port = srv_addr.sin_port;
1034 snotice.z_class = ZEPHYR_CTL_CLASS;
1036 snotice.z_recipient = "";
1037 snotice.z_kind = ACKED;
1038 snotice.z_num_other_fields = 0;
1039 snotice.z_sender = who->principal->string;
1040 snotice.z_recipient = notice->z_recipient;
1041 snotice.z_default_format = notice->z_default_format;
1043 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1044 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1046 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1047 error_message(retval));
1053 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1054 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1055 error_message(retval));
1060 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1066 /* Called from subscr_realm and subscr_foreign_user */
1068 subscr_add_raw(Client *client,
1072 Destlist *subs, *subs2, **head;
1075 head = (realm) ? &realm->subs : &client->subs;
1077 /* Loop over the new subscriptions. */
1078 for (subs = newsubs; subs; subs = subs2) {
1081 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1083 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1085 retval = triplet_register(client, &subs->dest, realm);
1086 if (retval != ZERR_NONE) {
1087 free_subscription(subs);
1088 if (retval == ZSRV_CLASSXISTS) {
1091 free_subscriptions(subs2);
1097 realm_get_realm_by_name(subs->dest.recip->string + 1);
1099 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
1101 syslog(LOG_WARNING, "subscr_add_raw: no mem");
1103 sub->dest.classname = make_string(subs->dest.classname->string, 0);
1104 sub->dest.inst = make_string(subs->dest.inst->string, 0);
1105 sub->dest.recip = make_string(subs->dest.recip->string, 0);
1106 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
1107 sub->dest.classname->string, sub->dest.inst->string,
1108 sub->dest.recip->string, remrealm->name));
1109 Destlist_insert(&remrealm->remsubs, sub);
1114 Destlist_insert(head, subs);
1119 /* Called from bdump_recv_loop to decapsulate realm subs */
1121 subscr_realm(ZRealm *realm,
1126 newsubs = extract_subscriptions(notice);
1129 syslog(LOG_WARNING, "empty subs in subscr_realm");
1133 return(subscr_add_raw(realm->client, realm, newsubs));
1136 /* Like realm_sendit, this only takes one item from subs */
1138 subscr_unsub_sendit(Client *who,
1147 Destlist *subsp, *subsn;
1149 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1150 subsn = subsp->next;
1151 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1152 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1153 subsp->dest.classname->string, subsp->dest.inst->string,
1154 subsp->dest.recip->string, realm->name));
1155 Destlist_delete(subsp);
1156 free_subscription(subsp);
1161 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1162 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1166 list[0] = subs->dest.classname->string;
1167 list[1] = subs->dest.inst->string;
1170 unotice.z_class = ZEPHYR_CTL_CLASS;
1171 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1172 unotice.z_opcode = REALM_UNSUBSCRIBE;
1173 unotice.z_recipient = "";
1174 unotice.z_kind = ACKED;
1176 unotice.z_sender = "";
1177 unotice.z_port = srv_addr.sin_port;
1178 unotice.z_num_other_fields = 0;
1179 unotice.z_default_format = "";
1181 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1182 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1183 error_message(retval));
1189 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1190 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1191 error_message(retval));
1195 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1199 /* Called from bump_send_loop by way of realm_send_realms */
1201 subscr_send_realm_subs(ZRealm *realm)
1204 Destlist *subs, *next;
1206 char *list[7 * NUM_FIELDS];
1210 strcpy(buf, realm->name);
1213 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1214 "", ADMIN_NEWREALM, "", "", list, num);
1215 if (retval != ZERR_NONE) {
1216 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1223 for (subs=realm->subs; subs; subs = next) {
1226 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1227 subs->dest.inst->string, subs->dest.recip->string));
1229 /* for each subscription */
1230 list[i * NUM_FIELDS] = subs->dest.classname->string;
1231 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1232 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1235 /* we only put 7 in each packet, so we don't run out of room */
1236 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1237 ZEPHYR_CTL_CLASS, "",
1238 REALM_SUBSCRIBE, "", "", list,
1240 if (retval != ZERR_NONE) {
1241 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1242 error_message(retval));
1249 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1250 "", REALM_SUBSCRIBE, "", "", list,
1252 if (retval != ZERR_NONE) {
1253 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1254 error_message(retval));
1263 subscr_realm_subs(ZRealm *realm)
1265 Destlist *subs, *next;
1266 char *text[2 + NUM_FIELDS];
1267 unsigned short num = 0;
1275 if (!realm->remsubs)
1278 for (subs=realm->remsubs; subs; subs = next) {
1281 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1282 subs->dest.inst->string, subs->dest.recip->string));
1286 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1287 &num, sizeof(u_short))) != ZERR_NONE)
1289 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1290 error_message(retval));
1294 text[0] = "0.0.0.0";
1296 text[2] = subs->dest.classname->string;
1297 text[3] = subs->dest.inst->string;
1298 text[4] = subs->dest.recip->string;
1300 /* format snotice */
1301 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1302 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1304 snotice.z_class = ZEPHYR_CTL_CLASS;
1306 snotice.z_recipient = "";
1307 snotice.z_kind = ACKED;
1308 snotice.z_num_other_fields = 0;
1309 snotice.z_default_format = "";
1310 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1311 resubmit them as the sender. */
1312 clientp = triplet_lookup(&subs->dest);
1314 snotice.z_sender = "";
1316 snotice.z_sender = (*clientp)->principal->string;
1318 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1319 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1321 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1322 error_message(retval));
1326 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1327 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1328 error_message(retval));
1332 realm_handoff(&snotice, 1, NULL, realm, 0);
1339 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1341 subscr_check_foreign_subs(ZNotice_t *notice,
1342 struct sockaddr_in *who,
1347 Destlist *subs, *next;
1357 for (subs = newsubs; subs; subs = subs->next)
1363 sender = make_string(notice->z_sender, 0);
1365 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1367 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1368 free_string(sender);
1372 /* grab the client information from the incoming message */
1373 cp = notice->z_message;
1382 for (subs = newsubs; subs; subs = next) {
1385 if (subs->dest.recip->string[0] != '\0') {
1386 rlm = realm_which_realm(who);
1387 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1388 subs->dest.recip->string,
1389 sender->string, rlm->name);
1392 acl = class_get_acl(subs->dest.classname);
1394 rlm = realm_which_realm(who);
1395 if (rlm && server == me_server) {
1396 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1397 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1398 sender->string, rlm->name,
1399 subs->dest.classname->string);
1400 free_subscriptions(newsubs);
1401 free_string(sender);
1403 return ZSRV_CLASSRESTRICTED;
1406 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1407 syslog(LOG_WARNING, "subscr unauth %s class %s",
1408 sender->string, subs->dest.classname->string);
1409 continue; /* the for loop */
1411 if (wildcard_instance == subs->dest.inst) {
1412 if (!access_check(sender->string, acl, INSTWILD)) {
1414 "subscr unauth %s class %s wild inst",
1415 sender->string, subs->dest.classname->string);
1421 /* okay to subscribe. save for return trip */
1422 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1423 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1424 text[found*NUM_FIELDS + 4] = "";
1427 retval = triplet_register(realm->client, &subs->dest, realm);
1429 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1430 subs->dest.inst->string, subs->dest.recip->string));
1433 if (retval != ZERR_NONE) {
1434 if (retval == ZSRV_CLASSXISTS) {
1437 free_subscriptions(newsubs); /* subs->next XXX */
1438 free_string(sender);
1443 Destlist_insert(&realm->subs, subs);
1445 /* don't send confirmation if we're not the initial server contacted */
1446 if (!(server_which_server(who) || found == 0)) {
1448 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1449 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1450 snotice.z_port = srv_addr.sin_port;
1451 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1452 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1453 error_message(retval));
1454 free_string(sender);
1458 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1459 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1460 error_message(retval));
1461 free_string(sender);
1466 realm_handoff(&snotice, 1, who, realm, 0);
1469 free_string(sender);
1474 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1475 Code_t subscr_foreign_user(ZNotice_t *notice,
1476 struct sockaddr_in *who,
1480 Destlist *newsubs, *temp;
1484 struct sockaddr_in newwho;
1485 char *cp, *tp0, *tp1;
1486 char rlm_recipient[REALM_SZ + 1];
1488 tp0 = cp = notice->z_message;
1490 newwho.sin_addr.s_addr = inet_addr(cp);
1491 if (newwho.sin_addr.s_addr == -1) {
1492 syslog(LOG_ERR, "malformed addr from %s", notice->z_sender);
1501 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1504 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1505 error_message(status));
1511 snotice.z_message = cp;
1512 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1514 newsubs = extract_subscriptions(&snotice);
1516 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1520 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1521 /* this was approved by the other realm, add subscriptions */
1523 if (!strcmp(tp0, "0.0.0.0")) {
1524 /* skip bogus ADD reply from subscr_realm_subs */
1525 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1529 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1530 client = client_find(&newwho.sin_addr, snotice.z_port);
1531 if (client == (Client *)0) {
1532 syslog(LOG_WARNING, "no client at %s/%d",
1533 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1534 free_subscriptions(newsubs);
1538 /* translate the recipient to represent the foreign realm */
1539 sprintf(rlm_recipient, "@%s", realm->name);
1540 for (temp = newsubs; temp; temp = temp->next) {
1541 temp->dest.recip = make_string(rlm_recipient, 0);
1544 status = subscr_add_raw(client, (ZRealm *)0, newsubs);
1545 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1546 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1547 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1549 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",