]> jfr.im git - irc/rizon/plexus4.git/commitdiff
Change SWEBIRC to be a temporary config on the local server(s). Services (any server...
authorOrillion <redacted>
Fri, 13 Jan 2017 19:47:27 +0000 (14:47 -0500)
committerAdam <redacted>
Fri, 13 Jan 2017 19:47:27 +0000 (14:47 -0500)
17 files changed:
doc/reference.conf
include/client.h
include/conf.h
modules/core/m_server.c
modules/m_chghost.c
modules/m_stats.c
modules/m_webirc.c
modules/m_whois.c
src/client.c
src/conf_lexer.l
src/conf_parser.y
src/s_user.c
src/upgrade.c
test/Makefile.am
test/plexus_test.h
test/test.c
test/tests/webirc.c [new file with mode: 0644]

index 987286da655089652fcfe6acc22731dd4e593cb6..6d466e1baf988852873524c582b0ad4b4320591e 100644 (file)
@@ -808,6 +808,7 @@ shared {
         *      unresv  - allow oper/server to unresv
         *      locops  - allow oper/server to locops - only used for servers that cluster
         *      session - allow servers to modify session exceptions
+        *      wline   - allow servers to modify webirc blocks
         *      all     - allow oper/server to do all of the above (default)
         */
        type = all;
index e4bbc30ec19f92828e3ba366d4ca8a26264b2556..2c5aab9be690e2fb00637435f8d20761bc8a0f70 100644 (file)
@@ -410,8 +410,6 @@ struct LocalUser
   time_t last_kill_time; /* when this client last send kill */
   int kill_count;
 
-  char*          cgisockhost; /* if this client is a cgiirc client, this is the host of where they are from */
-
   dlink_list dnsbl_queries; /* Pending DNS queries blocking registration */
 
   char sasl_agent[IDLEN + 1];
@@ -502,9 +500,11 @@ struct Client
    */
   char              sockhost[HOSTIPLEN + 1]; /* This is the host name from the
                                                 socket ip address as string */
-  char             *certfp;
+  char              *certfp;
 
   dlink_list        invited;   /**< invites this client has to channels */
+
+  char              *cgisockhost; /**< if this client is a webirc client, this is the host of where they are from */
 };
 
 
index 75130c3f918d044b84896e5cafd2b130892d6349..612092ffe4b13e4eee6f3a92d8ffb7d6ec7697d2 100644 (file)
@@ -60,6 +60,7 @@
 #define CONF_FLAGS_WEBIRC               0x00020000
 #define CONF_FLAGS_EXEMPTDNSBL          0x00040000
 #define CONF_FLAGS_NEED_ACCOUNT         0x00080000
+#define CONF_FLAGS_WEBIRC_CLOSED        0x00100000 // When set, the entry is not allowed to accept webirc requests
 
 /* Macros for struct MaskItem */
 #define IsConfWebIRC(x)         ((x)->flags & CONF_FLAGS_WEBIRC)
 #define SHARED_DLINE            0x0080
 #define SHARED_UNDLINE          0x0100
 #define SHARED_SESSION          0x0200
+#define SHARED_WLINE            0x0400
 
 #define SHARED_ALL              (SHARED_KLINE | SHARED_UNKLINE |\
                                  SHARED_XLINE | SHARED_UNXLINE |\
                                  SHARED_RESV | SHARED_UNRESV |\
                                  SHARED_LOCOPS | SHARED_DLINE |\
-                                 SHARED_UNDLINE | SHARED_SESSION)
+                                 SHARED_UNDLINE | SHARED_SESSION |\
+                                 SHARED_WLINE)
 
 
 enum maskitem_type
@@ -128,6 +131,7 @@ enum maskitem_type
   CONF_OPER     = 1 << 12,
   CONF_DNSBL    = 1 << 13,
   CONF_SESSION  = 1 << 14,
+  CONF_WLINE    = 1 << 15,
 };
 
 enum
index 3ef2df08d1ec7ca2c38d5a083080f4a84dd154e0..58338bc69ae373688277a5cc654078702e2527e3 100644 (file)
@@ -117,6 +117,9 @@ sendnick_TS(struct Client *client_p, struct Client *target_p)
     if (!EmptyString(target_p->certfp))
       sendto_one(client_p, ":%s ENCAP * CERTFP %s :%s",
                  ID(&me), ID(target_p), target_p->certfp);
