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