continue;
/* Compare host portion of ban. */
hostmask = banlist->banstr + banlist->nu_len + 1;
- if (((banlist->flags & BAN_IPMASK)
- ? !ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits)
- : match(hostmask, iphost))
+ if (!((banlist->flags & BAN_IPMASK)
+ && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
&& match(hostmask, cli_user(cptr)->host)
- && !(sr && match(hostmask, sr) == 0))
- continue;
+ && !(sr && !match(hostmask, sr)))
+ continue;
/* If an exception matches, no ban can match. */
if (banlist->flags & BAN_EXCEPTION)
return NULL;
member->user = who;
member->channel = chptr;
member->status = flags;
- member->oplevel = oplevel;
+ SetOpLevel(member, oplevel);
member->next_member = chptr->members;
if (member->next_member)
send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
}
-/** Check a key against a keyring.
- * We are now treating the key part of /join channellist key as a key
- * ring; that is, we try one key against the actual channel key, and if that
- * doesn't work, we try the next one, and so on. -Kev -Texaco
- * Returns: 0 on match, 1 otherwise
- * This version contributed by SeKs \<intru@info.polymtl.ca\>
- *
- * @param key Key to check
- * @param keyring Comma separated list of keys
- *
- * @returns True if the key was found and matches, false otherwise.
- */
-static int compall(char *key, char *keyring)
-{
- char *p1;
-
-top:
- p1 = key; /* point to the key... */
- while (*p1 && *p1 == *keyring)
- { /* step through the key and ring until they
- don't match... */
- p1++;
- keyring++;
- }
-
- if (!*p1 && (!*keyring || *keyring == ','))
- /* ok, if we're at the end of the and also at the end of one of the keys
- in the keyring, we have a match */
- return 0;
-
- if (!*keyring) /* if we're at the end of the key ring, there
- weren't any matches, so we return 1 */
- return 1;
-
- /* Not at the end of the key ring, so step
- through to the next key in the ring: */
- while (*keyring && *(keyring++) != ',');
-
- goto top; /* and check it against the key */
-}
-
-/** Returns if a user can join a channel with a specific key.
- *
- * @param sptr The client trying to join
- * @param chptr The channel to join
- * @param key The key to use
- *
- * @returns any error that occurred bit-wise OR'd with MAGIC_OPER_OVERRIDE
- * if the oper used the magic key, 0 if no error occurred.
- */
-int can_join(struct Client *sptr, struct Channel *chptr, char *key)
-{
- int overrideJoin = 0;
-
- /*
- * Now a banned user CAN join if invited -- Nemesi
- * Now a user CAN escape channel limit if invited -- bfriendly
- * Now a user CAN escape anything if invited -- Isomer
- */
-
- if (IsInvited(sptr, chptr))
- return 0;
-
- /* An oper can force a join on a local channel using "OVERRIDE" as the key.
- a HACK(4) notice will be sent if he would not have been supposed
- to join normally. */
- if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
- !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
- compall("OVERRIDE",key) == 0)
- overrideJoin = MAGIC_OPER_OVERRIDE;
-
- if (chptr->mode.mode & MODE_INVITEONLY)
- return overrideJoin + ERR_INVITEONLYCHAN;
-
- if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
- return overrideJoin + ERR_CHANNELISFULL;
-
- if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
- return overrideJoin + ERR_NEEDREGGEDNICK;
-
- if (find_ban(sptr, chptr->banlist))
- return overrideJoin + ERR_BANNEDFROMCHAN;
-
- /*
- * now using compall (above) to test against a whole key ring -Kev
- */
- if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
- return overrideJoin + ERR_BADCHANNELKEY;
-
- if (overrideJoin)
- return ERR_DONTCHEAT;
-
- return 0;
-}
-
/** Remove bells and commas from channel name
*
* @param cn Channel name to clean, modified in place.
if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
- if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
+ if ((totalbuflen - IRCD_MAX(9, tmp)) <= 0) /* don't overflow buffer */
MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
else {
bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
- totalbuflen -= IRCD_MAX(5, tmp) + 1;
+ totalbuflen -= IRCD_MAX(9, tmp) + 1;
}
} else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
tmp = strlen(MB_STRING(mbuf, i));
strptr_i = &remstr_i;
}
- /* deal with modes that take clients */
- if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
+ /* if we're changing oplevels 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)
+ *strptr_i += ircd_snprintf(0, strptr + *strptr_i, BUFSIZE - *strptr_i,
+ " %s%s:%d",
+ NumNick(MB_CLIENT(mbuf, i)),
+ MB_OPLEVEL(mbuf, i));
+
+ /* deal with other modes that take clients */
+ else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
/* deal with modes that take strings */
* @param mbuf The modebuf to append the mode to.
* @param mode The mode to append.
* @param client The client argument to append.
+ * @param oplevel The oplevel the user had or will have
*/
void
modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
- struct Client *client)
+ struct Client *client, int oplevel)
{
assert(0 != mbuf);
assert(0 != (mode & (MODE_ADD | MODE_DEL)));
MB_TYPE(mbuf, mbuf->mb_count) = mode;
MB_CLIENT(mbuf, mbuf->mb_count) = client;
+ MB_OPLEVEL(mbuf, mbuf->mb_count) = oplevel;
/* when we've reached the maximal count, flush the buffer */
if (++mbuf->mb_count >=
struct Ban banlist[MAXPARA];
struct {
unsigned int flag;
+ unsigned short oplevel;
struct Client *client;
} cli_change[MAXPARA];
};
}
}
+/** Helper function to clean key-like parameters. */
+static void
+clean_key(char *s)
+{
+ int t_len = KEYLEN;
+
+ while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
+ s++;
+ *s = '\0';
+}
+
/*
* Helper function to convert keys
*/
static void
mode_parse_key(struct ParseState *state, int *flag_p)
{
- char *t_str, *s;
- int t_len;
+ char *t_str;
if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
return;
return;
state->done |= DONE_KEY;
- t_len = KEYLEN;
-
/* clean up the key string */
- s = t_str;
- while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
- s++;
- *s = '\0';
-
- if (!*t_str) { /* warn if empty */
+ clean_key(t_str);
+ if (!*t_str || *t_str == ':') { /* warn if empty */
if (MyUser(state->sptr))
need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
"MODE -k");
modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
if (state->flags & MODE_PARSE_SET) {
- if (state->dir == MODE_ADD) /* set the new key */
- ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
- else /* remove the old key */
+ if (state->dir == MODE_DEL) /* remove the old key */
*state->chptr->mode.key = '\0';
+ else if (!state->chptr->mode.key[0]
+ || ircd_strcmp(t_str, state->chptr->mode.key) < 0)
+ ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
}
}
static void
mode_parse_upass(struct ParseState *state, int *flag_p)
{
- char *t_str, *s;
- int t_len;
+ char *t_str;
if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
return;
if (*state->chptr->mode.apass) {
send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
state->chptr->chname);
- } else if (TStime() - state->chptr->creationtime >= 171000) {
- send_reply(state->sptr, ERR_NOMANAGER_LONG, state->chptr->chname);
} else {
- send_reply(state->sptr, ERR_NOMANAGER_SHORT, state->chptr->chname);
+ send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname);
}
return;
}
return;
state->done |= DONE_UPASS;
- t_len = PASSLEN + 1;
-
/* clean up the upass string */
- s = t_str;
- while (*++s > ' ' && *s != ':' && --t_len)
- ;
- *s = '\0';
-
- if (!*t_str) { /* warn if empty */
+ clean_key(t_str);
+ if (!*t_str || *t_str == ':') { /* warn if empty */
if (MyUser(state->sptr))
need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
"MODE -U");
modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
if (state->flags & MODE_PARSE_SET) {
- if (state->dir == MODE_ADD) /* set the new upass */
- ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
- else /* remove the old upass */
+ if (state->dir == MODE_DEL) /* remove the old upass */
*state->chptr->mode.upass = '\0';
+ else if (state->chptr->mode.upass[0] == '\0'
+ || ircd_strcmp(t_str, state->chptr->mode.upass) < 0)
+ ircd_strncpy(state->chptr->mode.upass, t_str, KEYLEN);
}
}
mode_parse_apass(struct ParseState *state, int *flag_p)
{
struct Membership *memb;
- char *t_str, *s;
- int t_len;
+ char *t_str;
if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
return;
}
/* Don't allow to change the Apass if the channel is older than 48 hours. */
- if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
+ if (MyUser(state->sptr)
+ && TStime() - state->chptr->creationtime >= 172800
+ && !IsAnOper(state->sptr)) {
send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
return;
}
if (*state->chptr->mode.apass) {
send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
state->chptr->chname);
- } else if (TStime() - state->chptr->creationtime >= 171000) {
- send_reply(state->sptr, ERR_NOMANAGER_LONG, state->chptr->chname);
} else {
- send_reply(state->sptr, ERR_NOMANAGER_SHORT, state->chptr->chname);
+ send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname);
}
return;
}
return;
state->done |= DONE_APASS;
- t_len = PASSLEN + 1;
-
/* clean up the apass string */
- s = t_str;
- while (*++s > ' ' && *s != ':' && --t_len)
- ;
- *s = '\0';
-
- if (!*t_str) { /* warn if empty */
+ clean_key(t_str);
+ if (!*t_str || *t_str == ':') { /* warn if empty */
if (MyUser(state->sptr))
need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
"MODE -A");
if (state->flags & MODE_PARSE_SET) {
if (state->dir == MODE_ADD) { /* set the new apass */
+ /* Only accept the new apass if there is no current apass
+ * (e.g. when a user sets it) or the new one is "less" than the
+ * old (for resolving conflicts during burst).
+ */
+ if (state->chptr->mode.apass[0] == '\0'
+ || ircd_strcmp(t_str, state->chptr->mode.apass) < 0)
+ ircd_strncpy(state->chptr->mode.apass, t_str, KEYLEN);
/* Make it VERY clear to the user that this is a one-time password */
- ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
if (MyUser(state->sptr)) {
send_reply(state->sptr, RPL_APASSWARN_SET, state->chptr->mode.apass);
send_reply(state->sptr, RPL_APASSWARN_SECRET, state->chptr->chname,
/* Revert everyone to MAXOPLEVEL. */
for (memb = state->chptr->members; memb; memb = memb->next_member) {
if (memb->status & MODE_CHANOP)
- memb->oplevel = MAXOPLEVEL;
+ SetOpLevel(memb, MAXOPLEVEL);
}
}
}
{
char *t_str;
struct Client *acptr;
+ struct Membership *member;
+ int oplevel = MAXOPLEVEL + 1;
int i;
if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
if (MyUser(state->sptr)) /* find client we're manipulating */
acptr = find_chasing(state->sptr, t_str, NULL);
- else
+ else {
+ if (t_str[5] == ':') {
+ t_str[5] = '\0';
+ oplevel = atoi(t_str + 6);
+ }
acptr = findNUser(t_str);
+ }
if (!acptr)
return; /* find_chasing() already reported an error to the user */
state->cli_change[i].flag & flag_p[0]))
break; /* found a slot */
+ /* If we are going to bounce this deop, mark the correct oplevel. */
+ if (state->flags & MODE_PARSE_BOUNCE
+ && state->dir == MODE_DEL
+ && flag_p[0] == MODE_CHANOP
+ && (member = find_member_link(state->chptr, acptr)))
+ oplevel = OpLevel(member);
+
/* Store what we're doing to them */
state->cli_change[i].flag = state->dir | flag_p[0];
+ state->cli_change[i].oplevel = oplevel;
state->cli_change[i].client = acptr;
}
"deop", equal ? "the same" : "a higher");
continue;
}
- }
+ }
}
/* set op-level of member being opped */
if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
(MODE_ADD | MODE_CHANOP)) {
- /* If being opped by an outsider, get oplevel 0 for an apass
- * channel, else MAXOPLEVEL.
+ /* If a valid oplevel was specified, use it.
+ * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
* Otherwise, if not an apass channel, or state->member has
* MAXOPLEVEL, get oplevel MAXOPLEVEL.
* Otherwise, get state->member's oplevel+1.
*/
- if (!state->member)
- SetOpLevel(member, state->chptr->mode.apass[0] ? 0 : MAXOPLEVEL);
+ if (state->cli_change[i].oplevel <= MAXOPLEVEL)
+ SetOpLevel(member, state->cli_change[i].oplevel);
+ else if (!state->member)
+ SetOpLevel(member, MAXOPLEVEL);
else if (!state->chptr->mode.apass[0] || OpLevel(state->member) == MAXOPLEVEL)
SetOpLevel(member, MAXOPLEVEL);
else
/* accumulate the change */
modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
- state->cli_change[i].client);
+ state->cli_change[i].client,
+ state->cli_change[i].oplevel);
} /* for (i = 0; state->cli_change[i].flags; i++) */
}
assert(0 != jbuf);
if (!chan) {
- if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
- sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
-
+ sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
return;
}