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