]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blobdiff - zephyr/server/subscr.c
r4262@bucket (orig r252): kcr | 2008-01-20 22:11:00 -0500
[1ts-debian.git] / zephyr / server / subscr.c
index e937f67d229ba947ce102a0f971b6eb516a11a74..70aa1a8b54835eab8d81975b5ed4da3ddafe5437 100644 (file)
@@ -3,7 +3,8 @@
  *
  *     Created by:     John T. Kohl
  *
- *     $Id: subscr.c,v 1.56 1999/01/22 23:19:48 ghudson Exp $
+ *     $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/subscr.c,v $
+ *     $Author$
  *
  *     Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
  *     For copying and distribution information, see the file
@@ -15,7 +16,7 @@
 
 #ifndef lint
 #ifndef SABER
-static const char rcsid_subscr_c[] = "$Id: subscr.c,v 1.56 1999/01/22 23:19:48 ghudson Exp $";
+static const char rcsid_subscr_c[] = "$Id$";
 #endif
 #endif
 
@@ -72,34 +73,32 @@ Sched       serv_ksched;
 #ifdef OLD_COMPAT
 #define        OLD_ZEPHYR_VERSION      "ZEPH0.0"
 #define        OLD_CLIENT_INCOMPSUBS   "INCOMP"
-static void old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
-                                         struct sockaddr_in *who));
+static void old_compat_subscr_sendlist(ZNotice_t *notice, int auth,
+                                      struct sockaddr_in *who);
 extern int old_compat_count_subscr;    /* counter of old use */
 #endif /* OLD_COMPAT */
 #ifdef NEW_COMPAT
 #define NEW_OLD_ZEPHYR_VERSION "ZEPH0.1"
-static void new_old_compat_subscr_sendlist __P((ZNotice_t *notice, int auth,
-                                             struct sockaddr_in *who)); 
+static void new_old_compat_subscr_sendlist(ZNotice_t *notice, int auth,
+                                          struct sockaddr_in *who); 
 extern int new_compat_count_subscr;    /* counter of old use */
 #endif /* NEW_COMPAT */
 
-extern char *re_comp(), *re_conv();
-static Code_t add_subscriptions __P((Client *who, Destlist *subs_queue,
-                                  ZNotice_t *notice));
-static Destlist *extract_subscriptions __P((ZNotice_t *notice));
-static void free_subscriptions __P((Destlist *subs));
-static char **subscr_marshal_subs __P((ZNotice_t *notice, int auth,
-                                    struct sockaddr_in *who,
-                                    int *found));
-static Destlist *subscr_copy_def_subs __P((char *person));
-static Code_t subscr_subscribe_realms __P((struct sockaddr_in *who,
-                                          Destlist *newsubs,
-                                          ZNotice_t *notice));
-static Code_t subscr_realm_sendit __P((Client *who, Destlist *subs,
-                                      ZNotice_t *notice, Realm *realm));
-static void subscr_unsub_realms __P((Destlist *newsubs));
-static void subscr_unsub_sendit __P((Destlist *subs, Realm *realm));
-static int cl_match  __P((Destlist*, Client *));
+static Code_t add_subscriptions(Client *who, Destlist *subs_queue,
+                               ZNotice_t *notice, Server *server);
+static Destlist *extract_subscriptions(ZNotice_t *notice);
+static void free_subscriptions(Destlist *subs);
+static void free_subscription(Destlist *sub);
+static char **subscr_marshal_subs(ZNotice_t *notice, int auth,
+                                 struct sockaddr_in *who,
+                                 int *found);
+static Destlist *subscr_copy_def_subs(char *person);
+static Code_t subscr_realm_sendit(Client *who, Destlist *subs,
+                                 ZNotice_t *notice, ZRealm *realm);
+static void subscr_unsub_realms(Destlist *newsubs);
+static void subscr_unsub_sendit(Client *who, Destlist *subs, 
+                               ZRealm *realm);
+static int cl_match (Destlist*, Client *);
 
 static int defaults_read = 0;          /* set to 1 if the default subs
                                           are in memory */
@@ -118,27 +117,27 @@ String *empty;
  */
 
 Code_t
-subscr_subscribe(who, notice)
-    Client *who;
-    ZNotice_t *notice;
+subscr_subscribe(Client *who,
+                ZNotice_t *notice,
+                Server *server)
 {
     Destlist *subs;
 
     subs = extract_subscriptions(notice);
-    return add_subscriptions(who, subs, notice);
+    return add_subscriptions(who, subs, notice, server);
 }
 
 static Code_t