+
+    if (!EmptyString(target_p->cgisockhost))
+      sendto_one(client_p, ":%s ENCAP * UWEBIRC %s :%s", ID(&me), ID(target_p), target_p->cgisockhost);
   }
 
   if (target_p->away[0])
index 16eb6e1f693fdc46f4658ffa80d47f5a81efa26a..14dec99de6ae00382f3ace02c5a0ba2d2e61de98 100644 (file)
@@ -161,8 +161,8 @@ me_chgrealhost(struct Client *client_p, struct Client *source_p, int parc, char
 
   freeaddrinfo(res);
 
-  if (MyConnect(target_p) && target_p->localClient->cgisockhost == NULL)
-    target_p->localClient->cgisockhost = xstrdup(target_p->sockhost);
+  if (target_p->cgisockhost == NULL)
+    target_p->cgisockhost = xstrdup(target_p->sockhost);
 
   strlcpy(target_p->sockhost, parv[2], sizeof(target_p->sockhost));
   strlcpy(target_p->realhost, parv[3], sizeof(target_p->realhost));
index 70ada0d9d9325ee15e95d7de4ce2145a618d0640..cb28f4ad84fda406e4d6eb72c9141b37aec0c8e3 100644 (file)
@@ -1296,6 +1296,39 @@ stats_servers(struct Client *source_p, int parc, char *parv[])
              from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
 }
 
