]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - server/subscr.c
back out previous
[1ts-debian.git] / server / subscr.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains functions for managing subscription lists.
3  *
4  *      Created by:     John T. Kohl
5  *
6  *      $Id: subscr.c,v 1.56 1999/01/22 23:19:48 ghudson Exp $
7  *
8  *      Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
9  *      For copying and distribution information, see the file
10  *      "mit-copyright.h". 
11  */
12
13 #include <zephyr/mit-copyright.h>
14 #include "zserver.h"
15
16 #ifndef lint
17 #ifndef SABER
18 static const char rcsid_subscr_c[] = "$Id: subscr.c,v 1.56 1999/01/22 23:19:48 ghudson Exp $";
19 #endif
20 #endif
21
22 /*
23  * The subscription manager.
24  *
25  * External functions:
26  *
27  * Code_t subscr_subscribe(who, notice)
28  *      Client *who;
29  *      ZNotice_t *notice;
30  *
31  * Code_t subscr_cancel(sin, notice)
32  *      struct sockaddr_in *sin;
33  *      ZNotice_t *notice;
34  *
35  * Code_t subscr_cancel_client(client)
36  *      Client *client;
37  *
38  * Code_t subscr_cancel_host(addr)
39  *      struct in_addr *addr;
40  *
41  * Client *subscr_match_list(notice)
42  *      ZNotice_t *notice;
43  *
44  * void subscr_free_list(list)
45  *      Client *list;
46  *
47  * void subscr_sendlist(notice, auth, who)
48  *      ZNotice_t *notice;
49  *      int auth;
50  *      struct sockaddr_in *who;
51  *
52  * Code_t subscr_send_subs(client, vers)
53  *      Client *client;
54  *      char *vers;
55  *
56  * Code_t subscr_def_subs(who)
57  *      Client *who;
58  *
59  * void subscr_reset();
60  *
61  */
62
63 #ifdef HAVE_KRB4
64 #ifndef NOENCRYPTION
65 C_Block serv_key;
66 Sched   serv_ksched;
67 #endif
68 #endif
69
70 /* for compatibility when sending subscription information to old clients */
71
72 #ifdef OLD_COMPAT
73 #define OLD_ZEPHYR_VERSION      "ZEPH0.0"
74 #define OLD_CLIENT_INCOMPSUBS   "INCOMP"
75 static void old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
76                                           struct sockaddr_in *who));
77 extern int old_compat_count_subscr;     /* counter of old use */
78 #endif /* OLD_COMPAT */
79 #ifdef NEW_COMPAT
80 #define NEW_OLD_ZEPHYR_VERSION  "ZEPH0.1"
81 static void new_old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
82                                               struct sockaddr_in *who)); 
83 extern int new_compat_count_subscr;     /* counter of old use */
84 #endif /* NEW_COMPAT */
85
86 extern char *re_comp(), *re_conv();
87 static Code_t add_subscriptions __P((Client *who, Destlist *subs_queue,
88                                    ZNotice_t *notice));
89 static Destlist *extract_subscriptions __P((ZNotice_t *notice));
90 static void free_subscriptions __P((Destlist *subs));
91 static char **subscr_marshal_subs __P((ZNotice_t *notice, int auth,
92                                      struct sockaddr_in *who,
93                                      int *found));
94 static Destlist *subscr_copy_def_subs __P((char *person));
95 static Code_t subscr_subscribe_realms __P((struct sockaddr_in *who,
96                                            Destlist *newsubs,
97                                            ZNotice_t *notice));
98 static Code_t subscr_realm_sendit __P((Client *who, Destlist *subs,
99                                        ZNotice_t *notice, Realm *realm));
100 static void subscr_unsub_realms __P((Destlist *newsubs));
101 static void subscr_unsub_sendit __P((Destlist *subs, Realm *realm));
102 static int cl_match  __P((Destlist*, Client *));
103
104 static int defaults_read = 0;           /* set to 1 if the default subs
105                                            are in memory */
106 static ZNotice_t default_notice;        /* contains default subscriptions */
107
108 String *wildcard_instance;
109 String *empty;
110
111 /* WARNING: make sure this is the same as the number of strings you */
112 /* plan to hand back to the user in response to a subscription check, */
113 /* else you will lose.  See subscr_sendlist() */  
114 #define NUM_FIELDS      3
115
116 /*
117  * subscribe the client to types described in notice.
118  */
119
120 Code_t
121 subscr_subscribe(who, notice)
122     Client *who;
123     ZNotice_t *notice;
124 {
125     Destlist *subs;
126
127     subs = extract_subscriptions(notice);
128     return add_subscriptions(who, subs, notice);
129 }
130
131 static Code_t
132 add_subscriptions(who, subs, notice)
133     Client *who;
134     Destlist *subs;
135     ZNotice_t *notice;
136 {
137     Destlist *next;
138     Code_t retval;
139     Acl *acl;
140     String *sender;
141     Realm *realm = NULL;
142
143     if (!subs)
144         return ZERR_NONE;       /* no subscr -> no error */
145
146     sender = make_string(notice->z_sender, 0);
147
148     /* Loop over the new subscriptions. */
149     for (; subs; subs = next) {
150         next = subs->next;
151 #if 0
152         zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
153                 subs->dest.inst->string, subs->dest.recip->string));
154 #endif
155         if (!bdumping) {
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                 continue;
161             }
162             acl = class_get_acl(subs->dest.classname);
163             if (acl) {
164                 if (!access_check(sender->string, acl, SUBSCRIBE)) {
165                     syslog(LOG_WARNING, "subscr unauth %s class %s",
166                            sender->string, subs->dest.classname->string);
167                     continue; /* the for loop */
168                 }
169                 if (wildcard_instance == subs->dest.inst) {
170                     if (!access_check(sender->string, acl, INSTWILD)) {
171                         syslog(LOG_WARNING,
172                                "subscr unauth %s class %s wild inst",
173                                sender->string, subs->dest.classname->string);
174                         continue;
175                     }
176                 }
177             }
178         }
179         /* check the recipient for a realm which isn't ours */
180         realm = NULL;
181         if (subs->dest.recip->string[0] == '@' &&
182             strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
183             realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
184         if (realm) {
185             retval = subscr_realm_sendit(who, subs, notice, realm);
186             if (retval != ZERR_NONE) {
187                 free(subs);
188                 return(retval);
189             }
190         }
191         retval = triplet_register(who, &subs->dest, realm);
192         if (retval != ZERR_NONE) {
193             free(subs);
194             if (retval == ZSRV_CLASSXISTS) {
195                 continue;
196             } else {
197                 free_subscriptions(next);
198                 return retval;
199             }
200         }
201         LIST_INSERT(&who->subs, subs);
202     }
203
204     return ZERR_NONE;
205 }
206
207 /*
208  * add default subscriptions to the client's subscription chain.
209  */
210
211 Code_t
212 subscr_def_subs(who)
213     Client *who;
214 {
215     Destlist *subs;
216
217     subs = subscr_copy_def_subs(who->principal->string);
218     return add_subscriptions(who, subs, &default_notice);
219 }
220
221 void
222 subscr_reset()
223 {
224 #if 0
225     zdbug((LOG_DEBUG, "subscr_reset()"));
226 #endif
227     free(default_notice.z_message);
228     default_notice.z_message = NULL;
229     defaults_read = 0;
230 }
231
232 static Destlist *
233 subscr_copy_def_subs(person)
234     char *person;
235 {
236     int retval, fd;
237     struct stat statbuf;
238     char *def_sub_area, *cp;
239     Destlist *subs, *sub;
240
241     if (!defaults_read) {
242 #if 0
243         zdbug((LOG_DEBUG, "reading default subscription file"));
244 #endif
245         fd = open(subs_file, O_RDONLY, 0666);
246         if (fd < 0) {
247             syslog(LOG_ERR, "can't open %s:%m", subs_file);
248             return NULL;
249         }
250         retval = fstat(fd, &statbuf);
251         if (retval < 0) {
252             syslog(LOG_ERR, "fstat failure on %s:%m", subs_file);
253             close(fd);
254             return NULL;
255         }
256         def_sub_area = (char *) malloc(statbuf.st_size + 1);
257         if (!def_sub_area) {
258             syslog(LOG_ERR, "no mem copy_def_subs");
259             close(fd);
260             return NULL;
261         }
262         retval = read(fd, def_sub_area, (size_t) statbuf.st_size);
263         if (retval != statbuf.st_size) {
264             syslog(LOG_ERR, "short read in copy_def_subs");
265             close(fd);
266             return NULL;
267         }
268
269         close(fd);
270         def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */
271
272         /*
273            def_subs_area now points to a buffer full of subscription info.
274            Each line of the stuff is of the form:
275            class,inst,recipient
276
277            Commas and newlines may not appear as part of the class,
278            instance, or recipient. XXX!
279            */
280
281         /* split up the subscription info */
282         for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) {
283             if (*cp == '\n' || *cp == ',')
284                 *cp = '\0';
285         }
286         default_notice.z_message = def_sub_area;
287         default_notice.z_message_len = statbuf.st_size + 1;
288         default_notice.z_auth = 1;
289         defaults_read = 1;
290     }
291
292     /* needed later for access_check() */
293     default_notice.z_sender = person;
294     subs = extract_subscriptions(&default_notice);
295     /* replace any non-* recipients with "person" */
296
297     for (sub = subs; sub; sub = sub->next) {
298         /* if not a wildcard, replace it with person */
299         if (strcmp(sub->dest.recip->string, "*")) {
300             free_string(sub->dest.recip);
301             sub->dest.recip = make_string(person, 0);
302         } else {                /* replace with null recipient */
303             free_string(sub->dest.recip);
304             sub->dest.recip = dup_string(empty);
305         }
306     }
307     return subs;
308 }
309
310 /*
311  * Cancel a specific set of subscriptions.
312  */
313
314 Code_t
315 subscr_cancel(sin, notice)
316     struct sockaddr_in *sin;
317     ZNotice_t *notice;
318 {
319     Realm *realm;
320     Client *who;
321     Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
322     Code_t retval;
323     int found = 0;
324     int relation;
325
326 #if 0
327     zdbug((LOG_DEBUG,"subscr_cancel"));
328 #endif
329     who = client_find(&sin->sin_addr, notice->z_port);
330     if (!who)
331         return ZSRV_NOCLT;
332
333     if (!who->subs)
334         return ZSRV_NOSUB;
335
336     cancel_subs = extract_subscriptions(notice);
337     if (!cancel_subs)
338         return ZERR_NONE;       /* no subscr -> no error */
339
340     for (subs = cancel_subs; subs; subs = cancel_next) {
341         cancel_next = subs->next;
342         for (client_subs = who->subs; client_subs; client_subs = client_next) {
343             client_next = client_subs->next;
344             if (ZDest_eq(&client_subs->dest, &subs->dest)) {
345                 LIST_DELETE(client_subs);
346                 triplet_deregister(who, &client_subs->dest, NULL);
347                 if (retval == ZSRV_EMPTYCLASS &&
348                     client_subs->dest.recip->string[0] == '@') {
349                     realm =
350                         realm_get_realm_by_name(client_subs->dest.recip->string
351                                                 + 1);
352                     if (realm)
353                         subscr_unsub_sendit(client_subs, realm);
354                     realm = NULL;
355                 }
356                 free_string(client_subs->dest.classname);
357                 free_string(client_subs->dest.inst);
358                 free_string(client_subs->dest.recip);
359                 free(client_subs);
360                 found = 1;
361                 break;
362             }
363         }
364     }
365
366     free_subscriptions(cancel_subs);
367
368     if (found) {
369 #if 0
370         zdbug((LOG_DEBUG, "found & removed"));
371 #endif
372         return ZERR_NONE;
373     } else {
374 #if 0
375         zdbug((LOG_DEBUG, "not found"));
376 #endif
377         return ZSRV_NOSUB;
378     }
379 }
380
381 Code_t
382 subscr_realm_cancel(sin, notice, realm)
383     struct sockaddr_in *sin;
384     ZNotice_t *notice;
385     Realm *realm;
386 {
387     Client *who;
388     Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
389     Code_t retval;
390     int found = 0;
391
392     if (!realm)
393         return ZSRV_NORLM;
394
395     if (!realm->subs)
396         return ZSRV_NOSUB;
397
398     cancel_subs = extract_subscriptions(notice);
399     if (!cancel_subs)
400         return ZERR_NONE;       /* no subscr -> no error */
401
402     for (subs = cancel_subs; subs; subs = next) {
403         next = subs->next;
404         for (client_subs = realm->subs; client_subs; client_subs = next2) {
405             next2 = client_subs->next;
406             if (ZDest_eq(&client_subs->dest, &subs->dest)) {
407                 LIST_DELETE(client_subs);
408                 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
409                 free_string(client_subs->dest.classname);
410                 free_string(client_subs->dest.inst);
411                 free_string(client_subs->dest.recip);
412                 free(client_subs);
413                 found = 1;
414                 break;
415             }
416         }
417     }
418
419     free_subscriptions(cancel_subs);
420
421     if (found) {
422 #if 0
423         zdbug((LOG_DEBUG, "found & removed"));
424 #endif
425         return ZERR_NONE;
426     } else {
427 #if 0
428         zdbug((LOG_DEBUG, "not found"));
429 #endif
430         return ZSRV_NOSUB;
431     }
432 }
433
434 /*
435  * Cancel all the subscriptions for this client.
436  */
437
438 void
439 subscr_cancel_client(client)
440     Client *client;
441 {
442     Destlist *subs, *next;
443     Code_t retval;
444     Realm *realm;
445
446 #if 0
447     zdbug((LOG_DEBUG,"subscr_cancel_client %s",
448            inet_ntoa(client->addr.sin_addr)));
449 #endif
450     if (!client->subs)
451         return;
452
453     for (subs = client->subs; subs; subs = next) {
454         next = subs->next;
455 #if 0
456         zdbug((LOG_DEBUG,"sub_can %s", subs->dest.classname->string));
457 #endif
458         retval = triplet_deregister(client, &subs->dest, NULL);
459         if (retval == ZSRV_EMPTYCLASS &&
460             subs->dest.recip->string[0] == '@') {
461             realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
462             if (realm)
463                 subscr_unsub_sendit(subs, realm);
464             realm = NULL;
465         }
466         free_string(subs->dest.classname);
467         free_string(subs->dest.inst);
468         free_string(subs->dest.recip);
469         free(subs);
470     }
471
472     client->subs = NULL;
473 }
474
475 /*
476  * Send the requester a list of his current subscriptions
477  */
478
479 void
480 subscr_sendlist(notice, auth, who)
481     ZNotice_t *notice;
482     int auth;
483     struct sockaddr_in *who;
484 {
485     char **answer;
486     int found;
487     struct sockaddr_in send_to_who;
488     Code_t retval;
489
490 #ifdef OLD_COMPAT
491     if (strcmp(notice->z_version, OLD_ZEPHYR_VERSION) == 0) {
492         /* we are talking to an old client; use the old-style
493            acknowledgement-message */
494         old_compat_subscr_sendlist(notice, auth, who);
495         return;
496     }
497 #endif /* OLD_COMPAT */
498 #ifdef NEW_COMPAT
499     if (strcmp(notice->z_version, NEW_OLD_ZEPHYR_VERSION) == 0) {
500         /* we are talking to a new old client; use the new-old-style
501            acknowledgement-message */
502         new_old_compat_subscr_sendlist(notice, auth, who);
503         return;
504     }
505 #endif /* NEW_COMPAT */
506     answer = subscr_marshal_subs(notice, auth, who, &found);
507     send_to_who = *who;
508     send_to_who.sin_port = notice->z_port;  /* Return port */
509
510     retval = ZSetDestAddr(&send_to_who);
511     if (retval != ZERR_NONE) {
512         syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
513                error_message(retval));
514         if (answer)
515             free(answer);
516         return;
517     }
518
519     /* XXX for now, don't do authentication */
520     auth = 0;
521
522     notice->z_kind = ACKED;
523
524     /* use xmit_frag() to send each piece of the notice */
525
526     retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag);
527     if (retval != ZERR_NONE)
528         syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval));
529     if (answer)
530         free(answer);
531 }
532
533 static char **
534 subscr_marshal_subs(notice, auth, who, found)
535     ZNotice_t *notice;
536     int auth;
537     struct sockaddr_in *who;
538     int *found;
539 {
540     char **answer = NULL;
541     unsigned short temp;
542     Code_t retval;
543     Client *client;
544     Destlist *subs = NULL, *sub;
545     int i;
546     int defsubs = 0;
547
548 #if 0
549     zdbug((LOG_DEBUG, "subscr_marshal"));
550 #endif
551     *found = 0;
552
553     /* Note that the following code is an incredible crock! */
554         
555     /* We cannot send multiple packets as acknowledgements to the client,
556        since the hostmanager will ignore the later packets.  So we need
557        to send directly to the client. */
558
559     /* Make our own copy so we can send directly back to the client */
560     /* RSF 11/07/87 */
561
562     if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) {
563         /* If the client has requested his current subscriptions,
564            the message field of the notice contains the port number
565            of the client for which the sender desires the subscription
566            list.  The port field is the port of the sender. */
567
568         retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp);
569         if (retval != ZERR_NONE) {
570             syslog(LOG_WARNING, "subscr_marshal read port num: %s",
571                    error_message(retval));
572             return(NULL);
573         }
574
575         client = client_find(&who->sin_addr, htons(temp));
576
577         if (client)
578             subs = client->subs;
579     } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) {
580 #if 0
581         zdbug((LOG_DEBUG, "gimmedefs"));
582 #endif
583         /* subscr_copy_def_subs allocates new pointer rings, so
584            it must be freed when finished.
585            the string areas pointed to are static, however.*/
586         subs = subscr_copy_def_subs(notice->z_sender);
587         defsubs = 1;
588     } else {
589         syslog(LOG_ERR, "subscr_marshal bogus opcode %s",
590                notice->z_opcode);
591         return(NULL);
592     }
593
594     if (subs) {
595
596         /* check authenticity here.  The user must be authentic to get
597            a list of subscriptions. If he is not subscribed to
598            anything, this if-clause fails, and he gets a response
599            indicating no subscriptions.
600            if retrieving default subscriptions, don't care about
601            authentication. */
602
603         if (!auth && !defsubs)
604             return(NULL);
605         if (!defsubs) {
606             if (client && (strcmp(client->principal->string,
607                                   notice->z_sender) != 0)) {
608                 zdbug ((LOG_DEBUG,
609                         "subscr_marshal: %s requests subs for %s at %s/%d",
610                         notice->z_sender, client->principal->string,
611                         inet_ntoa(who->sin_addr), ntohs(who->sin_port)));
612                 return 0;
613             }
614         }
615
616         for (sub = subs; sub; sub = sub->next)
617             (*found)++;
618
619         /* found is now the number of subscriptions */
620
621         /* coalesce the subscription information into a list of char *'s */
622         answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *));
623         if (answer == NULL) {
624             syslog(LOG_ERR, "subscr no mem(answer)");
625             *found = 0;
626         } else {
627             i = 0;
628             for (sub = subs; sub; sub = sub->next) {
629                 answer[i * NUM_FIELDS] = sub->dest.classname->string;
630                 answer[i * NUM_FIELDS + 1] = sub->dest.inst->string;
631                 answer[i * NUM_FIELDS + 2] = sub->dest.recip->string;
632                 i++;
633             }
634         }
635     }
636     if (defsubs)
637         free_subscriptions(subs);
638     return answer;
639 }
640
641 #ifdef NEW_COMPAT
642 static void
643 new_old_compat_subscr_sendlist(notice, auth, who)
644     ZNotice_t *notice;
645     int auth;
646     struct sockaddr_in *who;
647 {
648     Code_t retval;
649     ZNotice_t reply;
650     ZPacket_t reppacket;
651     int packlen, found, count, initfound, zerofound;
652     char buf[64];
653     const char **answer;
654     struct sockaddr_in send_to_who;
655     int i;
656
657     new_compat_count_subscr++;
658
659     syslog(LOG_INFO, "new old subscr, %s", inet_ntoa(who->sin_addr));
660     reply = *notice;
661     reply.z_kind = SERVACK;
662     reply.z_authent_len = 0; /* save some space */
663     reply.z_auth = 0;
664
665     send_to_who = *who;
666     send_to_who.sin_port = notice->z_port;  /* Return port */
667
668     retval = ZSetDestAddr(&send_to_who);
669     if (retval != ZERR_NONE) {
670         syslog(LOG_WARNING, "new_old_subscr_sendlist set addr: %s",
671                error_message(retval));
672         return;
673     }
674
675     /* retrieve  the subscriptions */
676     answer = subscr_marshal_subs(notice, auth, who, &found);
677
678     /* note that when there are no subscriptions, found == 0, so
679        we needn't worry about answer being NULL since
680        ZFormatSmallRawNoticeList won't reference the pointer */
681
682     /* send 5 at a time until we are finished */
683     count = found?((found-1) / 5 + 1):1;        /* total # to be sent */
684     i = 0;                                      /* pkt # counter */
685 #if 0
686     zdbug((LOG_DEBUG,"Found %d subscriptions for %d packets", found, count));
687 #endif
688     initfound = found;
689     zerofound = (found == 0);
690     while (found > 0 || zerofound) {
691         packlen = sizeof(reppacket);
692         sprintf(buf, "%d/%d", ++i, count);
693         reply.z_opcode = buf;
694         retval = ZFormatSmallRawNoticeList(&reply,
695                                            answer + (initfound - found)
696                                             * NUM_FIELDS,
697                                            ((found > 5) ? 5 : found)
698                                             * NUM_FIELDS,
699                                            reppacket, &packlen);
700         if (retval != ZERR_NONE) {
701             syslog(LOG_ERR, "subscr_sendlist format: %s",
702                    error_message(retval));
703             if (answer)
704                 free(answer);
705             return;
706         }
707         retval = ZSendPacket(reppacket, packlen, 0);
708         if (retval != ZERR_NONE) {
709             syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
710                    error_message(retval));
711             if (answer)
712                 free(answer);
713             return;
714         }
715         found -= 5;
716         zerofound = 0;
717     }
718 #if 0
719     zdbug((LOG_DEBUG,"subscr_sendlist acked"));
720 #endif
721     if (answer)
722         free(answer);
723 }
724 #endif /* NEW_COMPAT */
725
726 #ifdef OLD_COMPAT
727 static void
728 old_compat_subscr_sendlist(notice, auth, who)
729     ZNotice_t *notice;
730     int auth;
731     struct sockaddr_in *who;
732 {
733     Client *client = client_find(&who->sin_addr, notice->z_port);
734     Destlist *subs;
735     Code_t retval;
736     ZNotice_t reply;
737     ZPacket_t reppacket;
738     int packlen, i, found = 0;
739     char **answer = NULL;
740
741     old_compat_count_subscr++;
742
743     syslog(LOG_INFO, "old old subscr, %s", inet_ntoa(who->sin_addr));
744     if (client && client->subs) {
745
746         /* check authenticity here.  The user must be authentic to get
747            a list of subscriptions. If he is not subscribed to
748            anything, the above test fails, and he gets a response
749            indicating no subscriptions */
750
751         if (!auth) {
752             clt_ack(notice, who, AUTH_FAILED);
753             return;
754         }
755
756         for (subs = client->subs; subs; subs = subs->next)
757             found++;
758         /* found is now the number of subscriptions */
759
760         /* coalesce the subscription information into a list of char *'s */
761         answer = (char **) malloc(found * NUM_FIELDS * sizeof(char *));
762         if (!answer) {
763             syslog(LOG_ERR, "old_subscr_sendlist no mem(answer)");
764             found = 0;
765         } else {
766             i = 0;
767             for (subs = client->subs; subs; subs = subs->next) {
768                 answer[i*NUM_FIELDS] = subs->dest.classname->string;
769                 answer[i*NUM_FIELDS + 1] = subs->dest.inst->string;
770                 answer[i*NUM_FIELDS + 2] = subs->dest.recip->string;
771                 i++;
772             }
773         }
774     }
775
776     /* note that when there are no subscriptions, found == 0, so
777        we needn't worry about answer being NULL */
778
779     reply = *notice;
780     reply.z_kind = SERVACK;
781     reply.z_authent_len = 0; /* save some space */
782     reply.z_auth = 0;
783
784     /* if it's too long, chop off one at a time till it fits */
785     while ((retval = ZFormatSmallRawNoticeList(&reply, answer,
786                                                found * NUM_FIELDS,
787                                                reppacket,
788                                                &packlen)) != ZERR_PKTLEN) {
789         found--;
790         reply.z_opcode = OLD_CLIENT_INCOMPSUBS;
791     }
792     if (retval != ZERR_NONE) {
793         syslog(LOG_ERR, "old_subscr_sendlist format: %s",
794                error_message(retval));
795         if (answer)
796             free(answer);
797         return;
798     }
799     retval = ZSetDestAddr(who);
800     if (retval != ZERR_NONE) {
801         syslog(LOG_WARNING, "subscr_sendlist set addr: %s",
802                error_message(retval));
803         if (answer)
804             free(answer);
805         return;
806     }
807     retval = ZSendPacket(reppacket, packlen, 0);
808     if (retval != ZERR_NONE) {
809         syslog(LOG_WARNING, "subscr_sendlist xmit: %s",
810                error_message(retval));
811         if (answer)
812             free(answer);
813         return;
814     }
815 #if 0
816     zdbug((LOG_DEBUG,"subscr_sendlist acked"));
817 #endif
818     if (answer)
819         free(answer);
820 }
821 #endif /* OLD_COMPAT */
822
823 /*
824  * Send the client's subscriptions to another server
825  */
826
827 /* version is currently unused; if necessary later versions may key off it
828    to determine what to send to the peer (protocol changes) */
829
830 /*ARGSUSED*/
831 Code_t
832 subscr_send_subs(client)
833     Client *client;
834 {
835     int i = 0;
836     Destlist *subs;
837 #ifdef HAVE_KRB4
838     char buf[512];
839     C_Block cblock;
840 #endif /* HAVE_KRB4 */
841     char buf2[512];
842     char *list[7 * NUM_FIELDS];
843     int num = 0;
844     Code_t retval;
845
846 #if 0
847     zdbug((LOG_DEBUG, "send_subs"));
848 #endif
849     sprintf(buf2, "%d",ntohs(client->addr.sin_port));
850
851     list[num++] = buf2;
852
853 #ifdef HAVE_KRB4
854 #ifdef NOENCRYPTION
855     memcpy(cblock, client->session_key, sizeof(C_Block));
856 #else
857     des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
858 #endif
859
860     retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
861     if (retval != ZERR_NONE) {
862 #if 0
863         zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
864 #endif
865     } else {
866         list[num++] = buf;
867 #if 0
868         zdbug((LOG_DEBUG, "cblock %s", buf));
869 #endif
870     }           
871 #endif /* HAVE_KRB4 */
872     retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
873                                  num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
874                                  client->principal->string, "", list, num);
875     if (retval != ZERR_NONE) {
876         syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval));
877         return retval;
878     }
879
880     if (!client->subs)
881         return ZERR_NONE;
882
883     for (subs = client->subs; subs; subs = subs->next) {
884         /* for each subscription */
885         list[i * NUM_FIELDS] = subs->dest.classname->string;
886         list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
887         list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
888         i++;
889         if (i >= 7) {
890             /* we only put 7 in each packet, so we don't run out of room */
891             retval = bdump_send_list_tcp(ACKED, &client->addr,
892                                          ZEPHYR_CTL_CLASS, "",
893                                          CLIENT_SUBSCRIBE, "", "", list,
894                                          i * NUM_FIELDS);
895             if (retval != ZERR_NONE) {
896                 syslog(LOG_ERR, "subscr_send_subs subs: %s",
897                        error_message(retval));
898                 return retval;
899             }
900             i = 0;
901         }
902     }
903     if (i) {
904         retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS,
905                                      "", CLIENT_SUBSCRIBE, "", "", list,
906                                      i * NUM_FIELDS);
907         if (retval != ZERR_NONE) {
908             syslog(LOG_ERR, "subscr_send_subs subs: %s",
909                    error_message(retval));
910             return retval;
911         }
912     }
913
914     return ZERR_NONE;
915 }
916
917 /*
918  * free the memory allocated for the list of subscriptions.
919  */
920
921 static void
922 free_subscriptions(subs)
923     Destlist *subs;
924 {
925     Destlist *next;
926
927     for (; subs; subs = next) {
928         next = subs->next;
929         free_string(subs->dest.classname);
930         free_string(subs->dest.inst);
931         free_string(subs->dest.recip);
932         free(subs);
933     }
934 }
935
936 #define ADVANCE(xx)     { cp += (strlen(cp) + 1); \
937                   if (cp >= notice->z_message + notice->z_message_len) { \
938                           syslog(LOG_WARNING, "malformed subscription %d", \
939                                  xx); \
940                           return subs; \
941                   }}
942
943 /*
944  * Parse the message body, returning a linked list of subscriptions, or
945  * NULL if there are no subscriptions there.
946  */
947
948 static Destlist *
949 extract_subscriptions(notice)
950     ZNotice_t *notice;
951 {
952     Destlist *subs = NULL, *sub;
953     char *recip, *class_name, *classinst;
954     char *cp = notice->z_message;
955
956     /* parse the data area for the subscriptions */
957     while (cp < notice->z_message + notice->z_message_len) {
958         class_name = cp;
959         if (*cp == '\0')            /* we've exhausted the subscriptions */
960             return(subs);
961         ADVANCE(1);
962         classinst = cp;
963         ADVANCE(2);
964         recip = cp;
965 #if 0
966         zdbug((LOG_DEBUG, "ext_sub: CLS %s INST %s RCPT %s",
967                class_name, classinst, cp));
968 #endif
969         cp += (strlen(cp) + 1);
970         if (cp > notice->z_message + notice->z_message_len) {
971             syslog(LOG_WARNING, "malformed sub 3");
972             return subs;
973         }
974         sub = (Destlist *) malloc(sizeof(Destlist));
975         if (!sub) {
976             syslog(LOG_WARNING, "ex_subs: no mem 2");
977             return subs;
978         }
979         sub->dest.classname = make_string(class_name, 1);
980         sub->dest.inst = make_string(classinst, 1);
981         /* Nuke @REALM if REALM is us. */
982         if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm()))
983             sub->dest.recip = make_string("", 0);
984         else
985             sub->dest.recip = make_string(recip, 0);
986         LIST_INSERT(&subs, sub);
987     }
988     return subs;
989 }
990
991 /*
992  * print subscriptions in subs onto fp.
993  * assumed to be called with SIGFPE blocked
994  * (true if called from signal handler)
995  */
996
997 void
998 subscr_dump_subs(fp, subs)
999     FILE *fp;
1000     Destlist *subs;
1001 {
1002     char *p;
1003
1004     if (!subs)                  /* no subscriptions to dump */
1005         return;
1006
1007     for (; subs; subs = subs->next) {
1008         fputs("\t'", fp);
1009         dump_quote(subs->dest.classname->string, fp);
1010         fputs("' '", fp);
1011         dump_quote(subs->dest.inst->string, fp);
1012         fputs("' '", fp);
1013         dump_quote(subs->dest.recip->string, fp);
1014         fputs("'\n", fp);
1015     }
1016 }
1017
1018 #define I_ADVANCE(xx)   { cp += (strlen(cp) + 1); \
1019                   if (cp >= notice->z_message + notice->z_message_len) { \
1020                           syslog(LOG_WARNING, "malformed subscription %d", \
1021                                  xx); \
1022                           return (ZERR_NONE); \
1023                   }}
1024
1025 /* As it exists, this function expects to take only the first sub from the 
1026  * Destlist. At some point, it and the calling code should be replaced */
1027 static Code_t
1028 subscr_realm_sendit(who, subs, notice, realm)
1029     Client *who;
1030     Destlist *subs;
1031     ZNotice_t *notice;
1032     Realm *realm;
1033 {
1034 #if 0
1035   Destlist *subs2;
1036 #endif
1037   ZNotice_t snotice;
1038   char *pack;
1039   int packlen;
1040   int found = 0, i;
1041   char **text;
1042   Code_t retval;
1043   char addr[16];          /* xxx.xxx.xxx.xxx max */
1044   char port[16];
1045   
1046 #if 0
1047   zdbug((LOG_DEBUG, "subscr_rlm_sendit"));
1048 #endif
1049
1050
1051 #ifdef notdef
1052   for (subs2 = subs; subs2; subs2 = subs2->next, found++);
1053   /* found is now the number of subscriptions */
1054   
1055   /* coalesce the subscription information into a list of char *'s */
1056   /* one extra for client information */
1057   if ((text = (char **) malloc((found * NUM_FIELDS + 2)
1058                                 * sizeof(char *))) == (char **) 0) 
1059     {
1060       syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1061       return(ENOMEM);
1062     }
1063 #endif /* notdef */
1064
1065   if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
1066       syslog(LOG_ERR, "subscr_rlm_sendit malloc");
1067       return(ENOMEM);
1068   }
1069   /* convert the address to a string of the form x.x.x.x/port */
1070   strcpy(addr, inet_ntoa(notice->z_sender_addr));
1071   if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) 
1072                            &notice->z_port, sizeof(u_short))) != ZERR_NONE) 
1073     {
1074       syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
1075              error_message(retval));
1076       return(ZERR_NONE);
1077     }
1078   text[0] = addr;
1079   text[1] = port;
1080
1081 #ifdef notdef
1082   for (i = 0, subs2 = subs; subs2, i < found ; i++, subs2 = subs2->next) {
1083     text[i*NUM_FIELDS + 2] = subs2->dest.classname->string;
1084     text[i*NUM_FIELDS + 3] = subs2->dest.inst->string;
1085     text[i*NUM_FIELDS + 4] = subs2->dest.recip->string;
1086   }
1087 #endif /* notdef */
1088
1089   text[2] = subs->dest.classname->string;
1090   text[3] = subs->dest.inst->string;
1091   text[4] = subs->dest.recip->string;
1092   
1093   /* format snotice */
1094   snotice.z_class_inst = ZEPHYR_CTL_REALM;
1095   snotice.z_opcode = REALM_REQ_SUBSCRIBE;
1096   snotice.z_port = srv_addr.sin_port;
1097
1098   snotice.z_class = ZEPHYR_CTL_CLASS;
1099
1100   snotice.z_recipient = "";
1101   snotice.z_kind = ACKED;
1102   snotice.z_num_other_fields = 0;
1103   snotice.z_default_format = "";
1104   snotice.z_sender = notice->z_sender;
1105   snotice.z_recipient = notice->z_recipient;
1106   snotice.z_default_format = notice->z_default_format;
1107   
1108 #ifdef notdef
1109   if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2,
1110                                   &pack, &packlen, ZNOAUTH)) != ZERR_NONE) 
1111 #else
1112   if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
1113                                   &pack, &packlen, ZNOAUTH)) != ZERR_NONE) 
1114 #endif
1115     {
1116       syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
1117              error_message(retval));
1118       free(text);
1119       return(ZERR_NONE);
1120     }
1121   free(text);
1122   
1123   if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1124     syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s",
1125            error_message(retval));
1126     free(pack);
1127     return(ZERR_NONE);
1128   }
1129   
1130 #if 0
1131   zdbug((LOG_DEBUG,"subscr_rlm_sendit len: %d", snotice.z_message_len));
1132 #endif
1133   realm_handoff(&snotice, 1, &(who->addr), realm, 0);
1134   free(pack);
1135   
1136   return(ZERR_NONE);
1137 }
1138
1139 static Code_t
1140 subscr_add_raw(client, realm, newsubs)
1141     Client *client;
1142     Realm *realm;
1143     Destlist *newsubs;
1144 {
1145   Destlist *subs, *subs2, *subs3, **head;
1146   Code_t retval;
1147
1148 #if 0
1149   zdbug((LOG_DEBUG, "subscr_add_raw"));
1150 #endif
1151   head = (realm) ? &realm->subs : &client->subs;
1152
1153   /* Loop over the new subscriptions. */
1154   for (subs = newsubs; subs; subs = subs2) {
1155     subs2 = subs->next;
1156 #ifdef DEBUG
1157     zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string));
1158     if (realm)
1159       zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name));
1160 #endif
1161     retval = triplet_register(client, &subs->dest, realm);
1162     if (retval != ZERR_NONE) {
1163       free(subs);
1164       if (retval == ZSRV_CLASSXISTS) {
1165         continue;
1166       } else {
1167         free_subscriptions(subs2);
1168         return retval;
1169       }
1170     }
1171     LIST_INSERT(head, subs);
1172   }
1173   return ZERR_NONE;
1174 }
1175
1176 Code_t
1177 subscr_realm(realm, notice)
1178     Realm *realm;
1179     ZNotice_t *notice;
1180 {
1181         Destlist  *newsubs;
1182
1183         newsubs = extract_subscriptions(notice);
1184
1185         if (!newsubs) {
1186                 syslog(LOG_WARNING, "empty subs in subscr_realm");
1187                 return(ZERR_NONE);
1188         }
1189
1190         return(subscr_add_raw(realm->client, realm, newsubs));
1191 }
1192
1193 /* Like realm_sendit, this only takes one item from subs */
1194 static void
1195 subscr_unsub_sendit(subs, realm)
1196     Destlist *subs;
1197     Realm *realm;
1198 {
1199   ZNotice_t unotice;
1200   Code_t retval;
1201 #ifdef notdef
1202   char *list[7 * NUM_FIELDS];
1203 #else /* notdef */
1204   char *list[NUM_FIELDS];
1205 #endif /* notdef */
1206   char *pack;
1207   int packlen;
1208   int found = 0;
1209   Destlist *subs2;
1210
1211   unotice.z_class = ZEPHYR_CTL_CLASS;
1212   unotice.z_class_inst = ZEPHYR_CTL_REALM;
1213   unotice.z_opcode = REALM_UNSUBSCRIBE;
1214   unotice.z_recipient = "";
1215   unotice.z_kind = ACKED;
1216
1217   unotice.z_sender = "";
1218   unotice.z_port = srv_addr.sin_port;
1219   unotice.z_num_other_fields = 0;
1220   unotice.z_default_format = "";
1221
1222 #ifdef notdef
1223   found = 0;
1224   for (subs2 = subs; subs2; subs2 = subs2->next) {
1225     list[found * NUM_FIELDS] = subs2->dest.classname->string;
1226     list[found * NUM_FIELDS + 1] = subs2->dest.inst->string;
1227     list[found * NUM_FIELDS + 2] = "";
1228           
1229     found++;
1230     
1231     if (found >= 7) {
1232       if ((retval = ZFormatNoticeList(&unotice, list, found * NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1233         syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1234                error_message(retval));
1235         return;
1236       }
1237       if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1238         syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1239                error_message(retval));
1240         free(pack);
1241         return;
1242       }
1243       free(pack);
1244       realm_handoff(&unotice, 1, (struct sockaddr_in *) 0, realm, 0);
1245       found = 0;
1246     }
1247   }
1248   
1249   if (found == 0)
1250     return;
1251
1252   if ((retval = ZFormatNoticeList(&unotice, list, found * NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1253     syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1254            error_message(retval));
1255     return;
1256   }
1257 #else /* notdef */
1258   list[0] = subs->dest.classname->string;
1259   list[1] = subs->dest.inst->string;
1260   list[2] = "";
1261
1262   if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1263     syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
1264            error_message(retval));
1265     return;
1266   }
1267 #endif /* notdef */
1268
1269   if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
1270     syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
1271            error_message(retval));
1272     free(pack);
1273     return;
1274   }
1275   free(pack);
1276   realm_handoff(&unotice, 1, (struct sockaddr_in *) 0, realm, 0);
1277 }
1278
1279 Code_t
1280 subscr_send_realm_subs(realm)
1281     Realm *realm;
1282 {
1283   int i = 0;
1284   Destlist *subs, *next;
1285   char buf[512];
1286   char *list[7 * NUM_FIELDS];
1287   int num = 0;
1288   Code_t retval;
1289
1290 #if 0
1291   zdbug((LOG_DEBUG, "send_realm_subs"));
1292 #endif
1293
1294   strcpy(buf, realm->name);
1295   list[num++] = buf;
1296
1297   retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS,
1298                                "", ADMIN_NEWREALM, "", "", list, num);
1299   if (retval != ZERR_NONE) {
1300     syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval));
1301     return retval;
1302   }
1303   
1304   if (!realm->subs)
1305     return ZERR_NONE;
1306
1307   for (subs=realm->subs; subs; subs = next) {
1308     next = subs->next;
1309 #ifdef DEBUG
1310     zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string,
1311             subs->dest.inst->string, subs->dest.recip->string));
1312 #endif
1313     /* for each subscription */
1314     list[i * NUM_FIELDS] = subs->dest.classname->string;
1315     list[i * NUM_FIELDS + 1] = subs->dest.inst->string;
1316     list[i * NUM_FIELDS + 2] = subs->dest.recip->string;
1317     i++;
1318     if (i >= 7) {
1319       /* we only put 7 in each packet, so we don't run out of room */
1320       retval = bdump_send_list_tcp(ACKED, &srv_addr,
1321                                    ZEPHYR_CTL_CLASS, "",
1322                                    REALM_SUBSCRIBE, "", "", list,
1323                                    i * NUM_FIELDS);
1324       if (retval != ZERR_NONE) {
1325         syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1326                error_message(retval));
1327         return retval;
1328       }
1329       i = 0;
1330     }
1331   }
1332   if (i) {
1333     retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS,
1334                                  "", REALM_SUBSCRIBE, "", "", list,
1335                                  i * NUM_FIELDS);
1336     if (retval != ZERR_NONE) {
1337       syslog(LOG_ERR, "subscr_send_realm_subs subs: %s",
1338              error_message(retval));
1339       return retval;
1340     }
1341   }
1342
1343   return ZERR_NONE;
1344 }
1345
1346 static Code_t
1347 subscr_check_foreign_subs(notice, who, realm, newsubs)
1348     ZNotice_t *notice;
1349     struct sockaddr_in *who;
1350     Realm *realm;
1351     Destlist *newsubs;
1352 {
1353   Destlist *subs, *subs2, *next;
1354   Acl *acl;
1355   char **text;
1356   int found = 0;
1357   ZNotice_t snotice;
1358   char *pack, *cp;
1359   int packlen;
1360   Code_t retval;
1361   String *sender;
1362
1363   for (subs = newsubs; subs; subs = subs->next)
1364     found++;
1365
1366   if (found == 0)
1367     return(ZERR_NONE);
1368   
1369   sender = make_string(notice->z_sender, 0);
1370
1371   if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) == (char **) 0) {
1372     syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
1373     return(ENOMEM);
1374   }
1375
1376   /* grab the client information from the incoming message */
1377   cp = notice->z_message;
1378   text[0] = cp;
1379
1380   I_ADVANCE(2);
1381   text[1] = cp;
1382
1383   I_ADVANCE(3);
1384
1385   found = 0;
1386   for (subs = newsubs; subs; subs = next) {
1387     next=subs->next;
1388     acl = class_get_acl(subs->dest.classname);
1389     if (acl) {
1390       if (!access_check(sender->string, acl, SUBSCRIBE)) {
1391         syslog(LOG_WARNING, "subscr unauth %s class %s",
1392                sender->string, subs->dest.classname->string);
1393         continue; /* the for loop */
1394       }
1395       if (wildcard_instance == subs->dest.inst) {
1396         if (!access_check(sender->string, acl, INSTWILD)) {
1397           syslog(LOG_WARNING,
1398                  "subscr unauth %s class %s wild inst",
1399                  sender->string, subs->dest.classname->string);
1400           continue;
1401         }
1402       }
1403     }
1404
1405     /* okay to subscribe.  save for return trip */
1406     text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
1407     text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
1408     text[found*NUM_FIELDS + 4] = "";
1409     found++;
1410
1411     retval = triplet_register(realm->client, &subs->dest, realm);
1412 #ifdef DEBUG
1413     zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
1414             subs->dest.inst->string, subs->dest.recip->string));
1415 #endif
1416
1417     if (retval != ZERR_NONE) {
1418       if (retval == ZSRV_CLASSXISTS) {
1419         continue;
1420       } else {
1421         free_subscriptions(subs->next);
1422         free(text);
1423         return retval;
1424       }
1425     }
1426     LIST_INSERT(&realm->subs, subs);
1427   }
1428   /* don't send confirmation if we're not the initial server contacted */
1429   if (!(server_which_server(who) || found == 0)) {
1430     snotice = *notice;
1431     snotice.z_opcode = REALM_ADD_SUBSCRIBE;
1432     snotice.z_class_inst = ZEPHYR_CTL_REALM;
1433     snotice.z_port = srv_addr.sin_port;
1434     if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
1435       syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
1436              error_message(retval));
1437       free(text);
1438       return(ZERR_NONE);      
1439     }
1440     if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
1441       syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
1442              error_message(retval));
1443       free(text);
1444       free(pack);
1445       return(ZERR_NONE);
1446     }
1447     realm_handoff(&snotice, 1, who, realm, 0);
1448     free(pack);
1449   }
1450   free(text);
1451   return ZERR_NONE;
1452 }
1453
1454 Code_t subscr_foreign_user(notice, who, realm)
1455     ZNotice_t *notice;
1456     struct sockaddr_in *who;
1457     Realm *realm;
1458 {
1459   Destlist *newsubs, *temp;
1460   Acl *acl;
1461   Code_t status;
1462   Client *client;
1463   ZNotice_t snotice;
1464   struct sockaddr_in newwho;
1465   char *cp;
1466   char rlm_recipient[REALM_SZ + 1];
1467   
1468 #if 0
1469   zdbug((LOG_DEBUG, "subscr_foreign_user"));
1470 #endif
1471   
1472   cp = notice->z_message;
1473   
1474   newwho.sin_addr.s_addr = inet_addr(cp);
1475   if (newwho.sin_addr.s_addr == -1) {
1476     syslog(LOG_ERR, "malformed addr from %s, notice->z_sender");
1477     return(ZERR_NONE);
1478   }
1479
1480   I_ADVANCE(0);
1481   
1482   snotice = *notice;
1483   
1484   if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(u_short)))
1485       != ZERR_NONE) 
1486     {
1487       syslog(LOG_ERR, "subscr_foreign_user read ascii: %s",
1488              error_message(status));
1489       return(ZERR_NONE);
1490     }
1491
1492   I_ADVANCE(1);
1493   
1494   snotice.z_message = cp;
1495   snotice.z_message_len = notice->z_message_len - (cp - notice->z_message);
1496
1497   newsubs = extract_subscriptions(&snotice);
1498   if (!newsubs) {
1499     syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender);
1500     return(ZERR_NONE);
1501   }
1502
1503   if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
1504     /* this was approved by the other realm, add subscriptions */
1505     
1506     client = client_find(&newwho.sin_addr, snotice.z_port);
1507     if (client == (Client *)0) {
1508       syslog(LOG_WARNING, "no client at %s/%d",
1509              inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port));
1510       free_subscriptions(newsubs);
1511       return(ZERR_NONE);
1512     }
1513     
1514     /* translate the recipient to represent the foreign realm */
1515     sprintf(rlm_recipient, "@%s", realm->name);
1516     for (temp = newsubs; temp; temp = temp->next) {
1517 #if 0
1518       syslog(LOG_DEBUG, "in foreign_user: class is %s", temp->dest.classname->string);
1519 #endif      
1520         temp->dest.recip = make_string(rlm_recipient, 0);
1521     }
1522     
1523     status = subscr_add_raw(client, (Realm *)0, newsubs);
1524   } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
1525     status = subscr_check_foreign_subs(notice, who, realm, newsubs);
1526   } else {
1527     syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",
1528            snotice.z_opcode);
1529     status = ZERR_NONE;
1530   }
1531   return(status);
1532 }
1533