-add_subscriptions(who, subs, notice)
-    Client *who;
-    Destlist *subs;
-    ZNotice_t *notice;
+add_subscriptions(Client *who,
+                 Destlist *subs,
+                 ZNotice_t *notice,
+                 Server *server)
 {
     Destlist *next;
     Code_t retval;
     Acl *acl;
     String *sender;
-    Realm *realm = NULL;
+    ZRealm *realm = NULL;
 
     if (!subs)
        return ZERR_NONE;       /* no subscr -> no error */
@@ -152,18 +151,25 @@ add_subscriptions(who, subs, notice)
        zdbug ((LOG_DEBUG, "subscr: %s/%s/%s", subs->dest.classname->string,
                subs->dest.inst->string, subs->dest.recip->string));
 #endif
+       /* check the recipient for a realm which isn't ours */
+       realm = NULL;
+       if (subs->dest.recip->string[0] == '@' &&
+           strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
+           realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
        if (!bdumping) {
            if (subs->dest.recip != empty && subs->dest.recip != sender
                && subs->dest.recip->string[0] != '@') {
                syslog(LOG_WARNING, "subscr unauth %s recipient %s",
                       sender->string, subs->dest.recip->string);
-               continue;
+               free_subscription(subs); /* free this one - denied */
+               continue; /* the for loop */
            }
            acl = class_get_acl(subs->dest.classname);
-           if (acl) {
+           if (acl && !realm) {
                if (!access_check(sender->string, acl, SUBSCRIBE)) {
                    syslog(LOG_WARNING, "subscr unauth %s class %s",
                           sender->string, subs->dest.classname->string);
+                   free_subscription(subs); /* free this one - denied */
                    continue; /* the for loop */
                }
                if (wildcard_instance == subs->dest.inst) {
@@ -171,36 +177,40 @@ add_subscriptions(who, subs, notice)
                        syslog(LOG_WARNING,
                               "subscr unauth %s class %s wild inst",
                               sender->string, subs->dest.classname->string);
-                       continue;
+                       free_subscription(subs); /* free this one - denied */
+                       continue; /* the for loop */
                    }
                }
            }
        }
-       /* check the recipient for a realm which isn't ours */
-       realm = NULL;
-       if (subs->dest.recip->string[0] == '@' &&
-           strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0)
-           realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
-       if (realm) {
-           retval = subscr_realm_sendit(who, subs, notice, realm);
-           if (retval != ZERR_NONE) {
-               free(subs);
-               return(retval);
-           }
-       }
-       retval = triplet_register(who, &subs->dest, realm);
-       if (retval != ZERR_NONE) {
-           free(subs);
-           if (retval == ZSRV_CLASSXISTS) {
-               continue;
+       if (realm && !bdumping) {
+               retval = subscr_realm_sendit(who, subs, notice, realm);
+               if (retval != ZERR_NONE) {
+                   free_subscription(subs);
+                   continue; /* the for loop */
            } else {
-               free_subscriptions(next);
-               return retval;
+                   /* Indicates we leaked traffic back to our realm */
+                   free_subscription(subs); /* free this one, wil get from
+                                               ADD */
            }
+       } else {
+         retval = triplet_register(who, &subs->dest, NULL);
+         if (retval != ZERR_NONE) {
+             if (retval == ZSRV_CLASSXISTS) {
+                 free_subscription(subs); /* free this one */
+             } else {
+                 free_subscriptions(subs);
+                 free_string(sender);
+                 return retval;
+             }
+         } else {
+             /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */
+             LIST_INSERT(&who->subs, subs);
+         }
        }
-       LIST_INSERT(&who->subs, subs);
     }
 
+    free_string(sender);
     return ZERR_NONE;
 }
 
@@ -209,17 +219,16 @@ add_subscriptions(who, subs, notice)
  */
 
 Code_t
-subscr_def_subs(who)
-    Client *who;
+subscr_def_subs(Client *who)
 {
     Destlist *subs;
 
     subs = subscr_copy_def_subs(who->principal->string);
-    return add_subscriptions(who, subs, &default_notice);
+    return add_subscriptions(who, subs, &default_notice, NULL);
 }
 
 void
-subscr_reset()
+subscr_reset(void)
 {
 #if 0
     zdbug((LOG_DEBUG, "subscr_reset()"));
@@ -230,8 +239,7 @@ subscr_reset()
 }
 
 static Destlist *
-subscr_copy_def_subs(person)
-    char *person;
+subscr_copy_def_subs(char *person)
 {
     int retval, fd;
     struct stat statbuf;
@@ -312,11 +320,10 @@ subscr_copy_def_subs(person)
  */
 
 Code_t
-subscr_cancel(sin, notice)
-    struct sockaddr_in *sin;
-    ZNotice_t *notice;
+subscr_cancel(struct sockaddr_in *sin,
+             ZNotice_t *notice)
 {
-    Realm *realm;
+    ZRealm *realm;
     Client *who;
     Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next;
     Code_t retval;
@@ -343,20 +350,17 @@ subscr_cancel(sin, notice)
            client_next = client_subs->next;
            if (ZDest_eq(&client_subs->dest, &subs->dest)) {
                LIST_DELETE(client_subs);
-               triplet_deregister(who, &client_subs->dest, NULL);
+               retval = triplet_deregister(who, &client_subs->dest, NULL);
                if (retval == ZSRV_EMPTYCLASS &&
                    client_subs->dest.recip->string[0] == '@') {
                    realm =
                        realm_get_realm_by_name(client_subs->dest.recip->string
                                                + 1);
                    if (realm)
-                       subscr_unsub_sendit(client_subs, realm);
+                       subscr_unsub_sendit(who, client_subs, realm);
                    realm = NULL;
                }
-               free_string(client_subs->dest.classname);
-               free_string(client_subs->dest.inst);
-               free_string(client_subs->dest.recip);
-               free(client_subs);
+               free_subscription(client_subs);
                found = 1;
                break;
            }
@@ -379,10 +383,9 @@ subscr_cancel(sin, notice)
 }
 
 Code_t
-subscr_realm_cancel(sin, notice, realm)
-    struct sockaddr_in *sin;
-    ZNotice_t *notice;
-    Realm *realm;
+subscr_realm_cancel(struct sockaddr_in *sin,
+                   ZNotice_t *notice,
+                   ZRealm *realm)
 {
     Client *who;
     Destlist *cancel_subs, *subs, *client_subs, *next, *next2;
@@ -406,10 +409,7 @@ subscr_realm_cancel(sin, notice, realm)
             if (ZDest_eq(&client_subs->dest, &subs->dest)) {
                 LIST_DELETE(client_subs);
                 retval = triplet_deregister(realm->client, &client_subs->dest, realm);
-                free_string(client_subs->dest.classname);
-                free_string(client_subs->dest.inst);
-                free_string(client_subs->dest.recip);
-                free(client_subs);
+               free_subscription(client_subs);
                 found = 1;
                 break;
             }
@@ -436,12 +436,11 @@ subscr_realm_cancel(sin, notice, realm)
  */
 
 void
-subscr_cancel_client(client)
-    Client *client;
+subscr_cancel_client(Client *client)
 {
     Destlist *subs, *next;
     Code_t retval;
-    Realm *realm;
+    ZRealm *realm;
 
 #if 0
     zdbug((LOG_DEBUG,"subscr_cancel_client %s",
@@ -460,13 +459,10 @@ subscr_cancel_client(client)
            subs->dest.recip->string[0] == '@') {
            realm = realm_get_realm_by_name(subs->dest.recip->string + 1);
            if (realm)
-               subscr_unsub_sendit(subs, realm);
+               subscr_unsub_sendit(client, subs, realm);
            realm = NULL;
        }
-       free_string(subs->dest.classname);
-       free_string(subs->dest.inst);
-       free_string(subs->dest.recip);
-       free(subs);
+       free_subscription(subs);
     }
 
     client->subs = NULL;
@@ -477,10 +473,9 @@ subscr_cancel_client(client)
  */
 
 void
-subscr_sendlist(notice, auth, who)
-    ZNotice_t *notice;
-    int auth;
-    struct sockaddr_in *who;
+subscr_sendlist(ZNotice_t *notice,
+               int auth,
+               struct sockaddr_in *who)
 {
     char **answer;
     int found;
@@ -531,11 +526,10 @@ subscr_sendlist(notice, auth, who)
 }
 
 static char **
-subscr_marshal_subs(notice, auth, who, found)
-    ZNotice_t *notice;
-    int auth;
-    struct sockaddr_in *who;
-    int *found;
+subscr_marshal_subs(ZNotice_t *notice,
+                   int auth,
+                   struct sockaddr_in *who,
+                   int *found)
 {
     char **answer = NULL;
     unsigned short temp;
@@ -549,7 +543,7 @@ subscr_marshal_subs(notice, auth, who, found)
     zdbug((LOG_DEBUG, "subscr_marshal"));
 #endif
     *found = 0;
-
+    
     /* Note that the following code is an incredible crock! */
        
     /* We cannot send multiple packets as acknowledgements to the client,
@@ -829,15 +823,19 @@ old_compat_subscr_sendlist(notice, auth, who)
 
 /*ARGSUSED*/
 Code_t
-subscr_send_subs(client)
-    Client *client;
+subscr_send_subs(Client *client)
 {
     int i = 0;
     Destlist *subs;
+#ifdef HAVE_KRB5
+    char buf[512];
+    char *bufp;
+#else
 #ifdef HAVE_KRB4
     char buf[512];
     C_Block cblock;
 #endif /* HAVE_KRB4 */
+#endif
     char buf2[512];
     char *list[7 * NUM_FIELDS];
     int num = 0;
@@ -850,14 +848,45 @@ subscr_send_subs(client)
 
     list[num++] = buf2;
 
+#ifdef HAVE_KRB5
+#ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
+    if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
+       bufp = malloc(Z_keylen(client->session_keyblock));
+       if (bufp == NULL) {
+           syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
+           return errno;
+       }
+       des_ecb_encrypt(Z_keydata(client->session_keyblock), bufp, serv_ksched.s, DES_ENCRYPT);
+       retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
+    } else {
+#endif
+       bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
+                                                               + length */
+       if (bufp == NULL) {
+           syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
+           return errno;
+       }
+       *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
+       *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
+       memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
+
+       retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
+#ifdef HAVE_KRB4
+    }
+#endif /* HAVE_KRB4 */
+#else /* HAVE_KRB5 */
 #ifdef HAVE_KRB4
 #ifdef NOENCRYPTION
     memcpy(cblock, client->session_key, sizeof(C_Block));
-#else
+#else /* NOENCRYPTION */
     des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
-#endif
+#endif /* NOENCRYPTION */
 
     retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
+#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB5 */    
+
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
     if (retval != ZERR_NONE) {
 #if 0
        zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
@@ -868,7 +897,7 @@ subscr_send_subs(client)
        zdbug((LOG_DEBUG, "cblock %s", buf));
 #endif
     }          
-#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB4 || HAVE_KRB5*/
     retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
                                 num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
                                 client->principal->string, "", list, num);
@@ -918,18 +947,27 @@ subscr_send_subs(client)
  * free the memory allocated for the list of subscriptions.
  */
 
+/*
+ * free the memory allocated for one subscription.
+ */
+
 static void
-free_subscriptions(subs)
-    Destlist *subs;
+free_subscription(Destlist *sub)
+{
+    free_string(sub->dest.classname);
+    free_string(sub->dest.inst);
+    free_string(sub->dest.recip);
+    free(sub);
+}
+
+static void
+free_subscriptions(Destlist *subs)
 {
     Destlist *next;
 
     for (; subs; subs = next) {
        next = subs->next;
-       free_string(subs->dest.classname);
-       free_string(subs->dest.inst);
-       free_string(subs->dest.recip);
-       free(subs);
+       free_subscription (subs);
     }
 }
 
@@ -946,8 +984,7 @@ free_subscriptions(subs)
  */
 
 static Destlist *
-extract_subscriptions(notice)
-    ZNotice_t *notice;
+extract_subscriptions(ZNotice_t *notice)
 {
     Destlist *subs = NULL, *sub;
     char *recip, *class_name, *classinst;
@@ -995,9 +1032,8 @@ extract_subscriptions(notice)
  */
 
 void
-subscr_dump_subs(fp, subs)
-    FILE *fp;
-    Destlist *subs;
+subscr_dump_subs(FILE *fp,
+                Destlist *subs)
 {
     char *p;
 
@@ -1025,15 +1061,11 @@ subscr_dump_subs(fp, subs)
 /* As it exists, this function expects to take only the first sub from the 
  * Destlist. At some point, it and the calling code should be replaced */
 static Code_t
-subscr_realm_sendit(who, subs, notice, realm)
-    Client *who;
-    Destlist *subs;
-    ZNotice_t *notice;
-    Realm *realm;
+subscr_realm_sendit(Client *who,
+                   Destlist *subs,
+                   ZNotice_t *notice,
+                   ZRealm *realm)
 {
-#if 0
-  Destlist *subs2;
-#endif
   ZNotice_t snotice;
   char *pack;
   int packlen;
@@ -1048,28 +1080,14 @@ subscr_realm_sendit(who, subs, notice, realm)
 #endif
 
 
-#ifdef notdef
-  for (subs2 = subs; subs2; subs2 = subs2->next, found++);
-  /* found is now the number of subscriptions */
-  
-  /* coalesce the subscription information into a list of char *'s */
-  /* one extra for client information */
-  if ((text = (char **) malloc((found * NUM_FIELDS + 2)
-                                * sizeof(char *))) == (char **) 0) 
-    {
-      syslog(LOG_ERR, "subscr_rlm_sendit malloc");
-      return(ENOMEM);
-    }
-#endif /* notdef */
-
   if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) {
       syslog(LOG_ERR, "subscr_rlm_sendit malloc");
       return(ENOMEM);
   }
   /* convert the address to a string of the form x.x.x.x/port */
-  strcpy(addr, inet_ntoa(notice->z_sender_addr));
+  strcpy(addr, inet_ntoa(who->addr.sin_addr));
   if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) 
-                           &notice->z_port, sizeof(u_short))) != ZERR_NONE) 
+                           &who->addr.sin_port, sizeof(u_short))) != ZERR_NONE) 
     {
       syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
              error_message(retval));
