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: /var/raeburn/z/repos/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: subscr.c,v 1.59 2001/07/03 03:28:31 zacheiss Exp $";
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 */
73 extern char *re_comp(), *re_conv();
74 static Code_t add_subscriptions __P((Client *who, Destlist *subs_queue,
75 ZNotice_t *notice, Server *server));
76 static Destlist *extract_subscriptions __P((ZNotice_t *notice));
77 static void free_subscriptions __P((Destlist *subs));
78 static void free_subscription __P((Destlist *sub));
79 static char **subscr_marshal_subs __P((Destlist *subs,
81 static Destlist *subscr_copy_def_subs __P((char *person));
82 static Code_t subscr_realm_sendit __P((Client *who, Destlist *subs,
83 ZNotice_t *notice, Realm *realm));
84 static void subscr_unsub_realms __P((Destlist *newsubs));
85 static void subscr_unsub_sendit __P((Client *who, Destlist *subs,
87 static int cl_match __P((Destlist*, Client *));
89 static int defaults_read = 0; /* set to 1 if the default subs
91 static ZNotice_t default_notice; /* contains default subscriptions */
93 String *wildcard_instance;
96 /* WARNING: make sure this is the same as the number of strings you */
97 /* plan to hand back to the user in response to a subscription check, */
98 /* else you will lose. See subscr_sendlist() */
102 * subscribe the client to types described in notice.
106 subscr_subscribe(who, notice, server)
113 subs = extract_subscriptions(notice);
114 return add_subscriptions(who, subs, notice, server);
118 add_subscriptions(who, subs, notice, server)
131 return ZERR_NONE; /* no subscr -> no error */
133 sender = make_string(notice->z_sender, 0);
135 /* Loop over the new subscriptions. */
136 for (; subs; subs = next) {
139 zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
140 subs->dest.inst->string, subs->dest.recip->string));
142 /* check the recipient for a realm which isn't ours */
144 if (subs->dest.recip->string[0] == '@' &&
145 strcmp((subs->dest.recip->string + 1), my_galaxy) != 0)
146 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
148 if (subs->dest.recip != empty && subs->dest.recip != sender
149 && subs->dest.recip->string[0] != '@') {
150 syslog(LOG_WARNING, "subscr unauth %s recipient %s",
151 sender->string, subs->dest.recip->string);
152 free_subscription(subs); /* free this one - denied */
153 continue; /* the for loop */
155 acl = class_get_acl(subs->dest.classname);
157 if (!access_check(sender->string, acl, SUBSCRIBE)) {
158 syslog(LOG_WARNING, "subscr unauth %s class %s",
159 sender->string, subs->dest.classname->string);
160 free_subscription(subs); /* free this one - denied */
161 continue; /* the for loop */
163 if (wildcard_instance == subs->dest.inst) {
164 if (!access_check(sender->string, acl, INSTWILD)) {
166 "subscr unauth %s class %s wild inst",
167 sender->string, subs->dest.classname->string);
168 free_subscription(subs); /* free this one - denied */
169 continue; /* the for loop */
174 if (realm && !bdumping) {
175 if (server && server == me_server) {
176 retval = subscr_realm_sendit(who, subs, notice, realm);
177 if (retval != ZERR_NONE) {
178 free_subscriptions(subs);
182 /* free this one, will get from ADD */
183 free_subscription(subs);
186 /* Indicates we leaked traffic back to our realm */
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 LIST_INSERT(&who->subs, subs);
210 * add default subscriptions to the client's subscription chain.
219 subs = subscr_copy_def_subs(who->principal->string);
220 return add_subscriptions(who, subs, &default_notice, NULL);
227 zdbug((LOG_DEBUG, "subscr_reset()"));
229 free(default_notice.z_message);
230 default_notice.z_message = NULL;
235 subscr_copy_def_subs(person)
240 char *def_sub_area, *cp;
241 Destlist *subs, *sub;
243 if (!defaults_read) {
245 zdbug((LOG_DEBUG, "reading default subscription file"));
247 fd = open(subs_file, O_RDONLY, 0666);
249 syslog(LOG_ERR, "can't open %s:%m", subs_file);
252 retval = fstat(fd, &statbuf);
254 syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
258 def_sub_area = (char *) malloc(statbuf.st_size + 1);
260 syslog(LOG_ERR, "no mem copy_def_subs");
264 retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
265 if (retval != statbuf.st_size) {
266 syslog(LOG_ERR, "short read in copy_def_subs");
272 def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
275 def_subs_area now points to a buffer full of subscription info.
276 Each line of the stuff is of the form:
279 Commas and newlines may not appear as part of the class,
280 instance, or recipient. XXX!
283 /* split up the subscription info */
284 for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
285 if (*cp == '\n' || *cp == ',')
288 default_notice.z_message = def_sub_area;
289 default_notice.z_message_len = statbuf.st_size + 1;
290 default_notice.z_auth = 1;
294 /* needed later for access_check() */
295 default_notice.z_sender = person;
296 subs = extract_subscriptions(&default_notice);
297 /* replace any non-* recipients with "person" */
299 for (sub = subs; sub; sub = sub->next) {
300 /* if not a wildcard, replace it with person */
301 if (strcmp(sub->dest.recip->string, "*")) {
302 free_string(sub->dest.recip);
303 sub->dest.recip = make_string(person, 0);
304 } else { /* replace with null recipient */
305 free_string(sub->dest.recip);
306 sub->dest.recip = dup_string(empty);
313 * Cancel a specific set of subscriptions.
317 subscr_cancel(sin, notice)
318 struct sockaddr_in *sin;
323 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 LIST_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(sin, notice, realm)
382 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 LIST_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)
438 Destlist *subs, *next;
443 zdbug((LOG_DEBUG,"subscr_cancel_client %s",
444 inet_ntoa(client->addr.sin_addr)));
449 for (subs = client->subs; subs; subs = next) {
452 zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
454 retval = triplet_deregister(client, &subs->dest, NULL);
455 if (retval == ZSRV_EMPTYCLASS &&
456 subs->dest.recip->string[0] == '@') {
457 realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
459 subscr_unsub_sendit(client, subs, realm);
462 free_subscription(subs);
469 * Send the requester a list of his current subscriptions
473 subscr_sendlist(notice, auth, who)
476 struct sockaddr_in *who;
480 Destlist *subs = NULL;
482 char **answer = NULL;
484 struct sockaddr_in send_to_who;
488 send_to_who.sin_port = notice->z_port; /* Return port */
490 retval = ZSetDestAddr(&send_to_who);
491 if (retval != ZERR_NONE) {
492 syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
493 error_message(retval));
497 if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
501 /* If the client has requested his current subscriptions,
502 the message field of the notice contains the port number
503 of the client for which the sender desires the subscription
504 list. The port field is the port of the sender. */
506 retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
507 if (retval != ZERR_NONE) {
508 syslog(LOG_WARNING, "subscr_marshal read port num: %s",
509 error_message(retval));
513 client = client_find(&who->sin_addr, htons(temp));
518 /* check authenticity here. The user must be authentic to get
519 a list of subscriptions. */
521 if (strcmp(client->principal->string, notice->z_sender) != 0) {
523 "subscr_marshal: %s requests subs for %s at %s/%d",
524 notice->z_sender, client->principal->string,
525 inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
531 } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
533 zdbug((LOG_DEBUG, "gimmedefs"));
535 /* subscr_copy_def_subs allocates new pointer rings, so
536 it must be freed when finished.
537 the string areas pointed to are static, however.*/
538 subs = subscr_copy_def_subs(notice->z_sender);
541 syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
546 answer = subscr_marshal_subs(subs, &found);
549 notice->z_kind = ACKED;
551 /* use xmit_frag() to send each piece of the notice */
553 retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
554 if (retval != ZERR_NONE)
555 syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
557 free_subscriptions(subs);
563 subscr_marshal_subs(subs, found)
567 char **answer = NULL;
573 zdbug((LOG_DEBUG, "subscr_marshal"));
577 /* Note that the following code is an incredible crock! */
579 /* We cannot send multiple packets as acknowledgements to the client,
580 since the hostmanager will ignore the later packets. So we need
581 to send directly to the client. */
583 /* Make our own copy so we can send directly back to the client */
589 for (sub = subs; sub; sub = sub->next)
592 /* found is now the number of subscriptions */
594 /* coalesce the subscription information into a list of char *'s */
595 answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
596 if (answer == NULL) {
597 syslog(LOG_ERR, "subscr no mem(answer)");
601 for (sub = subs; sub; sub = sub->next) {
602 answer[i * NUM_FIELDS] = sub->dest.classname->string;
603 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
604 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
613 * Send the client's subscriptions to another server
616 /* version is currently unused; if necessary later versions may key off it
617 to determine what to send to the peer (protocol changes) */
621 subscr_send_subs(client)
629 #endif /* HAVE_KRB4 */
631 char *list[7 * NUM_FIELDS];
636 zdbug((LOG_DEBUG, "send_subs"));
638 sprintf(buf2, "%d",ntohs(client->addr.sin_port));
644 memcpy(cblock, client->session_key, sizeof(C_Block));
646 des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
649 retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
650 if (retval != ZERR_NONE) {
652 zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
657 zdbug((LOG_DEBUG, "cblock %s", buf));
660 #endif /* HAVE_KRB4 */
661 retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
662 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
663 client->principal->string, "", list, num);
664 if (retval != ZERR_NONE) {
665 syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
672 for (subs = client->subs; subs; subs = subs->next) {
673 /* for each subscription */
674 list[i * NUM_FIELDS] = subs->dest.classname->string;
675 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
676 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
679 /* we only put 7 in each packet, so we don't run out of room */
680 retval = bdump_send_list_tcp(ACKED, &client->addr,
681 ZEPHYR_CTL_CLASS, "",
682 CLIENT_SUBSCRIBE, "", "", list,
684 if (retval != ZERR_NONE) {
685 syslog(LOG_ERR, "subscr_send_subs subs: %s",
686 error_message(retval));
693 retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
694 "", CLIENT_SUBSCRIBE, "", "", list,
696 if (retval != ZERR_NONE) {
697 syslog(LOG_ERR, "subscr_send_subs subs: %s",
698 error_message(retval));
707 * free the memory allocated for the list of subscriptions.
711 * free the memory allocated for one subscription.
715 free_subscription(Destlist *sub)
717 free_string(sub->dest.classname);
718 free_string(sub->dest.inst);
719 free_string(sub->dest.recip);
724 free_subscriptions(subs)
729 for (; subs; subs = next) {
731 free_subscription (subs);
735 #define ADVANCE(xx) { cp += (strlen(cp) + 1); \
736 if (cp >= notice->z_message + notice->z_message_len) { \
737 syslog(LOG_WARNING, "malformed subscription %d", \
743 * Parse the message body, returning a linked list of subscriptions, or
744 * NULL if there are no subscriptions there.
748 extract_subscriptions(notice)
751 Destlist *subs = NULL, *sub;
752 char *recip, *class_name, *classinst;
753 char *cp = notice->z_message;
755 /* parse the data area for the subscriptions */
756 while (cp < notice->z_message + notice->z_message_len) {
758 if (*cp == '\0') /* we've exhausted the subscriptions */
765 zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
766 class_name, classinst, cp));
768 cp += (strlen(cp) + 1);
769 if (cp > notice->z_message + notice->z_message_len) {
770 syslog(LOG_WARNING, "malformed sub 3");
773 sub = (Destlist *) malloc(sizeof(Destlist));
775 syslog(LOG_WARNING, "ex_subs: no mem 2");
778 sub->dest.classname = make_string(class_name, 1);
779 sub->dest.inst = make_string(classinst, 1);
780 /* Nuke @REALM if REALM is us. */
781 if (recip[0] == '@' && !strcmp(recip + 1, my_galaxy))
782 sub->dest.recip = make_string("", 0);
784 sub->dest.recip = make_string(recip, 0);
785 LIST_INSERT(&subs, sub);
791 * print subscriptions in subs onto fp.
792 * assumed to be called with SIGFPE blocked
793 * (true if called from signal handler)
797 subscr_dump_subs(fp, subs)
803 if (!subs) /* no subscriptions to dump */
806 for (; subs; subs = subs->next) {
808 dump_quote(subs->dest.classname->string, fp);
810 dump_quote(subs->dest.inst->string, fp);
812 dump_quote(subs->dest.recip->string, fp);
817 #define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \
818 if (cp >= notice->z_message + notice->z_message_len) { \
819 syslog(LOG_WARNING, "malformed subscription %d", \
821 return (ZERR_NONE); \
824 /* As it exists, this function expects to take only the first sub from the
825 * Destlist. At some point, it and the calling code should be replaced */
827 subscr_realm_sendit(who, subs, notice, realm)
839 char addr[16]; /* xxx.xxx.xxx.xxx max */
843 zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
847 if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
848 syslog(LOG_ERR, "subscr_rlm_sendit malloc");
851 /* convert the address to a string of the form x.x.x.x/port */
852 strcpy(addr, inet_ntoa(who->addr.sin_addr));
853 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
854 &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE)
856 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
857 error_message(retval));
863 text[2] = subs->dest.classname->string;
864 text[3] = subs->dest.inst->string;
865 text[4] = subs->dest.recip->string;
867 zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
868 text[0], text[1], who->principal->string, text[2], text[3], text[4]));
871 memset (&snotice, 0, sizeof(snotice));
872 snotice.z_class_inst = ZEPHYR_CTL_REALM;
873 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
874 snotice.z_port = srv_addr.sin_port;
876 snotice.z_class = ZEPHYR_CTL_CLASS;
878 snotice.z_recipient = "";
879 snotice.z_kind = ACKED;
880 snotice.z_num_other_fields = 0;
881 snotice.z_default_format = "";
882 snotice.z_sender = who->principal->string;
883 snotice.z_recipient = notice->z_recipient;
884 snotice.z_default_format = notice->z_default_format;
886 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
887 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
889 syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
890 error_message(retval));
896 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
897 syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
898 error_message(retval));
904 zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
906 realm_handoff(&snotice, 1, &(who->addr), realm, 0);
912 /* Called from subscr_realm and subscr_foreign_user */
914 subscr_add_raw(client, realm, newsubs)
919 Destlist *subs, *subs2, *subs3, **head;
923 zdbug((LOG_DEBUG, "subscr_add_raw"));
925 head = (realm) ? &realm->subs : &client->subs;
927 /* Loop over the new subscriptions. */
928 for (subs = newsubs; subs; subs = subs2) {
931 zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
933 zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
935 retval = triplet_register(client, &subs->dest, realm);
936 if (retval != ZERR_NONE) {
937 free_subscription(subs);
938 if (retval == ZSRV_CLASSXISTS) {
941 free_subscriptions(subs2);
947 realm_get_realm_by_name(subs->dest.recip->string + 1);
949 Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
951 syslog(LOG_WARNING, "subscr_add_raw: no mem");
953 sub->dest.classname = make_string(subs->dest.classname->string, 0);
954 sub->dest.inst = make_string(subs->dest.inst->string, 0);
955 sub->dest.recip = make_string(subs->dest.recip->string, 0);
957 zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
958 sub->dest.classname->string, sub->dest.inst->string,
959 sub->dest.recip->string, remrealm->name));
961 LIST_INSERT(&remrealm->remsubs, sub);
966 LIST_INSERT(head, subs);
971 /* Called from bdump_recv_loop to decapsulate realm subs */
973 subscr_realm(realm, notice)
979 newsubs = extract_subscriptions(notice);
982 syslog(LOG_WARNING, "empty subs in subscr_realm");
986 return(subscr_add_raw(realm->client, realm, newsubs));
989 /* Like realm_sendit, this only takes one item from subs */
991 subscr_unsub_sendit(who, subs, realm)
1002 Destlist *subsp, *subsn;
1004 for (subsp = realm->remsubs; subsp; subsp = subsn) {
1005 subsn = subsp->next;
1006 if (ZDest_eq(&subs->dest, &subsp->dest)) {
1008 zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
1009 subsp->dest.classname->string, subsp->dest.inst->string,
1010 subsp->dest.recip->string, realm->name));
1013 free_subscription(subsp);
1018 if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
1019 syslog(LOG_ERR, "subscr_unsub_sendit malloc");
1023 list[0] = subs->dest.classname->string;
1024 list[1] = subs->dest.inst->string;
1027 (void) memset((char *)&unotice, 0, sizeof(unotice));
1028 unotice.z_class = ZEPHYR_CTL_CLASS;
1029 unotice.z_class_inst = ZEPHYR_CTL_REALM;
1030 unotice.z_opcode = REALM_UNSUBSCRIBE;
1031 unotice.z_recipient = "";
1032 unotice.z_kind = ACKED;
1034 unotice.z_sender = "";
1035 unotice.z_port = srv_addr.sin_port;
1036 unotice.z_num_other_fields = 0;
1037 unotice.z_default_format = "";
1039 if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1040 syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1041 error_message(retval));
1047 if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1048 syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1049 error_message(retval));
1053 realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
1057 /* Called from bump_send_loop by way of realm_send_realms */
1059 subscr_send_realm_subs(realm)
1063 Destlist *subs, *next;
1065 char *list[7 * NUM_FIELDS];
1070 zdbug((LOG_DEBUG, "send_realm_subs"));
1073 strcpy(buf, realm->name);
1076 retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1077 "", ADMIN_NEWREALM, "", "", list, num);
1078 if (retval != ZERR_NONE) {
1079 syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1086 for (subs=realm->subs; subs; subs = next) {
1089 zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1090 subs->dest.inst->string, subs->dest.recip->string));
1092 /* for each subscription */
1093 list[i * NUM_FIELDS] = subs->dest.classname->string;
1094 list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1095 list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1098 /* we only put 7 in each packet, so we don't run out of room */
1099 retval = bdump_send_list_tcp(ACKED, &srv_addr,
1100 ZEPHYR_CTL_CLASS, "",
1101 REALM_SUBSCRIBE, "", "", list,
1103 if (retval != ZERR_NONE) {
1104 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1105 error_message(retval));
1112 retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1113 "", REALM_SUBSCRIBE, "", "", list,
1115 if (retval != ZERR_NONE) {
1116 syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1117 error_message(retval));
1126 subscr_realm_subs(realm)
1130 Destlist *subs, *next;
1132 char *text[2 + NUM_FIELDS];
1133 unsigned short num = 0;
1142 zdbug((LOG_DEBUG, "realm_subs"));
1145 if (!realm->remsubs)
1148 for (subs=realm->remsubs; subs; subs = next) {
1151 zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
1152 subs->dest.inst->string, subs->dest.recip->string));
1156 if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *)
1157 &num, sizeof(u_short))) != ZERR_NONE)
1159 syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1160 error_message(retval));
1164 text[0] = "0.0.0.0";
1166 text[2] = subs->dest.classname->string;
1167 text[3] = subs->dest.inst->string;
1168 text[4] = subs->dest.recip->string;
1170 /* format snotice */
1171 (void) memset((char *)&snotice, 0, sizeof(snotice));
1172 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1173 snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1175 snotice.z_class = ZEPHYR_CTL_CLASS;
1177 snotice.z_recipient = "";
1178 snotice.z_kind = ACKED;
1179 snotice.z_num_other_fields = 0;
1180 snotice.z_default_format = "";
1181 /* Evil. In the event this is ACL'd, pick a user who is subscribed and
1182 resubmit them as the sender. */
1183 clientp = triplet_lookup(&subs->dest);
1185 snotice.z_sender = "";
1187 snotice.z_sender = (*clientp)->principal->string;
1188 snotice.z_default_format = "";
1190 if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1191 &pack, &packlen, ZNOAUTH)) != ZERR_NONE)
1193 syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
1194 error_message(retval));
1198 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1199 syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
1200 error_message(retval));
1204 realm_handoff(&snotice, 1, NULL, realm, 0);
1211 /* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
1213 subscr_check_foreign_subs(notice, who, server, realm, newsubs)
1215 struct sockaddr_in *who;
1220 Destlist *subs, *subs2;
1231 for (subs = newsubs; subs; subs = subs->next)
1237 sender = make_string(notice->z_sender, 0);
1239 if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *)))
1241 syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1242 free_string(sender);
1246 /* grab the client information from the incoming message */
1247 cp = notice->z_message;
1257 rlm = realm_which_realm(who);
1259 for (subs = newsubs; subs; subs = subs->next) {
1260 if (subs->dest.recip->string[0] != '\0') {
1261 syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
1262 subs->dest.recip->string,
1263 sender->string, rlm->name);
1266 acl = class_get_acl(subs->dest.classname);
1268 if (rlm && server == me_server) {
1269 if (!realm_sender_in_realm(rlm->name, sender->string)) {
1270 syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
1271 sender->string, rlm->name,
1272 subs->dest.classname->string);
1273 free_subscriptions(newsubs);
1274 free_string(sender);
1276 return ZSRV_CLASSRESTRICTED;
1279 if (!access_check(sender->string, acl, SUBSCRIBE)) {
1280 syslog(LOG_WARNING, "subscr unauth %s class %s",
1281 sender->string, subs->dest.classname->string);
1282 continue; /* the for loop */
1284 if (wildcard_instance == subs->dest.inst) {
1285 if (!access_check(sender->string, acl, INSTWILD)) {
1287 "subscr unauth %s class %s wild inst",
1288 sender->string, subs->dest.classname->string);
1294 /* okay to subscribe. save for return trip */
1295 text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1296 text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1297 text[found*NUM_FIELDS + 4] = "";
1300 retval = triplet_register(realm->client, &subs->dest, realm);
1302 zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1303 subs->dest.inst->string, subs->dest.recip->string));
1306 if (retval != ZERR_NONE) {
1307 if (retval == ZSRV_CLASSXISTS) {
1310 free_subscriptions(newsubs); /* subs->next XXX */
1311 free_string(sender);
1316 LIST_INSERT(&realm->subs, subs);
1318 /* don't send confirmation if we're not the initial server contacted */
1319 if (!(server_which_server(who) || found == 0)) {
1321 snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1322 snotice.z_class_inst = ZEPHYR_CTL_REALM;
1323 snotice.z_port = srv_addr.sin_port;
1324 if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1325 syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1326 error_message(retval));
1327 free_string(sender);
1331 if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1332 syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1333 error_message(retval));
1334 free_string(sender);
1339 realm_handoff(&snotice, 1, who, realm, 0);
1342 free_string(sender);
1347 /* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
1348 Code_t subscr_foreign_user(notice, who, server, realm)
1350 struct sockaddr_in *who;
1354 Destlist *newsubs, *temp;
1359 struct sockaddr_in newwho;
1360 char *cp, *tp0, *tp1;
1361 char rlm_recipient[REALM_SZ + 1];
1364 zdbug((LOG_DEBUG, "subscr_foreign_user"));
1367 tp0 = cp = notice->z_message;
1369 newwho.sin_addr.s_addr = inet_addr(cp);
1370 if (newwho.sin_addr.s_addr == -1) {
1371 syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1380 if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1383 syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1384 error_message(status));
1390 snotice.z_message = cp;
1391 snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1393 newsubs = extract_subscriptions(&snotice);
1395 syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1399 if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1400 /* this was approved by the other realm, add subscriptions */
1402 if (!strcmp(tp0, "0.0.0.0")) {
1403 /* skip bogus ADD reply from subscr_realm_subs */
1404 zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
1408 zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
1409 client = client_find(&newwho.sin_addr, snotice.z_port);
1410 if (client == (Client *)0) {
1411 syslog(LOG_WARNING, "no client at %s/%d",
1412 inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1413 free_subscriptions(newsubs);
1417 /* translate the recipient to represent the foreign realm */
1418 sprintf(rlm_recipient, "@%s", realm->name);
1419 for (temp = newsubs; temp; temp = temp->next) {
1421 syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1423 temp->dest.recip = make_string(rlm_recipient, 0);
1426 status = subscr_add_raw(client, (Realm *)0, newsubs);
1427 } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1428 zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
1429 status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
1431 syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",