X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fm_burst.c;h=f1e4429e32d0d0d9d273478240374f7abb6006f5;hb=837bdbbb0e7e270cfd1d40a7ad730beaffa6c000;hp=01be1a6a6c9dc6cf3c524ccb77b2e916e43ad1f5;hpb=9321a253e348609094142de768a07c9f9f0b6ba3;p=ircu2.10.12-pk.git diff --git a/ircd/m_burst.c b/ircd/m_burst.c index 01be1a6..f1e4429 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -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; @@ -219,6 +221,57 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) timestamp = atoi(parv[2]); + if (chptr->creationtime) /* 0 for new (empty) channels, + i.e. when this server just restarted. */ + { + if (parc == 3) /* Zannel BURST? */ + { + /* An empty channel without +A set, will cause a BURST message + with exactly 3 parameters (because all modes have been reset). + If the timestamp on such channels is only a few seconds older + from our own, then we ignore this burst: we do not deop our + own side. + Likewise, we expect the other (empty) side to copy our timestamp + from our own BURST message, even though it is slightly larger. + + The reason for this is to allow people to join an empty + non-A channel (a zannel) during a net.split, and not be + deopped when the net reconnects (with another zannel). When + someone joins a split zannel, their side increments the TS by one. + If they cycle a few times then we still don't have a reason to + deop them. Theoretically I see no reason not to accept ANY timestamp, + but to be sure, we only accept timestamps that are just a few + seconds off (one second for each time they cycled the channel). */ + + /* Don't even deop users who cycled four times during the net.break. */ + if (timestamp < chptr->creationtime && + chptr->creationtime <= timestamp + 4 && + chptr->users != 0) /* Only do this when WE have users, so that + if we do this the BURST that we sent has + parc > 3 and the other side will use the + test below: */ + timestamp = chptr->creationtime; /* Do not deop our side. */ + } + else if (chptr->creationtime < timestamp && + timestamp <= chptr->creationtime + 4 && + chptr->users == 0) + { + /* If one side of the net.junction does the above + timestamp = chptr->creationtime, then the other + side must do this: */ + chptr->creationtime = timestamp; /* Use the same TS on both sides. */ + } + /* In more complex cases, we might still end up with a + creationtime desync of a few seconds, but that should + be synced automatically rather quickly (every JOIN + caries a timestamp and will sync it; modes by users do + not carry timestamps and are accepted regardless). + Only when nobody joins the channel on the side with + the oldest timestamp before a new net.break occurs + precisely inbetween the desync, an unexpected bounce + might happen on reconnect. */ + } + if (!chptr->creationtime || chptr->creationtime > timestamp) { /* * Kick local members if channel is +i or +k and our TS was larger @@ -231,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); @@ -249,7 +308,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) && (!(check_modes & MODE_REGONLY) || IsAccount(member->user))) continue; sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user); - sendcmdto_channel_butserv_butone(&me, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user); + sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user); make_zombie(member, member->user, &me, &me, chptr); } } @@ -306,7 +365,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) *chptr->topic = '\0'; *chptr->topic_nick = '\0'; chptr->topic_time = 0; - sendcmdto_channel_butserv_butone(&me, CMD_TOPIC, chptr, NULL, 0, + sendcmdto_channel_butserv_butone(&his, CMD_TOPIC, chptr, NULL, 0, "%H :%s", chptr, chptr->topic); } } else if (chptr->creationtime == timestamp) { @@ -371,11 +430,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) newban = make_ban(ban); /* create new ban */ strcpy(newban->who, "*"); newban->when = TStime(); - - newban->flags = BAN_BURSTED; /* set flags */ - if ((ptr = strrchr(ban, '@')) && check_if_ipmask(ptr + 1)) - newban->flags |= BAN_IPMASK; - + newban->flags |= BAN_BURSTED; newban->next = 0; if (lp) lp->next = newban; /* link it in */ @@ -422,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) { @@ -431,7 +494,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_VOICE; oplevel = -1; /* subsequent digits are an absolute op-level value. */ } - else if (isdigit(*ptr)) { + else if (IsDigit(*ptr)) { int level_increment = 0; if (oplevel == -1) { /* op-level is absolute value? */ if (current_mode_needs_reset) { @@ -443,11 +506,19 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP; do { level_increment = 10 * level_increment + *ptr++ - '0'; - } while(isdigit(*ptr)); + } 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 */ + } } } } @@ -471,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'; @@ -482,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)) @@ -498,7 +569,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) member->status |= CHFL_BURST_ALREADY_VOICED; /* Synchronize with the burst. */ member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE)); - member->oplevel = oplevel; + SetOpLevel(member, oplevel); } } } @@ -527,14 +598,14 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) for (member = chptr->members; member; member = member->next_member) { if (member->status & CHFL_BURST_JOINED) { /* joined during burst */ if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED)) - modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user); + modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member)); if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED)) - modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user); + modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member)); } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */ if (member->status & CHFL_CHANOP) - modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user); + modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member)); if (member->status & CHFL_VOICE) - modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user); + modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member)); member->status = (member->status & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE)) | CHFL_DEOPPED;