@@ -1078,19 +1096,15 @@ subscr_realm_sendit(who, subs, notice, realm)
   text[0] = addr;
   text[1] = port;
 
-#ifdef notdef
-  for (i = 0, subs2 = subs; subs2, i < found ; i++, subs2 = subs2->next) {
-    text[i*NUM_FIELDS + 2] = subs2->dest.classname->string;
-    text[i*NUM_FIELDS + 3] = subs2->dest.inst->string;
-    text[i*NUM_FIELDS + 4] = subs2->dest.recip->string;
-  }
-#endif /* notdef */
-
   text[2] = subs->dest.classname->string;
   text[3] = subs->dest.inst->string;
   text[4] = subs->dest.recip->string;
   
+  zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n",
+         text[0], text[1], who->principal->string, text[2], text[3], text[4]));
+  
   /* format snotice */
+  memset (&snotice, 0, sizeof(snotice));
   snotice.z_class_inst = ZEPHYR_CTL_REALM;
   snotice.z_opcode = REALM_REQ_SUBSCRIBE;
   snotice.z_port = srv_addr.sin_port;
@@ -1101,17 +1115,12 @@ subscr_realm_sendit(who, subs, notice, realm)
   snotice.z_kind = ACKED;
   snotice.z_num_other_fields = 0;
   snotice.z_default_format = "";
