Fix oplevel handling in bursts, fixing SF bugs #2596869 and #2597518.
[ircu2.10.12-pk.git] / ircd / m_burst.c
index 482ed658d8865f336c26fd2e90365073bf5b934a..f1e4429e32d0d0d9d273478240374f7abb6006f5 100644 (file)
@@ -115,6 +115,8 @@ netride_modes(int parc, char **parv, const char *curr_key)
   assert(modes && modes[0] == '+');
   while (*modes) {
     switch (*modes++) {
+    case '-':
+      return -1;
     case 'i':
       result |= MODE_INVITEONLY;
       break;
@@ -282,7 +284,13 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       if (parv[param][0] != '+')
         continue;
       check_modes = netride_modes(parc - param, parv + param, chptr->mode.key);
-      if (check_modes)
+      if (check_modes < 0)
+      {
+        if (chptr->users == 0)
+          sub1_from_channel(chptr);
+        return protocol_violation(sptr, "Invalid mode string in BURST");
+      }
+      else if (check_modes)
       {
         /* Clear any outstanding rogue invites */
         mode_invite_clear(chptr);
@@ -469,6 +477,14 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                    current_mode_needs_reset = 0;
                  }
                  current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
+                  /*
+                   * Older servers may send XXYYY:ov, in which case we
+                   * do not want to use the code for 'v' below.
+                   */
+                  if (ptr[1] == 'v') {
+                    current_mode |= CHFL_VOICE;
+                    ptr++;
+                  }
                }
                else if (*ptr == 'v') { /* has voice status */
                  if (current_mode_needs_reset) {
@@ -491,10 +507,18 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                  do {
                    level_increment = 10 * level_increment + *ptr++ - '0';
                  } while (IsDigit(*ptr));
+                 --ptr;
                  oplevel += level_increment;
+                  if (oplevel > MAXOPLEVEL) {
+                    protocol_violation(sptr, "Invalid cumulative oplevel %u during burst", oplevel);
+                    oplevel = MAXOPLEVEL;
+                    break;
+                  }
                }
-               else /* I don't recognize that flag */
+               else { /* I don't recognize that flag */
+                 protocol_violation(sptr, "Invalid flag '%c' in nick part of burst", *ptr);
                  break; /* so stop processing */
+               }
              }
            }
          }
@@ -518,7 +542,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
              nickstr[nickpos++] = 'v';
            if (current_mode & CHFL_CHANOP)
             {
-              if (chptr->mode.apass[0])
+              if (oplevel != MAXOPLEVEL)
                nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel);
               else
                 nickstr[nickpos++] = 'o';
@@ -529,7 +553,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
             last_oplevel = oplevel;
          }
 
-         if (IsBurst(sptr) || !(member = find_member_link(chptr, acptr)))
+         if (!(member = find_member_link(chptr, acptr)))
          {
            add_user_to_channel(chptr, acptr, current_mode, oplevel);
             if (!(current_mode & CHFL_DELAYED))