Avoid unwanted races for mode handling during burst processing.
authorMichael Poole <mdpoole@troilus.org>
Sat, 18 Mar 2006 15:52:58 +0000 (15:52 +0000)
committerMichael Poole <mdpoole@troilus.org>
Sat, 18 Mar 2006 15:52:58 +0000 (15:52 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1629 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
ircd/channel.c
ircd/m_create.c
ircd/m_mode.c

index 277698ba2170aa4b0d1309cb2a878d06bb823472..fbcc65089c2f9553626a5cbb082ba05360e28334 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2006-06-18  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/channel.c (modebuf_flush_int): Fix typo about changing
+       oplevels.  Send correct channel TS for modes to other servers.
+       (mode_parse): Accept timestamps on modes from users on other
+       servers.  If the received timestamp is too large, handle that.
+
+       * ircd/m_create.c (ms_create): Mention the CREATE-during-burst
+       case and handle it.
+
+       * ircd/m_mode.c (ms_mode): Put back HACK(3) when oplevels are off.
+
 2006-03-14  Wouter Coekarts <wouter@coekaerts.be>
 
        * ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field.
 2006-03-14  Wouter Coekarts <wouter@coekaerts.be>
 
        * ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field.
index 99e5182e6df59427cf825313573f17bb60915c23..e79dba7641d6d17486354574b903783d5e3c7c9c 100644 (file)
@@ -1805,7 +1805,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
        strptr_i = &remstr_i;
       }
 
        strptr_i = &remstr_i;
       }
 
-      /* if we're changing oplevels we know the oplevel, pass it on */
+      /* if we're changing oplevels and we know the oplevel, pass it on */
       if (mbuf->mb_channel->mode.apass[0]
           && (MB_TYPE(mbuf, i) & MODE_CHANOP)
           && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
       if (mbuf->mb_channel->mode.apass[0]
           && (MB_TYPE(mbuf, i) & MODE_CHANOP)
           && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
@@ -1849,9 +1849,9 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
                            addbuf, remstr, addstr);
     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
       /*
                            addbuf, remstr, addstr);
     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
       /*
-       * If HACK2 was set, we're bouncing; we send the MODE back to the
-       * connection we got it from with the senses reversed and a TS of 0;
-       * origin is us
+       * If HACK2 was set, we're bouncing; we send the MODE back to
+       * the connection we got it from with the senses reversed and
+       * the proper TS; origin is us
        */
       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
                    mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
        */
       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
                    mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
@@ -1859,21 +1859,14 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
                    mbuf->mb_channel->creationtime);
     } else {
       /*
                    mbuf->mb_channel->creationtime);
     } else {
       /*
-       * We're propagating a normal MODE command to the rest of the network;
-       * we send the actual channel TS unless this is a HACK3 or a HACK4
+       * We're propagating a normal (or HACK3 or HACK4) MODE command
+       * to the rest of the network.  We send the actual channel TS.
        */
        */
-      if (IsServer(mbuf->mb_source) || IsMe(mbuf->mb_source))
-       sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
-                             "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
-                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
-                             addbuf, remstr, addstr,
-                             (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
-                             mbuf->mb_channel->creationtime);
-      else
-       sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
-                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
-                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
-                             addbuf, remstr, addstr);
+      sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
+                            "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
+                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+                            addbuf, remstr, addstr,
+                            mbuf->mb_channel->creationtime);
     }
   }
 
     }
   }
 
@@ -3272,7 +3265,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
       state.parc--;
 
       /* is it a TS? */
       state.parc--;
 
       /* is it a TS? */