-  snotice.z_sender = notice->z_sender;
+  snotice.z_sender = who->principal->string;
   snotice.z_recipient = notice->z_recipient;
   snotice.z_default_format = notice->z_default_format;
   
-#ifdef notdef
-  if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2,
-                                  &pack, &packlen, ZNOAUTH)) != ZERR_NONE) 
-#else
   if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
                                   &pack, &packlen, ZNOAUTH)) != ZERR_NONE) 
-#endif
     {
       syslog(LOG_WARNING, "subscr_rlm_sendit format: %s",
              error_message(retval));
@@ -1136,11 +1145,11 @@ subscr_realm_sendit(who, subs, notice, realm)
   return(ZERR_NONE);
 }
 
+/* Called from subscr_realm and subscr_foreign_user */
 static Code_t
-subscr_add_raw(client, realm, newsubs)
-    Client *client;
-    Realm *realm;
-    Destlist *newsubs;
+subscr_add_raw(Client *client,
+              ZRealm *realm,
+              Destlist *newsubs)
 {
   Destlist *subs, *subs2, *subs3, **head;
   Code_t retval;
@@ -1160,12 +1169,33 @@ subscr_add_raw(client, realm, newsubs)
 #endif
     retval = triplet_register(client, &subs->dest, realm);
     if (retval != ZERR_NONE) {
-      free(subs);
-      if (retval == ZSRV_CLASSXISTS) {
-        continue;
-      } else {
-        free_subscriptions(subs2);
-        return retval;
+       free_subscription(subs);
+       if (retval == ZSRV_CLASSXISTS) {
+           continue;
+       } else {
+           free_subscriptions(subs2);
+           return retval;
+       }
+    } else {
+      if (!realm) {
+       ZRealm *remrealm = 
+         realm_get_realm_by_name(subs->dest.recip->string + 1);
+       if (remrealm) {
+         Destlist *sub = (Destlist *) malloc(sizeof(Destlist));
+         if (!sub) {
+            syslog(LOG_WARNING, "subscr_add_raw: no mem");
+         } else {
+           sub->dest.classname = make_string(subs->dest.classname->string, 0);
+           sub->dest.inst = make_string(subs->dest.inst->string, 0);
+           sub->dest.recip = make_string(subs->dest.recip->string, 0);
+#if 1
+           zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s",
+                   sub->dest.classname->string, sub->dest.inst->string, 
+                   sub->dest.recip->string, remrealm->name));
+#endif
+           LIST_INSERT(&remrealm->remsubs, sub);
+         }
+       }
       }
     }
     LIST_INSERT(head, subs);