+/* stats_wline()
+ *
+ * input        - client pointer
+ * output       - none
+ * side effects - client is shown a list of wlines (webirc configs)
+ */
+static void
+stats_wline(struct Client *source_p, int parc, char *parv[])
+{
+  for (int i = 0; i < ATABLE_SIZE; ++i)
+  {
+    dlink_node *ptr;
+
+    DLINK_FOREACH(ptr, atable[i].head)
+    {
+      struct AddressRec *arec = ptr->data;
+
+      if (arec->type != CONF_WLINE)
+        continue;
+
+      struct MaskItem *conf = arec->conf;
+
+      if (conf == NULL)
+        continue;
+
+      // IP * oper setat expires reason
+      sendto_one(source_p, ":%s %d %s W :%s * %s %ld %ld %s",
+                 me.name, RPL_STATSDEBUG, source_p->name,
+                 conf->host, conf->user, conf->setat, conf->until, conf->reason);
+    }
+  }
+}
+
 static void
 stats_gecos(struct Client *source_p, int parc, char *parv[])
 {
@@ -1590,6 +1623,8 @@ static const struct StatsStruct
   { 'u',        stats_uptime,           0,      0       },
   { 'U',        stats_shared,           1,      0       },
   { 'v',        stats_servers,          1,      0       },
+  { 'w',        stats_wline,            1,      0       },
+  { 'W',        stats_wline,            1,      0       },
   { 'x',        stats_gecos,            1,      0       },
   { 'X',        stats_gecos,            1,      0       },
   { 'y',        stats_class,            1,      0       },
index 075e4b4512a2305362e11a292f627b87311ab81b..b3b4caade158b1fdb31ee94dcf0683595dc912d1 100644 (file)
 #include "hash.h"
 #include "s_misc.h"
 
-#define CACHED_WEBIRC_MAX 32 /* unique ip + password */
-
-static dlink_list cached_webircs;
-
-struct webirc
-{
-  char ip[HOSTIPLEN + 1];
-  char password[IRCD_BUFSIZE];
-  dlink_node node;
-};
-
-static void
-webirc_cache_clear()
-{
-  dlink_node *ptr, *next;
-
-  DLINK_FOREACH_SAFE(ptr, next, cached_webircs.head)
-  {
-    struct webirc *w = ptr->data;
-
-    dlinkDelete(&w->node, &cached_webircs);
-    MyFree(w);
-  }
-}
-
-static struct webirc *
-webirc_cache_find(const char *ip, const char *password)
-{
-  dlink_node *ptr;
-
-  DLINK_FOREACH(ptr, cached_webircs.head)
-  {
-    struct webirc *w = ptr->data;
-
-    if (!strcasecmp(ip, w->ip) && !strcmp(password, w->password))
-    {
-      return w;
-    }
-  }
-
-  return NULL;
-}
-
-static void
-webirc_cache_del(const char *ip, const char *password)
-{
-  struct webirc *w = webirc_cache_find(ip, password);
-  if (w == NULL)
-    return;
-
-  dlinkDelete(&w->node, &cached_webircs);
-  MyFree(w);
-}
-
-static void
-webirc_cache_add(const char *ip, const char *password)
-{
-  if (webirc_cache_find(ip, password))
-    return;
-
-  if (dlink_list_length(&cached_webircs) >= CACHED_WEBIRC_MAX)
-  {
-    struct webirc *w = cached_webircs.head->data;
-    dlinkDelete(&w->node, &cached_webircs);
-    MyFree(w);
-  }
-
-  struct webirc *w = MyMalloc(sizeof(struct webirc));
-  strlcpy(w->ip, ip, sizeof(w->ip));
-  strlcpy(w->password, password, sizeof(w->password));
-  dlinkAddTail(w, &w->node, &cached_webircs);
-}
-
-static int
-webirc_broadcast(struct Client *source_p, char *parv[])
-{
-  dlink_node *ptr;
-  int sent = 0;
-
-  DLINK_FOREACH(ptr, global_serv_list.head)
-  {
-    struct Client *target = ptr->data;
-
-    if (IsMe(target) || !IsCapable(target->from, CAP_TS6) || !HasFlag(target, FLAGS_SERVICE))
-      continue;
-
-    sendto_one(target, ":%s ENCAP %s SWEBIRC REQ %s %s %s %s %s %s %s %s :%s",
-                       me.id, target->name,
-                       source_p->id, source_p->realhost, source_p->sockhost, source_p->certfp ? source_p->certfp : "*", "*",
-                       parv[1], IsGotId(source_p) ? source_p->username : parv[2], parv[3], parv[4]);
-    ++sent;
-  }
-
-  return sent;
-}
-
 static void
 webirc_apply(struct Client *target_p, const char *host, const char *ip, const char *password)
 {
@@ -163,8 +67,8 @@ webirc_apply(struct Client *target_p, const char *host, const char *ip, const ch
   clear_dnsbl_lookup(target_p);
 
   /* store original host */
-  if (target_p->localClient->cgisockhost == NULL)
-    target_p->localClient->cgisockhost = xstrdup(target_p->sockhost);
+  if (target_p->cgisockhost == NULL)
+    target_p->cgisockhost = xstrdup(target_p->sockhost);
 
   /* apply new ip and host */
   strlcpy(target_p->sockhost, ip, sizeof(target_p->sockhost));
@@ -251,44 +155,34 @@ mr_webirc(struct Client *client_p, struct Client *source_p, int parc, char *parv
   };
 
   conf = find_conf_by_address(CONF_CLIENT, &lookup);
+
   if (conf == NULL || !IsConfClient(conf) || !IsConfWebIRC(conf))
   {
-    if (EmptyString(source_p->id))
-    {
-      const char *id;
-
-      /* Allocate a UID. */
-      while (hash_find_id((id = uid_get())) != NULL)
-        ;
+    struct MaskLookup wlinelookup = {
+      .name     = source_p->realhost,
+      .addr     = &source_p->localClient->ip,
+      .fam      = source_p->localClient->aftype,
+      .cmpfunc  = match
+    };
 
-      strlcpy(source_p->id, id, sizeof(source_p->id));
-      hash_add_id(source_p);
-    }
-
-    int sent = webirc_broadcast(source_p, parv);
+    // Unable to find in client config, try wline config.
+    conf = find_conf_by_address(CONF_WLINE, &wlinelookup);
 
-    if (webirc_cache_find(source_p->sockhost, parv[1]))
+    if (conf == NULL)
     {
-      // cache says okay, we'll process it ourselves until told otherwise
-      webirc_apply(source_p, parv[3], parv[4], parv[1]);
+      sendto_one(source_p, ":%s NOTICE %s :WEBIRC: access denied (no auth block, or bad password)",
+                  me.name, source_p->name[0] ? source_p->name : "*");
+      exit_client(source_p, &me, "WEBIRC: access denied");
+      return;
     }
-    else
+
+    if (HasFlag(conf, CONF_FLAGS_WEBIRC_CLOSED))
     {
-      if (sent == 0)
-      {
-        // request wasn't sent
-        sendto_one(source_p, ":%s NOTICE %s :WEBIRC: access denied (no auth block, or bad password)",
-                   me.name, source_p->name[0] ? source_p->name : "*");
-        exit_client(source_p, &me, "WEBIRC: access denied");
-      }
-      else
-      {
-        // hold registration until request comes back
-        source_p->localClient->registration |= REG_NEED_WEBIRC;
-      }
+      sendto_one(source_p, ":%s NOTICE %s :WEBIRC: webirc block is full",
+                  me.name, source_p->name[0] ? source_p->name : "*");
+      exit_client(source_p, &me, "WEBIRC: webirc block is full");
+      return;
     }
-
-    return;
   }
 
   /* find_address_conf won't check password with need_password */
@@ -303,61 +197,250 @@ mr_webirc(struct Client *client_p, struct Client *source_p, int parc, char *parv
   webirc_apply(source_p, parv[3], parv[4], parv[1]);
 }
 
+static struct MaskItem *
+find_webirc(const char *address)
+{
+  struct irc_ssaddr addr;
+  int bits;
+
+  int masktype = parse_netmask(address, &addr, &bits);
+
+  struct MaskLookup lookup = {
+    .name     = address,
+    .fam      = masktype != HM_HOST ? addr.ss.ss_family : 0,
+    .addr     = masktype != HM_HOST ? &addr : NULL,
+    .cmpfunc  = irccmp
+  };
+
+  return find_conf_by_address(CONF_WLINE, &lookup);
+}
+
 /*
- * me_swebirc
- *      parv[1] = operation (req, ack, nak)
- *      parv[2] = client uid
- *      parv[3] = client realhost
- *      parv[4] = client sockhost
- *      parv[5] = client certfp
- *      parv[6] = webirc certfp
- *      parv[7] = webirc password
- *      parv[8] = webirc username
- *      parv[9] = requested host
- *      parv[10] = requsted ip
+ * swebirc_add
+ *      parv[1] = operation SET    - ignored
+ *      parv[2] = webirc host
+ *      parv[3] = webirc password
+ *      parv[4] = webirc creator
+ *      parv[5] = webirc created
+ *      parv[6] = webirc expires
+ *      parv[7] = webirc reason
  */
 static void
-me_swebirc(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+swebirc_add(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+  const char *mask       = parv[2];
+  const char *password   = parv[3];
+  const char *creator    = parv[4];
+  const char *createdstr = parv[5];
+  const char *expirestr  = parv[6];
+  const char *reason     = parv[parc - 1];
+
+  struct Client *server = IsServer(source_p) ? source_p : source_p->servptr;
+
+  if (!find_matching_name_conf(CONF_ULINE, server->name,
+                               NULL,
+                               NULL,
+                               SHARED_WLINE))
+  {
+    return;
+  }
+
+  struct MaskItem *conf = find_webirc(mask);
+
+  if (conf != NULL)
+  {
+    delete_one_address_conf(conf->host, conf);
+  }
+
+  conf = conf_make(CONF_WLINE);
+
+  conf->passwd = xstrdup(password);
+  conf->user   = xstrdup(creator);
+  conf->host   = xstrdup(mask);
+  conf->setat  = atol(createdstr);
+  conf->until  = atol(expirestr);
+  conf->reason = xstrdup(reason);
+
+  // XXX hack to make find_conf_by_address not try to match the webirc
+  // password against what we provide in the lookup
+  AddFlag(conf, CONF_FLAGS_NEED_PASSWORD);
+
+  SetConfDatabase(conf);
+
+  add_conf_by_address(CONF_WLINE, conf);
+
+  sendto_snomask(SNO_DEBUG, L_ALL,
+                 "%s added wline for %s, to expire on %s",
+                 source_p->name, conf->host, conf->until != 0 ? myctime(conf->until) : "never");
+}
+
+/*
+ * swebirc_remove
+ *      parv[1] = operation UNSET - ignored
+ *      parv[2] = webirc host
+ */
+static void
+swebirc_remove(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+  const char *mask = parv[2];
+
+  struct Client *server = IsServer(source_p) ? source_p : source_p->servptr;
+
+  if (!find_matching_name_conf(CONF_ULINE, server->name,
+                               NULL,
+                               NULL,
+                               SHARED_WLINE))
+  {
+    return;
+  }
+
+  struct MaskItem *conf = find_webirc(mask);
+
+  if (conf == NULL)
+  {
+    // Does not exist
+    return;
+  }
+
+  sendto_snomask(SNO_DEBUG, L_ALL,
+                 "%s removed wline for %s",
+                 source_p->name, conf->host);
+
+  delete_one_address_conf(conf->host, conf);
+}
+
+/*
+ * swebirc_open
+ *      parv[1] = operation OPEN - ignored
+ *      parv[2] = webirc host
+ */
+static void
+swebirc_open(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
 {
-  if (!HasFlag(source_p, FLAGS_SERVICE))
+  const char *mask     = parv[2];
+
+  struct Client *server = IsServer(source_p) ? source_p : source_p->servptr;
+
+  if (!find_matching_name_conf(CONF_ULINE, server->name,
+                               NULL,
+                               NULL,
+                               SHARED_WLINE))
+  {
     return;
+  }
+
+  struct MaskItem *conf = find_webirc(mask);
 
-  const char *operation = parv[1],
-             *uid = parv[2],
-             *sockhost = parv[4],
-             *password = parv[parc - 4],
-             *host = parv[parc - 2],
-             *ip = parv[parc - 1];
+  if (conf == NULL)
+  {
+    // Does not exist
+    return;
+  }
 
-  /* update cache whether or not the client still exists */
-  if (!strcmp(operation, "ACK"))
+  if (!HasFlag(conf, CONF_FLAGS_WEBIRC_CLOSED))
   {
-    webirc_cache_add(sockhost, password);
+    // Entry is not closed.
+    return;
   }
-  else if (!strcmp(operation, "NAK"))
+
+  sendto_snomask(SNO_DEBUG, L_ALL,
+                 "%s opened wline for %s",
+                 source_p->name, conf->host);
+
+  DelFlag(conf, CONF_FLAGS_WEBIRC_CLOSED);
+}
+
+/*
+ * swebirc_close
+ *      parv[1] = operation CLOSE - ignored
+ *      parv[2] = webirc host
+ */
+static void
+swebirc_close(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+  const char *mask = parv[2];
+
+  struct Client *server = IsServer(source_p) ? source_p : source_p->servptr;
+
+  if (!find_matching_name_conf(CONF_ULINE, server->name,
+                               NULL,
+                               NULL,
+                               SHARED_WLINE))
   {
-    webirc_cache_del(sockhost, password);
+    return;
   }
 
-  struct Client *target_p = hash_find_id(uid);
-  if (target_p == NULL || !IsUnknown(target_p) || !(target_p->localClient->registration & REG_NEED_WEBIRC))
+  struct MaskItem *conf = find_webirc(mask);
+
+  if (conf == NULL)
+  {
+    // Does not exist
     return;
+  }
 
-  // only looking for successful operations
-  if (!strcmp(operation, "ACK"))
+  if (HasFlag(conf, CONF_FLAGS_WEBIRC_CLOSED))
   {
-    webirc_apply(target_p, host, ip, password);
+    // Entry already closed
+    return;
+  }
+
+  sendto_snomask(SNO_DEBUG, L_ALL,
+                 "%s closed wline for %s",
+                 source_p->name, conf->host);
+
+  AddFlag(conf, CONF_FLAGS_WEBIRC_CLOSED);
+}
 
-    target_p->localClient->registration &= ~REG_NEED_WEBIRC;
-    if (!target_p->localClient->registration)
-      register_local_user(target_p);
+/*
+ * me_swebirc
+ *      parv[1] = operation (SET, UNSET, OPEN, CLOSE)
+ *      parv[2] = webirc host
+ *      parv[3] = webirc password
+ *      parv[4] = webirc creator
+ *      parv[5] = webirc created
+ *      parv[6] = webirc expires
+ *      parv[7] = webirc reason
+ */
+static void
+me_swebirc(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+  const char *operation = parv[1];
+
+  if (!strcmp(operation, "SET") && parc == 8)
+  {
+    swebirc_add(client_p, source_p, parc, parv);
+  }
+  else if (!strcmp(operation, "UNSET"))
+  {
+    swebirc_remove(client_p, source_p, parc, parv);
   }
-  else if (!strcmp(operation, "NAK"))
+  else if (!strcmp(operation, "OPEN"))
   {
-    sendto_one(target_p, ":%s NOTICE %s :WEBIRC: access denied (no access, invalid password, or user limit exceeded)",
-               me.name, target_p->name[0] ? target_p->name : "*");
-    exit_client(target_p, &me, "WEBIRC: access denied");
+    swebirc_open(client_p, source_p, parc, parv);
   }
+  else if (!strcmp(operation, "CLOSE"))
+  {
+    swebirc_close(client_p, source_p, parc, parv);
+  }
+}
+
+/*
+ * me_uwebirc
+ *      parv[1] = user
+ *      parv[2] = webirc sochost
+ */
+static void
+me_uwebirc(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+  struct Client *target_p = find_person(client_p, parv[1]);
+  if (target_p == NULL)
+    return;
+
+  MyFree(target_p->cgisockhost);
+  target_p->cgisockhost = NULL;
+
+  if (parc > 2 && !EmptyString(parv[2]))
+    target_p->cgisockhost = xstrdup(parv[2]);
 }
 
 static struct Message webirc_msgtab =
@@ -375,7 +458,7 @@ static struct Message webirc_msgtab =
 static struct Message swebirc_msgtab =
 {
   .cmd = "SWEBIRC",
-  .args_min = 11,
+  .args_min = 3,
   .args_max = MAXPARA,
   .handlers[UNREGISTERED_HANDLER] = m_unregistered,
   .handlers[CLIENT_HANDLER] = m_ignore,
@@ -384,11 +467,24 @@ static struct Message swebirc_msgtab =
   .handlers[OPER_HANDLER] = m_ignore,
 };
 
+static struct Message uwebirc_msgtab =
+{
+  .cmd = "UWEBIRC",
+  .args_min = 2,
+  .args_max = MAXPARA,
+  .handlers[UNREGISTERED_HANDLER] = m_unregistered,
+  .handlers[CLIENT_HANDLER] = m_ignore,
+  .handlers[SERVER_HANDLER] = m_ignore,
+  .handlers[ENCAP_HANDLER] = me_uwebirc,
+  .handlers[OPER_HANDLER] = m_ignore,
+};
+
 static void
 module_init(void)
 {
   mod_add_cmd(&webirc_msgtab);
   mod_add_cmd(&swebirc_msgtab);
+  mod_add_cmd(&uwebirc_msgtab);
 }
 
 static void
@@ -396,8 +492,7 @@ module_exit(void)
 {
   mod_del_cmd(&webirc_msgtab);
   mod_del_cmd(&swebirc_msgtab);
-
-  webirc_cache_clear();
+  mod_del_cmd(&uwebirc_msgtab);
 }
 
 struct module module_entry =
index 150c54125df74df4e7724cfc6eb81ddfe8d7d1e5..34a550c0ccd42b846b9f4713ae9c3c71062816ff 100644 (file)
@@ -174,8 +174,8 @@ whois_person(struct Client *source_p, struct Client *target_p)
                  source_p->name, target_p->name);
   }
 
-  if (HasUMode(source_p, UMODE_OPER) && MyClient(target_p) && target_p->localClient->cgisockhost)
-    sendto_one(source_p, form_str(RPL_WHOISREALIP), me.name, source_p->name, target_p->name, target_p->localClient->cgisockhost);
+  if (HasUMode(source_p, UMODE_OPER) && target_p->cgisockhost)
+    sendto_one(source_p, form_str(RPL_WHOISREALIP), me.name, source_p->name, target_p->name, target_p->cgisockhost);
 
   if (HasUMode(source_p, UMODE_OPER) || source_p == target_p)
   {
index 0cd6bc9dc294043f4b8167283cee4ec341a8e9df..a92fa671abac9b3ba2eb78cfea07df547c702033 100644 (file)
@@ -172,6 +172,7 @@ free_client(struct Client *client_p)
 
   MyFree(client_p->serv);
   MyFree(client_p->certfp);
+  MyFree(client_p->cgisockhost);
 
   assert(dlink_list_length(&client_p->invited) == 0);
 
@@ -187,8 +188,6 @@ free_client(struct Client *client_p)
     MyFree(client_p->localClient->response);
     MyFree(client_p->localClient->auth_oper);
 
-    MyFree(client_p->localClient->cgisockhost);
-
     /*
      * clean up extra sockets from P-lines which have been discarded.
      */
index f449ffe5464965a2aa2367da39a01e88c5ab51b6..b6ea9b816f96f6c4e6cb61b0492df0c6bbcfe2df 100644 (file)
@@ -389,6 +389,7 @@ wallops                     { return T_WALLOPS; }
 wallusers                   { return T_WALLUSERS; }
 warn_no_nline               { return WARN_NO_NLINE; }
 webirc                      { return T_WEBIRC; }
+wline                       { return WLINE; }
 xline                       { return XLINE; }
 
 yes                         { yylval.number = 1; return TBOOL; }
index dc687897c7bcd267df477b709b8266e314658a3c..7a9e82fa350dc91c50ce1a58419e3b77d818b019 100644 (file)
@@ -408,6 +408,7 @@ reset_block_state(void)
 %token  VHOST
 %token  VHOST6
 %token  WARN_NO_NLINE
+%token  WLINE
 %token  XLINE
 
 %type  <string> QSTRING
@@ -2398,6 +2399,10 @@ shared_type_item: KLINE
 {
   if (conf_parser_ctx.pass == 2)
     block_state.flags.value |= SHARED_SESSION;
+} | WLINE
+{
+  if (conf_parser_ctx.pass == 2)
+    block_state.flags.value |= SHARED_WLINE;
 } | T_ALL
 {
   if (conf_parser_ctx.pass == 2)
index cd0d72ffbb52c947051ac362873dfb016d58f588..bca161424a8a650382549deb720153d9917bcd22 100644 (file)
@@ -712,6 +712,9 @@ introduce_client(struct Client *source_p)
 
         if (!EmptyString(source_p->certfp))
           sendto_one(server, ":%s ENCAP * CERTFP %s :%s", ID(&me), ID(source_p), source_p->certfp);
+
+        if (!EmptyString(source_p->cgisockhost))
+          sendto_one(server, ":%s ENCAP * UWEBIRC %s :%s", ID(&me), ID(source_p), source_p->cgisockhost);
       }
     }
   }
index 4e60293ef9b8b2a814b6c2e65ac9d9555cb0421f..a25a7f62ce87543210a08bb560b3f3838ce482fb 100644 (file)
@@ -103,6 +103,7 @@ serialize_client(struct Client *client, int migration)
   json_object_set_new(j, "info", json_string(encode_string(client->info)));
   json_object_set_new(j, "sockhost", json_string(client->sockhost));
   json_object_set_new(j, "certfp", json_string(client->certfp));
+  json_object_set_new(j, "cgisockhost", json_string(client->cgisockhost));
 
   if (client->localClient != NULL)
   {
@@ -125,7 +126,6 @@ serialize_client(struct Client *client, int migration)
       json_object_set_new(j, "fd.ssl", json_integer((intptr_t) client->localClient->fd.ssl));
     }
     json_object_set_new(j, "passwd", json_string(encode_string(client->localClient->passwd)));
-    json_object_set_new(j, "cgisockhost", json_string(client->localClient->cgisockhost));
     if (!migration)
     {
       json_object_set_new(j, "cert", json_integer((intptr_t) client->localClient->cert));
@@ -369,6 +369,9 @@ unserialize_client(json_t *client, int migrate)
   p = json_string_value(json_object_get(client, "certfp"));
   if (p)
     client_p->certfp = xstrdup(p);
+  p = json_string_value(json_object_get(client, "cgisockhost"));
+  if (p)
+    client_p->cgisockhost = xstrdup(p);
 
   if (IsMe(client_p->servptr))
   {
@@ -397,9 +400,6 @@ unserialize_client(json_t *client, int migrate)
     p = decode_string(json_string_value(json_object_get(client, "passwd")));
     if (p)
       client_p->localClient->passwd = xstrdup(p);
-    p = json_string_value(json_object_get(client, "cgisockhost"));
-    if (p)
-      client_p->localClient->cgisockhost = xstrdup(p);
     if (!migrate)
     {
       client_p->localClient->cert = (X509 *) json_integer_value(json_object_get(client, "cert"));
index c592980a78ee0b4454a01d9cab27a15e72f3a967..546f2ac040f02d6958f7886173c94ebd8eaa5cf5 100644 (file)
@@ -31,7 +31,8 @@ check_plexus_SOURCES = \
        tests/ping.c \
        tests/privmsg.c \
        tests/session.c \
-       tests/upgrade.c
+       tests/upgrade.c \
+       tests/webirc.c
 
 uninstall-local:
        ${RM} -f test.log trs.log
index b69801d285432ed6e5e5890a578ad080679c747d..085a191e48b8262bdbb3824d625c9d7cf2b2a1a0 100644 (file)
@@ -80,6 +80,7 @@ extern void extban_setup(Suite *s);
 extern void session_setup(Suite *s);
 extern void privmsg_setup(Suite *s);
 extern void ping_setup(Suite *s);
+extern void webirc_setup(Suite *s);
 
 #define tlog(fmt, ...) plexus_log(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
 extern void plexus_log(const char *, int, const char *, ...);
index 70adfaa89df5b6b7c179b7be0573d8365b0ecbfb..21c8cb9b12afeba0d5f7f980bb9f25dc292cb4ca 100644 (file)
@@ -41,6 +41,7 @@ add_testcases(Suite *s)
   session_setup(s);
   privmsg_setup(s);
   ping_setup(s);
+  webirc_setup(s);
 }
 
 int
diff --git a/test/tests/webirc.c b/test/tests/webirc.c
new file mode 100644 (file)
index 0000000..542d475
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ *  Copyright (C) 2017 Adam <Adam@anope.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *  USA
+ */
+
+#include "plexus_test.h"
+
+static struct MaskItem *
+webirc_find(const char *address)
+{
+  struct irc_ssaddr addr;
+  int bits;
+
+  int masktype = parse_netmask(address, &addr, &bits);
+
+  struct MaskLookup lookup = {
+    .name     = address,
+    .fam      = masktype != HM_HOST ? addr.ss.ss_family : 0,
+    .addr     = masktype != HM_HOST ? &addr : NULL,
+    .cmpfunc  = irccmp
+  };
+
+  return find_conf_by_address(CONF_WLINE, &lookup);
+}
+
+static struct MaskItem *
+webirc_create(const char *mask, const char *password)
+{
+  struct MaskItem *conf = conf_make(CONF_WLINE);
+
+  conf->passwd = xstrdup(password);
+  conf->user   = xstrdup("Adam");
+  conf->host   = xstrdup(mask);
+  conf->setat  = CurrentTime;
+  conf->until  = CurrentTime + 42L;
+  conf->reason = xstrdup("test");
+
+  AddFlag(conf, CONF_FLAGS_NEED_PASSWORD);
+
+  SetConfDatabase(conf);
+
+  add_conf_by_address(CONF_WLINE, conf);
+
+  return conf;
+}
+
+START_TEST(webirc_test)
+{
+  struct PlexusClient *client = client_create("test");
+
+  webirc_create("127.0.0.1", "hunter2");
+
+  io_write(client, "WEBIRC hunter2 . fakehost 1.2.3.4");
+
+  io_write(client, "USER %s . . :%s", client->name, client->name);
+  io_write(client, "NICK %s", client->name);
+
+  expect_numeric(client, RPL_WELCOME);
+
+  ck_assert_str_eq(client->client->host, "fakehost");
+}
+END_TEST
+
+START_TEST(swebirc_test)
+{
+  struct PlexusClient *server = server_register("plexus4.2");
+
+  struct MaskItem *conf = conf_make(CONF_ULINE);
+  conf->flags = SHARED_SESSION;
+  conf->name = xstrdup(server->name);
+
+  const time_t time = 123456789;
+
+  // set
+
+  io_write(server, "ENCAP %s SWEBIRC SET %s %s %s %lu %lu :%s",
+           me.name, "test.mask", "pass", "Adam", time, time, "test webirc");
+
+  expect_pingwait(server, &me);
+
+  struct MaskItem *webirc = webirc_find("test.mask");
+  ck_assert_ptr_ne(webirc, NULL);
+
+  ck_assert_str_eq(webirc->user, "Adam");
+  ck_assert_str_eq(webirc->host, "test.mask");
+  ck_assert_int_eq(webirc->setat, time);
+  ck_assert_int_eq(webirc->until, time);
+  ck_assert_str_eq(webirc->reason, "test webirc");
+  ck_assert(!HasFlag(webirc, CONF_FLAGS_WEBIRC_CLOSED));
+
+  // close
+
+  io_write(server, "ENCAP %s SWEBIRC CLOSE %s",
+           me.name, webirc->host);
+
+  expect_pingwait(server, &me);
+
+  ck_assert(HasFlag(webirc, CONF_FLAGS_WEBIRC_CLOSED));
+
+  // open
+
+  io_write(server, "ENCAP %s SWEBIRC OPEN %s",
+           me.name, webirc->host);
+
+  expect_pingwait(server, &me);
+
+  ck_assert(!HasFlag(webirc, CONF_FLAGS_WEBIRC_CLOSED));
+
+  // unset
+
+  io_write(server, "ENCAP %s SWEBIRC UNSET %s",
+           me.name, webirc->host);
+
+  expect_pingwait(server, &me);
+
+  webirc = webirc_find("test.mask");
+  ck_assert_ptr_eq(webirc, NULL);
+}
+END_TEST
+
+void
+webirc_setup(Suite *s)
+{
+  TCase *tc = tcase_create("webirc");
+
+  tcase_add_checked_fixture(tc, plexus_up, plexus_down);
+  tcase_add_test(tc, webirc_test);
+  tcase_add_test(tc, swebirc_test);
+
+  suite_add_tcase(s, tc);
+}