-      if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
+      if (IsServer(state.cptr) && !state.parc && IsDigit(*modestr)) {
        time_t recv_ts;
 
        if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
        time_t recv_ts;
 
        if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
@@ -3282,6 +3275,35 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
 
        if (recv_ts && recv_ts < state.chptr->creationtime)
          state.chptr->creationtime = recv_ts; /* respect earlier TS */
 
        if (recv_ts && recv_ts < state.chptr->creationtime)
          state.chptr->creationtime = recv_ts; /* respect earlier TS */
+        else if (recv_ts > state.chptr->creationtime) {
+          struct Client *sserv;
+
+          /* Check whether the originating server has fully processed
+           * the burst to it. */
+          sserv = state.cptr;
+          if (!IsServer(sserv))
+              sserv = cli_user(sserv)->server;
+          if (IsBurstOrBurstAck(sserv)) {
+            /* This is a legal but unusual case; the source server
+             * probably just has not processed the BURST for this
+             * channel.  It SHOULD wipe out all its modes soon, so
+             * silently ignore the mode change rather than send a
+             * bounce that could desync modes from our side (that
+             * have already been sent).
+             */
+            state.mbuf->mb_add = 0;
+            state.mbuf->mb_rem = 0;
+            state.mbuf->mb_count = 0;
+            return state.args_used;
+          } else {
+            /* Server is desynced; bounce the mode and deop the source
+             * to fix it. */
+            state.mbuf->mb_dest &= ~MODEBUF_DEST_CHANNEL;
+            state.mbuf->mb_dest |= MODEBUF_DEST_BOUNCE | MODEBUF_DEST_HACK2;
+            if (!IsServer(state.cptr))
+              state.mbuf->mb_dest |= MODEBUF_DEST_DEOP;
+          }
+        }
 
        break; /* break out of while loop */
       } else if (state.flags & MODE_PARSE_STRICT ||
 
        break; /* break out of while loop */
       } else if (state.flags & MODE_PARSE_STRICT ||
index e27e56649fda939dd8fa0333a8b3d2ee49fa43f1..db21be8d00de8f4b07b33ee2a28dcd88f773d9ca 100644 (file)
@@ -172,7 +172,7 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
              the fact that it was a zannel. The influence of this on a network
              that is completely 2.10.12.03 or higher is neglectable: Normally
              a server only sends a CREATE after first sending a DESTRUCT. Thus,
              the fact that it was a zannel. The influence of this on a network
              that is completely 2.10.12.03 or higher is neglectable: Normally
              a server only sends a CREATE after first sending a DESTRUCT. Thus,
-             by receiving a CREATE for a zannel one of two things happened:
+             by receiving a CREATE for a zannel one of three things happened:
              1. The DESTRUCT was sent during a net.break; this could mean that
                 our zannel is at the verge of expiring too, it should have been
                 destructed. It is correct to copy the newer TS now, all modes
              1. The DESTRUCT was sent during a net.break; this could mean that
                 our zannel is at the verge of expiring too, it should have been
                 destructed. It is correct to copy the newer TS now, all modes
@@ -185,28 +185,45 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 already left within the time span of a message propagation.
                 The channel will therefore be less than 48 hours old and no
                 'protection' is necessary.
                 already left within the time span of a message propagation.
                 The channel will therefore be less than 48 hours old and no
                 'protection' is necessary.
+              3. The source server sent the CREATE while linking,
+                 before it got the BURST for our zannel.  If this
+                 happens, we should reset the channel back to the old
+                 timestamp.  This can be distinguished from case #1 by
+                 checking IsBurstOrBurstAck(cli_user(sptr)->server).
            */
           !(chptr->users == 0 && !chptr->mode.apass[0]))) {
            */
           !(chptr->users == 0 && !chptr->mode.apass[0]))) {
-       modebuf_init(&mbuf, sptr, cptr, chptr,
-                    (MODEBUF_DEST_SERVER |  /* Send mode to server */
-                     MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
-                     MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
-
-       modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
-
-       modebuf_flush(&mbuf);
-
-       badop = 1;
+        if (!IsBurstOrBurstAck(cli_user(sptr)->server)) {
+          modebuf_init(&mbuf, sptr, cptr, chptr,
+                       (MODEBUF_DEST_SERVER |  /* Send mode to server */
+                        MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
+                        MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
+
+          modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
+
+          modebuf_flush(&mbuf);
+
+          badop = 1;
+        } else if (chanTS > chptr->creationtime + 4) {
+          /* If their handling of the BURST will lead to deopping the
+           * user, have the user join without getting ops (if the
+           * server's handling of the BURST keeps their ops, the channel
+           * will use our timestamp).
+           */
+          badop = 1;
+        }
+
+        if (badop)
+          joinbuf_join(&join, chptr, 0);
       }
     }
     else /* Channel doesn't exist: create it */
       chptr = get_channel(sptr, name, CGT_CREATE);
 
       }
     }
     else /* Channel doesn't exist: create it */
       chptr = get_channel(sptr, name, CGT_CREATE);
 
-    if (!badop) /* Set/correct TS */
+    if (!badop) {
+      /* Set (or correct) our copy of the TS */
       chptr->creationtime = chanTS;
       chptr->creationtime = chanTS;
-
-    joinbuf_join(badop ? &join : &create, chptr,
-                (badop ? 0 : CHFL_CHANOP));
+      joinbuf_join(&create, chptr, CHFL_CHANOP);
+    }
   }
 
   joinbuf_flush(&join); /* flush out the joins and creates */
   }
 
   joinbuf_flush(&join); /* flush out the joins and creates */
index c994569e878c5d7897c0dbb16bfc3f1ddf3fa71c..ca366ccd65bf243b430c84e6174f1016fac6af48 100644 (file)
@@ -86,6 +86,7 @@
 #include "client.h"
 #include "hash.h"
 #include "ircd.h"
 #include "client.h"
 #include "hash.h"
 #include "ircd.h"
+#include "ircd_features.h"
 #include "ircd_log.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
 #include "ircd_log.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
@@ -177,10 +178,15 @@ ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                   (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
                    MODEBUF_DEST_SERVER  | /* Send mode to servers */
                    MODEBUF_DEST_HACK4));  /* Send a HACK(4) message */
                   (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
                    MODEBUF_DEST_SERVER  | /* Send mode to servers */
                    MODEBUF_DEST_HACK4));  /* Send a HACK(4) message */
+    else if (!feature_bool(FEAT_OPLEVELS))
+      modebuf_init(&mbuf, sptr, cptr, chptr,
+                  (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
+                   MODEBUF_DEST_SERVER  | /* Send mode to servers */
+                   MODEBUF_DEST_HACK3));  /* Send a HACK(3) message */
     else
       /* Servers need to be able to op people who join using the Apass
     else
       /* Servers need to be able to op people who join using the Apass
-       * or upass, as well as people joining a zannel, therefore we no
-       * longer generate HACK3. */
+       * or upass, as well as people joining a zannel, therefore we do
+       * not generate HACK3 when oplevels are on. */
       modebuf_init(&mbuf, sptr, cptr, chptr,
                   (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
                    MODEBUF_DEST_SERVER));   /* Send mode to servers */
       modebuf_init(&mbuf, sptr, cptr, chptr,
                   (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
                    MODEBUF_DEST_SERVER));   /* Send mode to servers */