@@ -1173,10 +1203,10 @@ subscr_add_raw(client, realm, newsubs)
   return ZERR_NONE;
 }
 
+/* Called from bdump_recv_loop to decapsulate realm subs */
 Code_t
-subscr_realm(realm, notice)
-    Realm *realm;
-    ZNotice_t *notice;
+subscr_realm(ZRealm *realm,
+            ZNotice_t *notice)
 {
         Destlist  *newsubs;
 
@@ -1192,21 +1222,40 @@ subscr_realm(realm, notice)
 
 /* Like realm_sendit, this only takes one item from subs */
 static void
-subscr_unsub_sendit(subs, realm)
-    Destlist *subs;
-    Realm *realm;
+subscr_unsub_sendit(Client *who,
+                   Destlist *subs,
+                   ZRealm *realm)
 {
   ZNotice_t unotice;
   Code_t retval;
-#ifdef notdef
-  char *list[7 * NUM_FIELDS];
-#else /* notdef */
-  char *list[NUM_FIELDS];
-#endif /* notdef */
+  char **list;
   char *pack;
   int packlen;
   int found = 0;
-  Destlist *subs2;
+  Destlist *subsp, *subsn;
+
+  for (subsp = realm->remsubs; subsp; subsp = subsn) {
+    subsn = subsp->next;
+    if (ZDest_eq(&subs->dest, &subsp->dest)) {
+#if 1
+      zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s",
+             subsp->dest.classname->string, subsp->dest.inst->string, 
+             subsp->dest.recip->string, realm->name));
+#endif
+      LIST_DELETE(subsp);
+      free_subscription(subsp);
+      break;
+    }
+  }
+
+  if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) {
+      syslog(LOG_ERR, "subscr_unsub_sendit malloc");
+      return;
+  }
+
+  list[0] = subs->dest.classname->string;
+  list[1] = subs->dest.inst->string;
+  list[2] = "";
 
   unotice.z_class = ZEPHYR_CTL_CLASS;
   unotice.z_class_inst = ZEPHYR_CTL_REALM;
