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