X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/8e3b2b85c7221f2f9f1ca6d5e48880d521d2a1a3..ab72b3e800c5848fa2376dc982c49b0ffa6079ed:/src/chmode.c diff --git a/src/chmode.c b/src/chmode.c index 64a0857..6ee15eb 100644 --- a/src/chmode.c +++ b/src/chmode.c @@ -22,7 +22,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * - * $Id: chmode.c 3580 2007-11-07 23:45:14Z jilles $ */ #include "stdinc.h" @@ -42,7 +41,8 @@ #include "s_newconf.h" #include "logger.h" #include "chmode.h" -#include "irc_dictionary.h"; +#include "irc_dictionary.h" + /* bitmasks for error returns, so we send once per call */ #define SM_ERR_NOTS 0x00000001 /* No TS on channel */ @@ -57,6 +57,7 @@ #define SM_ERR_NOPRIVS 0x00000400 #define SM_ERR_RPL_Q 0x00000800 #define SM_ERR_RPL_F 0x00001000 +#define SM_ERR_MLOCK 0x00002000 #define MAXMODES_SIMPLE 46 /* a-zA-Z except bqeIov */ @@ -69,17 +70,17 @@ static int no_override_deop; char cflagsbuf[256]; char cflagsmyinfo[256]; +char cflagsparaminfo[256]; int chmode_flags[256]; /* OPTIMIZE ME! -- dwr */ void -construct_noparam_modes(void) +construct_cflags_strings(void) { int i; char *ptr = cflagsbuf; char *ptr2 = cflagsmyinfo; - static int prev_chmode_flags[256]; *ptr = '\0'; *ptr2 = '\0'; @@ -91,7 +92,7 @@ construct_noparam_modes(void) !(chmode_table[i].set_func == chm_throttle) && !(chmode_table[i].set_func == chm_key) && !(chmode_table[i].set_func == chm_limit) && - !(chmode_table[i].set_func == chm_owner) && + !(chmode_table[i].set_func == chm_admin) && !(chmode_table[i].set_func == chm_op) && !(chmode_table[i].set_func == chm_halfop) && !(chmode_table[i].set_func == chm_voice)) @@ -103,22 +104,6 @@ construct_noparam_modes(void) chmode_flags[i] = 0; } - if (prev_chmode_flags[i] != 0 && prev_chmode_flags[i] != chmode_flags[i]) - { - if (chmode_flags[i] == 0) - { - chmode_table[i].set_func = chm_orphaned; - sendto_realops_snomask(SNO_DEBUG, L_ALL, "Cmode +%c is now orphaned", i); - } - else - { - sendto_realops_snomask(SNO_DEBUG, L_ALL, "Orphaned cmode +%c is picked up by module", i); - } - chmode_flags[i] = prev_chmode_flags[i]; - } - else - prev_chmode_flags[i] = chmode_flags[i]; - switch (chmode_flags[i]) { case MODE_EXLIMIT: @@ -137,14 +122,17 @@ construct_noparam_modes(void) break; default: - if(chmode_flags[i] != 0) + if(chmode_flags[i] != 0 && !(chmode_table[i].set_func == chm_orphaned)) { *ptr++ = (char) i; } } /* Should we leave orphaned check here? -- dwr */ - if(!(chmode_table[i].set_func == chm_nosuch) && !(chmode_table[i].set_func == chm_orphaned)) + if( !(chmode_table[i].set_func == chm_nosuch) && + !(chmode_table[i].set_func == chm_orphaned) && + !(chmode_table[i].set_func == chm_admin && !ConfigChannel.use_admin) && + !(chmode_table[i].set_func == chm_halfop && !ConfigChannel.use_halfop)) { *ptr2++ = (char) i; } @@ -154,6 +142,21 @@ construct_noparam_modes(void) *ptr2++ = '\0'; } +void +construct_cflag_param_string(void) +{ + + *cflagsparaminfo = '\0'; + rb_snprintf(cflagsparaminfo, sizeof cflagsparaminfo, "%sb%s%s%s%sklov%s%s", + ConfigChannel.use_admin ? "a" : "", + ConfigChannel.use_except ? "e" : "", + ConfigChannel.use_forward ? "f" : "", + ConfigChannel.use_halfop ? "h" : "", + strcasecmp(ConfigChannel.disabledmodes, "j") ? "" : "j", + strcasecmp(ConfigChannel.disabledmodes, "q") ? "" : "q", + ConfigChannel.use_invex ? "I" : ""); +} + /* * find_umode_slot * @@ -162,7 +165,7 @@ construct_noparam_modes(void) * 0 if no cflags are available * side effects - NONE */ -unsigned int +static unsigned int find_cflag_slot(void) { unsigned int all_cflags = 0, my_cflag = 0, i; @@ -176,11 +179,39 @@ find_cflag_slot(void) return my_cflag; } +unsigned int +cflag_add(char c_, ChannelModeFunc function) +{ + int c = (unsigned char)c_; + + if (chmode_table[c].set_func != chm_nosuch && + chmode_table[c].set_func != chm_orphaned) + return 0; + + if (chmode_table[c].set_func == chm_nosuch) + chmode_table[c].mode_type = find_cflag_slot(); + if (chmode_table[c].mode_type == 0) + return 0; + chmode_table[c].set_func = function; + construct_cflags_strings(); + return chmode_table[c].mode_type; +} + +void +cflag_orphan(char c_) +{ + int c = (unsigned char)c_; + + s_assert(chmode_flags[c] != 0); + chmode_table[c].set_func = chm_orphaned; + construct_cflags_strings(); +} + static int get_channel_access(struct Client *source_p, struct membership *msptr) { - if(!MyClient(source_p) || is_owner(msptr)) - return CHFL_OWNER; + if(!MyClient(source_p) || is_admin(msptr)) + return CHFL_ADMIN; else if(is_chanop(msptr)) return CHFL_CHANOP; else if(is_halfop(msptr)) @@ -505,7 +536,7 @@ chm_simple(struct Client *source_p, struct Channel *chptr, struct Metadata *md; struct DictionaryIter iter; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if (IsOverride(source_p)) override = 1; @@ -548,12 +579,12 @@ chm_simple(struct Client *source_p, struct Channel *chptr, { DICTIONARY_FOREACH(md, &iter, chptr->metadata) { - if(!strcmp(md->name, "KICKNOREJOIN")) + if(!strcmp(md->value, "KICKNOREJOIN")) channel_metadata_delete(chptr, md->name, 0); } } if(c == 'K') - channel_metadata_delete(chptr, md->name, 0); + channel_metadata_delete(chptr, "NOREPEAT", 0); chptr->mode.mode &= ~mode_type; @@ -574,7 +605,10 @@ chm_orphaned(struct Client *source_p, struct Channel *chptr, const char **parv, int *errors, int dir, char c, long mode_type) { if(MyClient(source_p)) + { + sendto_one_numeric(source_p, 469, "Mode %c is disabled.", c); return; + } if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type)) { @@ -626,6 +660,7 @@ chm_hidden(struct Client *source_p, struct Channel *chptr, if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) return; + /* setting + */ if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type)) { @@ -639,6 +674,19 @@ chm_hidden(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].mems = ONLY_OPERS; mode_changes[mode_count].override = 0; mode_changes[mode_count++].arg = NULL; + + /* A little ugly */ + sendto_wallops_flags(UMODE_WALLOP, &me, + "+%c set on [%s] by %s!%s@%s", + c, chptr->chname, source_p->name, source_p->username, source_p->host); + ilog(L_MAIN, "+%c set on [%s] by %s", + c, chptr->chname, get_oper_name(source_p)); + + if(*chptr->chname != '&') + sendto_server(NULL, NULL, NOCAPS, NOCAPS, + ":%s WALLOPS :+%c set on [%s] by %s!%s@%s", + me.name, c, chptr->chname, source_p->name, source_p->username, + source_p->host); } else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type)) { @@ -652,6 +700,19 @@ chm_hidden(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].id = NULL; mode_changes[mode_count].override = 0; mode_changes[mode_count++].arg = NULL; + + /* A little ugly */ + sendto_wallops_flags(UMODE_WALLOP, &me, + "+%c unset from [%s] by %s!%s@%s", + c, chptr->chname, source_p->name, source_p->username, source_p->host); + ilog(L_MAIN, "+%c unset from [%s] by %s", + c, chptr->chname, get_oper_name(source_p)); + + if(*chptr->chname != '&') + sendto_server(NULL, NULL, NOCAPS, NOCAPS, + ":%s WALLOPS :+%c unset from [%s] by %s!%s@%s", + me.name, c, chptr->chname, source_p->name, source_p->username, + source_p->host); } } @@ -660,6 +721,8 @@ chm_staff(struct Client *source_p, struct Channel *chptr, int alevel, int parc, int *parn, const char **parv, int *errors, int dir, char c, long mode_type) { + int override = 0; + if(!IsOper(source_p) && !IsServer(source_p)) { if(!(*errors & SM_ERR_NOPRIVS)) @@ -676,6 +739,20 @@ chm_staff(struct Client *source_p, struct Channel *chptr, return; } + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) + { + if (IsOverride(source_p)) + override = 1; + else + { + if(!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chptr->chname); + *errors |= SM_ERR_NOOPS; + return; + } + } + if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) return; @@ -690,7 +767,7 @@ chm_staff(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].id = NULL; mode_changes[mode_count].mems = ALL_MEMBERS; - mode_changes[mode_count].override = 0; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = NULL; } else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type)) @@ -702,7 +779,7 @@ chm_staff(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].caps = 0; mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; - mode_changes[mode_count].override = 0; + mode_changes[mode_count].override = override; mode_changes[mode_count].id = NULL; mode_changes[mode_count++].arg = NULL; } @@ -775,8 +852,8 @@ chm_ban(struct Client *source_p, struct Channel *chptr, case CHFL_QUIET: list = &chptr->quietlist; errorval = SM_ERR_RPL_Q; - rpl_list = RPL_BANLIST; - rpl_endlist = RPL_ENDOFBANLIST; + rpl_list = RPL_QUIETLIST; + rpl_endlist = RPL_ENDOFQUIETLIST; mems = ALL_MEMBERS; caps = 0; break; @@ -794,15 +871,17 @@ chm_ban(struct Client *source_p, struct Channel *chptr, *errors |= errorval; /* non-ops cant see +eI lists.. */ - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP && mode_type != CHFL_BAN && + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && mode_type != CHFL_BAN && mode_type != CHFL_QUIET) { if(IsOverride(source_p)) { - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + sendto_wallops_flags(UMODE_WALLOP, &me, "%s is overriding modes on %s: (%s list)", - get_oper_name(source_p), chptr->chname, - mode_type == CHFL_INVEX ? "invex" : "exempt"); + get_oper_name(source_p), chptr->chname, mode_type == CHFL_INVEX ? "invex" : "exempt"); + sendto_server(NULL, chptr, NOCAPS, NOCAPS, + ":%s WALLOPS :%s is overriding modes on %s: (%s list)", + me.name, get_oper_name(source_p), chptr->chname, mode_type == CHFL_INVEX ? "invex" : "exempt"); } else { @@ -822,14 +901,11 @@ chm_ban(struct Client *source_p, struct Channel *chptr, me.name, source_p->name, chptr->chname, banptr->banstr, banptr->who, banptr->when); } - if (mode_type == CHFL_QUIET) - sendto_one(source_p, ":%s %d %s %s :End of Channel Quiet List", me.name, rpl_endlist, source_p->name, chptr->chname); - else - sendto_one(source_p, form_str(rpl_endlist), me.name, source_p->name, chptr->chname); + sendto_one(source_p, form_str(rpl_endlist), me.name, source_p->name, chptr->chname); return; } - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -917,16 +993,16 @@ chm_ban(struct Client *source_p, struct Channel *chptr, } void -chm_owner(struct Client *source_p, struct Channel *chptr, +chm_admin(struct Client *source_p, struct Channel *chptr, int alevel, int parc, int *parn, const char **parv, int *errors, int dir, char c, long mode_type) { struct membership *mstptr; - const char *ownernick; + const char *adminnick; struct Client *targ_p; int override = 0; - if(!ConfigChannel.use_owner) + if(!ConfigChannel.use_admin) { if(*errors & SM_ERR_UNKNOWN) return; @@ -935,7 +1011,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, return; } - if(alevel != CHFL_OWNER) + if(alevel != CHFL_ADMIN) { if(IsOverride(source_p)) override = 1; @@ -943,8 +1019,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, { if(!(*errors & SM_ERR_NOOPS)) - sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), - me.name, source_p->name, chptr->chname); + sendto_one(source_p, ":%s 482 %s %s :You're not a channel administrator", me.name, source_p->name, chptr->chname); *errors |= SM_ERR_NOOPS; return; } @@ -953,17 +1028,17 @@ chm_owner(struct Client *source_p, struct Channel *chptr, if((dir == MODE_QUERY) || (parc <= *parn)) return; - ownernick = parv[(*parn)]; + adminnick = parv[(*parn)]; (*parn)++; /* empty nick */ - if(EmptyString(ownernick)) + if(EmptyString(adminnick)) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*"); return; } - if((targ_p = find_chasing(source_p, ownernick, NULL)) == NULL) + if((targ_p = find_chasing(source_p, adminnick, NULL)) == NULL) { return; } @@ -974,7 +1049,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, { if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p)) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, - form_str(ERR_USERNOTINCHANNEL), ownernick, chptr->chname); + form_str(ERR_USERNOTINCHANNEL), adminnick, chptr->chname); *errors |= SM_ERR_NOTONCHANNEL; return; } @@ -1004,7 +1079,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].override = override; mode_changes[mode_count++].client = targ_p; - mstptr->flags |= CHFL_OWNER; + mstptr->flags |= CHFL_ADMIN; } else { @@ -1025,7 +1100,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].override = override; mode_changes[mode_count++].client = targ_p; - mstptr->flags &= ~CHFL_OWNER; + mstptr->flags &= ~CHFL_ADMIN; } } @@ -1039,7 +1114,7 @@ chm_op(struct Client *source_p, struct Channel *chptr, struct Client *targ_p; int override = 0; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN) { if(IsOverride(source_p)) override = 1; @@ -1152,7 +1227,7 @@ chm_halfop(struct Client *source_p, struct Channel *chptr, return; } - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN) { if(IsOverride(source_p)) override = 1; @@ -1256,7 +1331,7 @@ chm_voice(struct Client *source_p, struct Channel *chptr, struct Client *targ_p; int override = 0; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -1343,7 +1418,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr, int limit; int override = 0; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -1410,7 +1485,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr, int joins = 0, timeslice = 0; int override = 0; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -1502,7 +1577,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr, } #ifndef FORWARD_OPERONLY - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -1557,7 +1632,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr, if(MyClient(source_p) && !(targptr->mode.mode & MODE_FREETARGET)) { if((msptr = find_channel_membership(targptr, source_p)) == NULL || - is_any_op(msptr)) + !is_any_op(msptr)) { if(IsOverride(source_p)) override = 1; @@ -1607,7 +1682,7 @@ chm_key(struct Client *source_p, struct Channel *chptr, char *key; int override = 0; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -1693,7 +1768,7 @@ chm_regonly(struct Client *source_p, struct Channel *chptr, { int override = 0; - if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) + if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP) { if(IsOverride(source_p)) override = 1; @@ -1833,7 +1908,7 @@ struct ChannelMode chmode_table[256] = {chm_nosuch, 0 }, {chm_nosuch, 0 }, {chm_nosuch, 0 }, - {chm_owner, 0 }, /* a */ + {chm_admin, 0 }, /* a */ {chm_ban, CHFL_BAN }, /* b */ {chm_simple, MODE_NOCOLOR }, /* c */ {chm_nosuch, 0 }, /* d */ @@ -2062,6 +2137,19 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, dir = MODE_QUERY; break; default: + /* If this mode char is locked, don't allow local users to change it. */ + if (MyClient(source_p) && chptr->mode_lock && strchr(chptr->mode_lock, c)) + { + if (!(errors & SM_ERR_MLOCK)) + sendto_one_numeric(source_p, + ERR_MLOCKRESTRICTED, + form_str(ERR_MLOCKRESTRICTED), + chptr->chname, + c, + chptr->mode_lock); + errors |= SM_ERR_MLOCK; + continue; + } chmode_table[(unsigned char) c].set_func(fakesource_p, chptr, alevel, parc, &parn, parv, &errors, dir, c, @@ -2139,10 +2227,14 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, sendto_channel_local(flags, chptr, "%s%s %s", cmdbuf, modebuf, parabuf); if(override) - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + { + sendto_wallops_flags(UMODE_WALLOP, &me, "%s is overriding modes on %s: %s %s", - get_oper_name(source_p), chptr->chname, - modebuf, parabuf); + get_oper_name(source_p), chptr->chname, modebuf, parabuf); + sendto_server(NULL, chptr, NOCAPS, NOCAPS, + ":%s WALLOPS :%s is overriding modes on %s: %s %s", + me.name, get_oper_name(source_p), chptr->chname, modebuf, parabuf); + } } else continue; @@ -2182,10 +2274,14 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, { sendto_channel_local(flags, chptr, "%s%s %s", cmdbuf, modebuf, parabuf); if(override) - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + { + sendto_wallops_flags(UMODE_WALLOP, &me, "%s is overriding modes on %s: %s %s", - get_oper_name(source_p), chptr->chname, - modebuf, parabuf); + get_oper_name(source_p), chptr->chname, modebuf, parabuf); + sendto_server(NULL, chptr, NOCAPS, NOCAPS, + ":%s WALLOPS :%s is overriding modes on %s: %s %s", + me.name, get_oper_name(source_p), chptr->chname, modebuf, parabuf); + } } } if(override) @@ -2201,3 +2297,24 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, if(MyClient(source_p) || rb_dlink_list_length(&serv_list) > 1) send_cap_mode_changes(client_p, source_p, chptr, mode_changes, mode_count); } + +/* set_channel_mlock() + * + * inputs - client, source, channel, params + * output - + * side effects - channel mlock is changed / MLOCK is propagated + */ +void +set_channel_mlock(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, const char *newmlock, int propagate) +{ + rb_free(chptr->mode_lock); + chptr->mode_lock = newmlock ? rb_strdup(newmlock) : NULL; + + if (propagate) + { + sendto_server(client_p, NULL, CAP_TS6 | CAP_MLOCK, NOCAPS, ":%s MLOCK %ld %s :%s", + source_p->id, (long) chptr->channelts, chptr->chname, + chptr->mode_lock ? chptr->mode_lock : ""); + } +}