X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fm_join.c;h=e0049667ca8a1eb691f603312e453ad0bb8688b6;hb=refs%2Fheads%2Fupstream;hp=d274e35db13d6c5f2a2656f019bf850c8658ceff;hpb=b0cb97e9754a805ea2109852ba88ebc7e98d7fe2;p=ircu2.10.12-pk.git diff --git a/ircd/m_join.c b/ircd/m_join.c index d274e35..e004966 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -158,7 +158,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (!(chptr = FindChannel(name))) { if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) - || strlen(name) >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { + || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } @@ -167,7 +167,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) continue; /* Try to add the new channel as a recent target for the user. */ - if (check_target_limit(sptr, chptr, chptr->chname, 1)) { + if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); continue; @@ -182,15 +182,17 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) int flags = CHFL_DEOPPED; int err = 0; - /* Check target change limits. */ - /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; - else if (IsInvited(sptr, chptr)) { + else if (chptr->users == 0 && !chptr->mode.apass[0]) { + /* Joining a zombie channel (zannel): give ops and increment TS. */ + flags = CHFL_CHANOP; + chptr->creationtime++; + } else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (chptr->mode.mode & MODE_INVITEONLY) err = ERR_INVITEONLYCHAN; @@ -217,7 +219,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { - send_reply(sptr, err, chptr->chname); + send_reply(sptr, ERR_DONTCHEAT, chptr->chname); continue; } break; @@ -237,11 +239,34 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) /* Is there some reason the user may not join? */ if (err) { - send_reply(sptr, err, chptr->chname); + switch(err) { + case ERR_NEEDREGGEDNICK: + send_reply(sptr, + ERR_NEEDREGGEDNICK, + chptr->chname, + feature_str(FEAT_URLREG)); + break; + default: + send_reply(sptr, err, chptr->chname); + break; + } continue; } joinbuf_join(&join, chptr, flags); + if (flags & CHFL_CHANOP) { + struct ModeBuf mbuf; + /* Always let the server op him: this is needed on a net with older servers + because they 'destruct' channels immediately when they become empty without + sending out a DESTRUCT message. As a result, they would always bounce a mode + (as HACK(2)) when the user ops himself. + (There is also no particularly good reason to have the user op himself.) + */ + modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); + modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, + chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); + modebuf_flush(&mbuf); + } } del_invite(sptr, chptr); @@ -302,18 +327,7 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) for (name = ircd_strtok(&p, chanlist, ","); name; name = ircd_strtok(&p, 0, ",")) { - if (name[0] == '0' && name[1] == ':') - { - flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; - name += 2; - } - else if (name[0] == '1' && name[1] == ':') - { - flags = CHFL_CHANOP; - name += 2; - } - else - flags = CHFL_DEOPPED; + flags = CHFL_DEOPPED; if (IsLocalChannel(name) || !IsChannelName(name)) { @@ -332,8 +346,7 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) } flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0; - /* when the network is 2.10.11+ then remove MAGIC_REMOTE_JOIN_TS */ - chptr->creationtime = creation ? creation : MAGIC_REMOTE_JOIN_TS; + chptr->creationtime = creation; } else { /* We have a valid channel? */ if ((member = find_member_link(chptr, sptr))) @@ -349,9 +362,70 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) else flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0; /* Always copy the timestamp when it is older, that is the only way to - ensure network-wide synchronization of creation times. */ - if (creation && creation < chptr->creationtime) + ensure network-wide synchronization of creation times. + We now also copy a creation time that only 1 second younger... + this is needed because the timestamp must be incremented + by one when someone joins an existing, but empty, channel. + However, this is only necessary when the channel is still + empty (also here) and when this channel doesn't have +A set. + + To prevent this from allowing net-rides on the channel, we + clear all modes from the channel. + + (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only + user in the channel; c1 parts and rejoins, gaining ops. + Before s2 sees c1's part, c2 joins the channel and parts + immediately. s1 sees c1 part, c1 create, c2 join, c2 part; + c2's join resets the timestamp. s2 sees c2 join, c2 part, c1 + part, c1 create; but since s2 sees the channel as a zannel or + non-existent, it does not bounce the create with the newer + timestamp.) + */ + if (creation && (creation < chptr->creationtime || + (!chptr->mode.apass[0] && chptr->users == 0))) { + struct Membership *member; + struct ModeBuf mbuf; + chptr->creationtime = creation; + /* Wipe out the current modes on the channel. */ + modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3); + + modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode); + chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS; + + if (chptr->mode.limit) { + modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); + chptr->mode.limit = 0; + } + + if (chptr->mode.key[0]) { + modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); + chptr->mode.key[0] = '\0'; + } + + if (chptr->mode.upass[0]) { + modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0); + chptr->mode.upass[0] = '\0'; + } + + if (chptr->mode.apass[0]) { + modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0); + chptr->mode.apass[0] = '\0'; + } + + for (member = chptr->members; member; member = member->next_member) + { + if (IsChanOp(member)) { + modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member)); + member->status &= ~CHFL_CHANOP; + } + if (HasVoice(member)) { + modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member)); + member->status &= ~CHFL_VOICE; + } + } + modebuf_flush(&mbuf); + } } joinbuf_join(&join, chptr, flags);