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