Rework ircd-side MLOCK enforcement: instead of trying to track modes locked on or off, instead keep a simple list of mode letters that are locked, and reject any change to those modes.

This commit is contained in:
Stephen Bennett 2010-04-30 22:01:21 +01:00
parent 2d10c55990
commit b72bd23a03
4 changed files with 13 additions and 40 deletions

View File

@ -38,7 +38,6 @@ struct Client;
struct Mode
{
unsigned int mode;
unsigned int off_mode;
int limit;
char key[KEYLEN];
unsigned int join_num;
@ -51,7 +50,7 @@ struct Channel
{
rb_dlink_node node;
struct Mode mode;
struct Mode mode_lock;
char *mode_lock;
char *topic;
char *topic_info;
time_t topic_time;
@ -294,7 +293,7 @@ void resv_chan_forcepart(const char *name, const char *reason, int temp_time);
extern void set_channel_mode(struct Client *client_p, struct Client *source_p,
struct Channel *chptr, struct membership *msptr, int parc, const char *parv[]);
extern void set_channel_mlock(struct Client *client_p, struct Client *source_p,
struct Channel *chptr, int parc, const char *parv[]);
struct Channel *chptr, const char *newmlock);
extern struct ChannelMode chmode_table[256];

View File

@ -236,7 +236,7 @@ ms_mlock(struct Client *client_p, struct Client *source_p, int parc, const char
return 0;
if(IsServer(source_p))
set_channel_mlock(client_p, source_p, chptr, parc - 3, parv + 3);
set_channel_mlock(client_p, source_p, chptr, parv[3]);
return 0;
}

View File

@ -142,6 +142,7 @@ free_channel(struct Channel *chptr)
{
channel_metadata_clear(chptr);
rb_free(chptr->chname);
rb_free(chptr->mode_lock);
rb_bh_free(channel_heap, chptr);
}

View File

@ -530,7 +530,7 @@ chm_simple(struct Client *source_p, struct Channel *chptr,
return;
/* setting + */
if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type) && !(chptr->mode_lock.off_mode & mode_type))
if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
{
/* if +f is disabled, ignore an attempt to set +QF locally */
if(!ModuleModes.MODE_FORWARD && MyClient(source_p) &&
@ -595,7 +595,7 @@ chm_orphaned(struct Client *source_p, struct Channel *chptr,
mode_changes[mode_count].mems = ALL_MEMBERS;
mode_changes[mode_count++].arg = NULL;
}
else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type) && !(chptr->mode_lock.mode & mode_type))
else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
{
chptr->mode.mode &= ~mode_type;
@ -2084,6 +2084,9 @@ 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))
continue;
chmode_table[(unsigned char) c].set_func(fakesource_p, chptr, alevel,
parc, &parn, parv,
&errors, dir, c,
@ -2240,41 +2243,11 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
*/
void
set_channel_mlock(struct Client *client_p, struct Client *source_p,
struct Channel *chptr, int parc, const char *parv[])
struct Channel *chptr, const char *newmlock)
{
int dir = MODE_ADD;
const char *ml = parv[0];
char c;
memset(&chptr->mode_lock, '\0', sizeof(struct Mode));
for(; (c = *ml) != 0; ml++)
{
switch (c)
{
case '+':
dir = MODE_ADD;
break;
case '-':
dir = MODE_DEL;
break;
default:
if (chmode_table[(unsigned char) c].set_func == chm_simple)
switch(dir)
{
case MODE_ADD:
chptr->mode_lock.mode |= chmode_table[(unsigned char) c].mode_type;
chptr->mode_lock.off_mode &= ~chmode_table[(unsigned char) c].mode_type;
break;
case MODE_DEL:
chptr->mode_lock.off_mode |= chmode_table[(unsigned char) c].mode_type;
chptr->mode_lock.mode &= ~chmode_table[(unsigned char) c].mode_type;
break;
}
break;
}
}
rb_free(chptr->mode_lock);
chptr->mode_lock = rb_strdup(newmlock);
sendto_server(client_p, NULL, CAP_TS6 | CAP_MLOCK, NOCAPS, ":%s MLOCK %ld %s %s",
source_p->id, (long) chptr->channelts, chptr->chname, channel_mlock(chptr, &me));
source_p->id, (long) chptr->channelts, chptr->chname, chptr->mode_lock);
}