Bump patchlevel; add more epoll support; assertion check in
[ircu2.10.12-pk.git] / ircd / channel.c
index ff12cc1cae844197758d43e402ced3a381d9f869..1912d16275899a6a9470964f39fa45e40ccb6ab8 100644 (file)
@@ -258,24 +258,15 @@ int sub1_from_channel(struct Channel* chptr)
 
   chptr->users = 0;
 
-  /*
-   * Also channels without Apass set need to be kept alive,
-   * otherwise Bad Guys(tm) would be able to takeover
-   * existing channels too easily, and then set an Apass!
-   * However, if a channel without Apass becomes empty
-   * then we try to be kind to them and remove possible
-   * limiting modes.
-   */
-  chptr->mode.mode &= ~MODE_INVITEONLY;
-  chptr->mode.limit = 0;
-  /*
-   * We do NOT reset a possible key or bans because when
-   * the 'channel owners' can't get in because of a key
-   * or ban then apparently there was a fight/takeover
-   * on the channel and we want them to contact IRC opers
-   * who then will educate them on the use of Apass/upass.
+  /* There is a semantics problem here: Assuming no fragments across a
+   * split, a channel without Apass could be maliciously destroyed and
+   * recreated, and someone could set apass on the new instance.
+   *
+   * This could be fixed by preserving the empty non-Apass channel for
+   * the same time as if it had an Apass (but removing +i and +l), and
+   * reopping the first user to rejoin.  However, preventing net rides
+   * requires a backwards-incompatible protocol change..
    */
-
   if (!chptr->mode.apass[0])         /* If no Apass, destroy now. */
     destruct_channel(chptr);
   else if (TStime() - chptr->creationtime < 172800)    /* Channel younger than 48 hours? */
@@ -355,12 +346,15 @@ struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
 {
   char        nu[NICKLEN + USERLEN + 2];
   char        tmphost[HOSTLEN + 1];
+  char        iphost[SOCKIPLEN + 1];
+  char       *hostmask;
   char       *sr;
   struct Ban *found;
 
   /* Build nick!user and alternate host names. */
   ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
                 cli_name(cptr), cli_user(cptr)->username);
+  ircd_ntoa_r(iphost, &cli_ip(cptr));
   if (!IsAccount(cptr))
     sr = NULL;
   else if (HasHiddenHost(cptr))
@@ -385,10 +379,12 @@ struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
     if (res)
       continue;
     /* Compare host portion of ban. */
-    if (!((banlist->flags & BAN_IPMASK)
-         && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
-        && match(banlist->banstr + banlist->nu_len + 1, cli_user(cptr)->host)
-        && !(sr && match(banlist->banstr + banlist->nu_len + 1, sr) == 0))
+    hostmask = banlist->banstr + banlist->nu_len + 1;
+    if (((banlist->flags & BAN_IPMASK)
+         ? !ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits)
+         : match(hostmask, iphost))
+        && match(hostmask, cli_user(cptr)->host)
+        && !(sr && match(hostmask, sr) == 0))
       continue;
     /* If an exception matches, no ban can match. */
     if (banlist->flags & BAN_EXCEPTION)
@@ -1113,9 +1109,10 @@ char *pretty_mask(char *mask)
       user = mask;
       host = ++ptr;
     }
-    else if (*ptr == '.')
+    else if (*ptr == '.' || *ptr == ':')
     {
-      /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
+      /* Case 2: Found character specific to IP or hostname (without
+       * finding a '!' or '@' yet) */
       last_dot = ptr;
       continue;
     }
@@ -1288,7 +1285,8 @@ void clean_channelname(char *cn)
   int i;
 
   for (i = 0; cn[i]; i++) {
-    if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
+    if (i >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))
+        || !IsChannelChar(cn[i])) {
       cn[i] = '\0';
       return;
     }
@@ -1638,8 +1636,8 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
 
   /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
    */
-  if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
-    app_source = &me;
+  if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source) || IsMe(mbuf->mb_source))
+    app_source = &his;
   else
     app_source = mbuf->mb_source;
 
@@ -2545,6 +2543,7 @@ mode_parse_upass(struct ParseState *state, int *flag_p)
 static void
 mode_parse_apass(struct ParseState *state, int *flag_p)
 {
+  struct Membership *memb;
   char *t_str, *s;
   int t_len;
 
@@ -2653,10 +2652,18 @@ mode_parse_apass(struct ParseState *state, int *flag_p)
        send_reply(state->sptr, RPL_APASSWARN_SECRET, state->chptr->chname,
                    state->chptr->mode.apass);
       }
+      /* Give the channel manager level 0 ops. */
+      if (!(state->flags & MODE_PARSE_FORCE) && IsChannelManager(state->member))
+        SetOpLevel(state->member, 0);
     } else { /* remove the old apass */
       *state->chptr->mode.apass = '\0';
       if (MyUser(state->sptr))
         send_reply(state->sptr, RPL_APASSWARN_CLEAR);
+      /* Revert everyone to MAXOPLEVEL. */
+      for (memb = state->chptr->members; memb; memb = memb->next_member) {
+        if (memb->status & MODE_CHANOP)
+          memb->oplevel = MAXOPLEVEL;
+      }
     }
   }
 }
@@ -2812,7 +2819,7 @@ mode_parse_ban(struct ParseState *state, int *flag_p)
   newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
       | (*flag_p == MODE_BAN ? 0 : BAN_EXCEPTION);
   set_ban_mask(newban, collapse(pretty_mask(t_str)));
-  ircd_strncpy(newban->who, cli_name(state->sptr), HOSTLEN);
+  ircd_strncpy(newban->who, IsUser(state->sptr) ? cli_name(state->sptr) : "*", NICKLEN);
   newban->when = TStime();
   apply_ban(&state->chptr->banlist, newban, 0);
 }
@@ -3403,10 +3410,11 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
     /* send notification to all servers */
     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
     {
-      if (flags & CHFL_CHANOP)
+      if (flags & CHFL_CHANOP) {
+        assert(oplevel == 0 || oplevel == 1);
         sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
                               "%u:%H %Tu", oplevel, chan, chan->creationtime);
-      else
+      else
         sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
                               "%H %Tu", chan, chan->creationtime);
     }
@@ -3417,7 +3425,7 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
 
       /* send an op, too, if needed */
       if (flags & CHFL_CHANOP && (oplevel < MAXOPLEVEL || !MyUser(jbuf->jb_source)))
-       sendcmdto_channel_butserv_butone((chan->mode.apass[0] ? &me : jbuf->jb_source),
+       sendcmdto_channel_butserv_butone((chan->mode.apass[0] ? &his : jbuf->jb_source),
                                          CMD_MODE, chan, NULL, 0, "%H +o %C",
                                         chan, jbuf->jb_source);
     } else if (MyUser(jbuf->jb_source))
@@ -3524,7 +3532,7 @@ void CheckDelayedJoins(struct Channel *chan)
     if (!memb2) {
       /* clear +d */
       chan->mode.mode &= ~MODE_WASDELJOINS;
-      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
+      sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan, NULL, 0,
                                        "%H -d", chan);
     }
   }