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