@@ -1219,52 +1268,13 @@ subscr_unsub_sendit(subs, realm)
   unotice.z_num_other_fields = 0;
   unotice.z_default_format = "";
 
-#ifdef notdef
-  found = 0;
-  for (subs2 = subs; subs2; subs2 = subs2->next) {
-    list[found * NUM_FIELDS] = subs2->dest.classname->string;
-    list[found * NUM_FIELDS + 1] = subs2->dest.inst->string;
-    list[found * NUM_FIELDS + 2] = "";
-          
-    found++;
-    
-    if (found >= 7) {
-      if ((retval = ZFormatNoticeList(&unotice, list, found * NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
-        syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
-               error_message(retval));
-        return;
-      }
-      if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
-        syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
-               error_message(retval));
-        free(pack);
-        return;
-      }
-      free(pack);
-      realm_handoff(&unotice, 1, (struct sockaddr_in *) 0, realm, 0);
-      found = 0;
-    }
-  }
-  
-  if (found == 0)
-    return;
-
-  if ((retval = ZFormatNoticeList(&unotice, list, found * NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
-    syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
-           error_message(retval));
-    return;
-  }
-#else /* notdef */
-  list[0] = subs->dest.classname->string;
-  list[1] = subs->dest.inst->string;
-  list[2] = "";
-
   if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
     syslog(LOG_WARNING, "subscr_unsub_sendit format: %s",
            error_message(retval));
+    free(list);
     return;
   }
-#endif /* notdef */
+  free(list);
 
   if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) {
     syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s",
@@ -1272,13 +1282,13 @@ subscr_unsub_sendit(subs, realm)
     free(pack);
     return;
   }
+  realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0);
   free(pack);
-  realm_handoff(&unotice, 1, (struct sockaddr_in *) 0, realm, 0);
 }
 
+/* Called from bump_send_loop by way of realm_send_realms */
 Code_t
-subscr_send_realm_subs(realm)
-    Realm *realm;
+subscr_send_realm_subs(ZRealm *realm)
 {
   int i = 0;
   Destlist *subs, *next;
@@ -1343,118 +1353,230 @@ subscr_send_realm_subs(realm)
   return ZERR_NONE;
 }
 
-static Code_t
-subscr_check_foreign_subs(notice, who, realm, newsubs)
-    ZNotice_t *notice;
-    struct sockaddr_in *who;
-    Realm *realm;
-    Destlist *newsubs;
+Code_t
+subscr_realm_subs(ZRealm *realm)
 {
-  Destlist *subs, *subs2, *next;
-  Acl *acl;
-  char **text;
-  int found = 0;
+  int i = 0;
+  Destlist *subs, *next;
+  char buf[512];
+  char *text[2 + NUM_FIELDS];
+  unsigned short num = 0;
+  Code_t retval;
   ZNotice_t snotice;
-  char *pack, *cp;
+  char *pack;
   int packlen;
-  Code_t retval;
-  String *sender;
-
-  for (subs = newsubs; subs; subs = subs->next)
-    found++;
-
-  if (found == 0)
-    return(ZERR_NONE);
-  
-  sender = make_string(notice->z_sender, 0);
-
-  if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) == (char **) 0) {
-    syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
-    return(ENOMEM);
-  }
-
-  /* grab the client information from the incoming message */
-  cp = notice->z_message;
-  text[0] = cp;
-
-  I_ADVANCE(2);
-  text[1] = cp;
-
-  I_ADVANCE(3);
+  Client **clientp;
+  char port[16];
 
-  found = 0;
-  for (subs = newsubs; subs; subs = next) {
-    next=subs->next;
-    acl = class_get_acl(subs->dest.classname);
-    if (acl) {
-      if (!access_check(sender->string, acl, SUBSCRIBE)) {
-        syslog(LOG_WARNING, "subscr unauth %s class %s",
-               sender->string, subs->dest.classname->string);
-        continue; /* the for loop */
-      }
-      if (wildcard_instance == subs->dest.inst) {
-        if (!access_check(sender->string, acl, INSTWILD)) {
-          syslog(LOG_WARNING,
-                 "subscr unauth %s class %s wild inst",
-                 sender->string, subs->dest.classname->string);
-          continue;
-        }
-      }
-    }
+#if 0
+  zdbug((LOG_DEBUG, "realm_subs"));
+#endif
 
-    /* okay to subscribe.  save for return trip */
-    text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
-    text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
-    text[found*NUM_FIELDS + 4] = "";
-    found++;
+  if (!realm->remsubs)
+    return ZERR_NONE;
 
-    retval = triplet_register(realm->client, &subs->dest, realm);
+  for (subs=realm->remsubs; subs; subs = next) {
+    next = subs->next;
 #ifdef DEBUG
-    zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
+    zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string,
             subs->dest.inst->string, subs->dest.recip->string));
 #endif
 
-    if (retval != ZERR_NONE) {
-      if (retval == ZSRV_CLASSXISTS) {
-        continue;
-      } else {
-        free_subscriptions(subs->next);
-        free(text);
-        return retval;
+    num = 0;
+    if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) 
+                            &num, sizeof(u_short))) != ZERR_NONE) 
+      {
+       syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s",
+              error_message(retval));
+       return(ZERR_NONE);
       }
-    }
-    LIST_INSERT(&realm->subs, subs);
-  }
-  /* don't send confirmation if we're not the initial server contacted */
-  if (!(server_which_server(who) || found == 0)) {
-    snotice = *notice;
-    snotice.z_opcode = REALM_ADD_SUBSCRIBE;
+
+    text[0] = "0.0.0.0";
+    text[1] = port;
+    text[2] = subs->dest.classname->string;
+    text[3] = subs->dest.inst->string;
+    text[4] = subs->dest.recip->string;
+
+    /* format snotice */
     snotice.z_class_inst = ZEPHYR_CTL_REALM;
-    snotice.z_port = srv_addr.sin_port;
-    if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
-      syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
-             error_message(retval));
-      free(text);
-      return(ZERR_NONE);      
-    }
+    snotice.z_opcode = REALM_REQ_SUBSCRIBE;
+    snotice.z_port = 0;
+    snotice.z_class = ZEPHYR_CTL_CLASS;
+
+    snotice.z_recipient = "";
+    snotice.z_kind = ACKED;
+    snotice.z_num_other_fields = 0;
+    snotice.z_default_format = "";
+    /* Evil. In the event this is ACL'd, pick a user who is subscribed and
+       resubmit them as the sender. */
+    clientp = triplet_lookup(&subs->dest);
+    if (!clientp)
+      snotice.z_sender = "";
+    else
+      snotice.z_sender = (*clientp)->principal->string;
+    snotice.z_default_format = "";
+
+    if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2,
+                                   &pack, &packlen, ZNOAUTH)) != ZERR_NONE) 
+      {
+       syslog(LOG_WARNING, "subscr_rlm_subs format: %s",
+              error_message(retval));
+       return(ZERR_NONE);
+      }
+  
     if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
-      syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
-             error_message(retval));
-      free(text);
+      syslog(LOG_WARNING, "subscr_rlm_subs parse: %s",
+            error_message(retval));
       free(pack);
       return(ZERR_NONE);
     }
-    realm_handoff(&snotice, 1, who, realm, 0);
+    realm_handoff(&snotice, 1, NULL, realm, 0);
     free(pack);
   }
-  free(text);
+
   return ZERR_NONE;
 }
 
-Code_t subscr_foreign_user(notice, who, realm)
-    ZNotice_t *notice;
-    struct sockaddr_in *who;
-    Realm *realm;
+/* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */
+static Code_t
+subscr_check_foreign_subs(ZNotice_t *notice,
+                         struct sockaddr_in *who,
+                         Server *server,
+                         ZRealm *realm,
+                         Destlist *newsubs)
+{
+    Destlist *subs, *subs2, *next;
+    Acl *acl;
+    char **text;
+    int found = 0;
+    ZNotice_t snotice;
+    char *pack, *cp;
+    int packlen;
+    Code_t retval;
+    String *sender;
+
+    for (subs = newsubs; subs; subs = subs->next)
+       found++;
+
+    if (found == 0)
+       return(ZERR_NONE);
+  
+    sender = make_string(notice->z_sender, 0);
+    
+    if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) 
+       == (char **) 0) {
+       syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)");
+       free_string(sender);
+       return(ENOMEM);
+    }
+
+    /* grab the client information from the incoming message */
+    cp = notice->z_message;
+    text[0] = cp;
+
+    I_ADVANCE(2);
+    text[1] = cp;
+
+    I_ADVANCE(3);
+
+    found = 0;
+    for (subs = newsubs; subs; subs = next) {
+       ZRealm *rlm;
+       next=subs->next;
+       if (subs->dest.recip->string[0] != '\0') {
+         rlm = realm_which_realm(who);
+         syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)",
+                subs->dest.recip->string,
+                sender->string, rlm->name);
+         continue;
+       }
+       acl = class_get_acl(subs->dest.classname);
+       if (acl) {
+           rlm = realm_which_realm(who); 
+           if (rlm && server == me_server) { 
+               if (!realm_sender_in_realm(rlm->name, sender->string)) { 
+                   syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s",
+                          sender->string, rlm->name, 
+                          subs->dest.classname->string);
+                   free_subscriptions(newsubs);
+                   free_string(sender);
+                   free(text);
+                   return ZSRV_CLASSRESTRICTED;
+               } 
+           } 
+           if (!access_check(sender->string, acl, SUBSCRIBE)) {
+               syslog(LOG_WARNING, "subscr unauth %s class %s",
+                      sender->string, subs->dest.classname->string);
+               continue; /* the for loop */
+           }
+           if (wildcard_instance == subs->dest.inst) {
+               if (!access_check(sender->string, acl, INSTWILD)) {
+                   syslog(LOG_WARNING,
+                          "subscr unauth %s class %s wild inst",
+                          sender->string, subs->dest.classname->string);
+                   continue;
+               }
+           }
+       }
+
+       /* okay to subscribe.  save for return trip */
+       text[found*NUM_FIELDS + 2] = subs->dest.classname->string;
+       text[found*NUM_FIELDS + 3] = subs->dest.inst->string;
+       text[found*NUM_FIELDS + 4] = "";
+       found++;
+       
+       retval = triplet_register(realm->client, &subs->dest, realm);
+#ifdef DEBUG
+       zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string,
+               subs->dest.inst->string, subs->dest.recip->string));
+#endif
+
+       if (retval != ZERR_NONE) {
+           if (retval == ZSRV_CLASSXISTS) {
+               continue;
+           } else {
+               free_subscriptions(newsubs); /* subs->next XXX */
+               free_string(sender);
+               free(text);
+               return retval;
+           }
+       }
+       LIST_INSERT(&realm->subs, subs);
+    }
+    /* don't send confirmation if we're not the initial server contacted */
+    if (!(server_which_server(who) || found == 0)) {
+       snotice = *notice;
+       snotice.z_opcode = REALM_ADD_SUBSCRIBE;
+       snotice.z_class_inst = ZEPHYR_CTL_REALM;
+       snotice.z_port = srv_addr.sin_port;
+       if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) {
+           syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s",
+                  error_message(retval));
+           free_string(sender);
+           free(text);
+           return(ZERR_NONE);      
+       }
+       if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) {
+           syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s",
+                  error_message(retval));
+           free_string(sender);
+           free(text);
+           free(pack);
+           return(ZERR_NONE);
+       }
+       realm_handoff(&snotice, 1, who, realm, 0);
+       free(pack);
+    }
+    free_string(sender);
+    free(text);
+    return ZERR_NONE;
+}
+
+/* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */
+Code_t subscr_foreign_user(ZNotice_t *notice,
+                          struct sockaddr_in *who,
+                          Server *server,
+                          ZRealm *realm)
 {
   Destlist *newsubs, *temp;
   Acl *acl;
@@ -1462,14 +1584,14 @@ Code_t subscr_foreign_user(notice, who, realm)
   Client *client;
   ZNotice_t snotice;
   struct sockaddr_in newwho;
-  char *cp;
+  char *cp, *tp0, *tp1;
   char rlm_recipient[REALM_SZ + 1];
   
 #if 0
   zdbug((LOG_DEBUG, "subscr_foreign_user"));
 #endif
   
-  cp = notice->z_message;
+  tp0 = cp = notice->z_message;
   
   newwho.sin_addr.s_addr = inet_addr(cp);
   if (newwho.sin_addr.s_addr == -1) {
@@ -1478,6 +1600,7 @@ Code_t subscr_foreign_user(notice, who, realm)
   }
 
   I_ADVANCE(0);
+  tp1 = cp;
   
   snotice = *notice;
   
@@ -1503,6 +1626,13 @@ Code_t subscr_foreign_user(notice, who, realm)
   if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) {
     /* this was approved by the other realm, add subscriptions */
     
+    if (!strcmp(tp0, "0.0.0.0")) {
+      /* skip bogus ADD reply from subscr_realm_subs */
+      zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped"));
+      return(ZERR_NONE);
+    }
+
+    zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1));
     client = client_find(&newwho.sin_addr, snotice.z_port);
     if (client == (Client *)0) {
       syslog(LOG_WARNING, "no client at %s/%d",
@@ -1520,9 +1650,10 @@ Code_t subscr_foreign_user(notice, who, realm)
         temp->dest.recip = make_string(rlm_recipient, 0);
     }
     
-    status = subscr_add_raw(client, (Realm *)0, newsubs);
+    status = subscr_add_raw(client, (ZRealm *)0, newsubs);
   } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) {
-    status = subscr_check_foreign_subs(notice, who, realm, newsubs);
+    zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1));
+    status = subscr_check_foreign_subs(notice, who, server, realm, newsubs);
   } else {
     syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user",
            snotice.z_opcode);