diff --git a/TODO-SHADOW b/TODO-SHADOW index 01422cb..ecff06d 100644 --- a/TODO-SHADOW +++ b/TODO-SHADOW @@ -2,7 +2,6 @@ Todo list for Shadowircd 6.0 ----------------------------- * swhois support * custom operstrings (?) -* autochanmodes defined in the .conf (cmodes that are set on a channel on initial join.) * halfops - probably enabled/disabled via a configure switch on in the .conf * owner/+a prefix/cmode - see comment for halfops :D * "soft" callerid umode (+G, only allows PM's from users in the same channel as you) diff --git a/doc/example.conf b/doc/example.conf index ead3b0f..7636a38 100755 --- a/doc/example.conf +++ b/doc/example.conf @@ -326,6 +326,7 @@ exempt { }; channel { + autochanmodes = "nt"; use_invex = yes; use_except = yes; use_knock = yes; @@ -510,6 +511,7 @@ general { reject_duration = 5 minutes; throttle_duration = 60; throttle_count = 4; + expire_override_time = 5 minutes; }; modules { diff --git a/doc/reference.conf b/doc/reference.conf index 672946d..4c4e608 100755 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -673,6 +673,11 @@ exempt { /* The channel block contains options pertaining to channels */ channel { + /* autochanmodes: Modes that will be set on a unregistered channel + * when the first user joins it. + */ + autochanmodes = "nt"; + /* invex: Enable/disable channel mode +I, a n!u@h list of masks * that can join a +i channel without an invite. */ @@ -1260,6 +1265,12 @@ general { /* throttle_count: Number of connections within throttle_duration that it takes * for throttling to take effect */ throttle_count = 4; + + /* expire_override_time: User mode +p (override) will be automatically unset + * this long after it is set. 0 disables this (not recommended). Default is + * 5 minutes. + */ + expire_override_time = 5 minutes; }; modules { diff --git a/help/opers/umode b/help/opers/umode index 3c78a53..d930b58 100644 --- a/help/opers/umode +++ b/help/opers/umode @@ -13,6 +13,7 @@ Usermodes: (* designates that the umode is oper only) * +l - Can see oper locops (local wallops). * +s - Can see server notices (see /quote help snomask). * +z - Can see operwalls. + * +p - Override -- implicit operator access in all channels. +B - Marks you as a bot in /whois. +C - Prevents you from receiving CTCPs other than ACTION. +D - Deaf - ignores all channel messages. diff --git a/include/channel.h b/include/channel.h index c7a6ecf..4064c3d 100644 --- a/include/channel.h +++ b/include/channel.h @@ -88,6 +88,7 @@ struct membership unsigned int flags; unsigned long bants; + unsigned long override_ts; }; #define BANLEN 195 @@ -114,6 +115,7 @@ struct ChModeChange int caps; int nocaps; int mems; + int override; struct Client *client; }; @@ -171,6 +173,7 @@ typedef int (*ExtbanFunc)(const char *data, struct Client *client_p, #define MODE_FREEINVITE 0x0800 /* allow free use of /invite */ #define MODE_FREETARGET 0x1000 /* can be forwarded to without authorization */ #define MODE_DISFORWARD 0x2000 /* disable channel forwarding */ +#define MODE_NOOPERKICK 0x4000 /* disallow kicking opers aka immune */ #define MODE_NOCTCP 0x8000 /* Block CTCPs directed to this channel */ #define MODE_NONOTICE 0x16000 /* Block notices directed to this channel */ #define MODE_NOACTION 0x32000 /* Block CTCP ACTION directed to this channel */ @@ -194,6 +197,8 @@ typedef int (*ExtbanFunc)(const char *data, struct Client *client_p, /* channel visible */ #define ShowChannel(v,c) (PubChannel(c) || IsMember((v),(c))) +/* user visible in channel */ +#define ShowInChannel(v,t,c) ((PubChannel(c) && !IsInvisible(t)) || IsMember((v),(c))) #define IsMember(who, chan) ((who && who->user && \ find_channel_membership(chan, who)) ? 1 : 0) diff --git a/include/chmode.h b/include/chmode.h index a9c04a6..48e96d5 100644 --- a/include/chmode.h +++ b/include/chmode.h @@ -48,6 +48,9 @@ extern void chm_simple(struct Client *source_p, struct Channel *chptr, extern void chm_ban(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); +extern void chm_hidden(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); extern void 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); diff --git a/include/client.h b/include/client.h index 2d673cf..e1f285a 100644 --- a/include/client.h +++ b/include/client.h @@ -281,6 +281,8 @@ struct LocalUser struct ev_entry *event; /* used for associated events */ struct PrivilegeSet *privset; /* privset... */ + + struct rb_event_t *override_timeout_event; }; struct PreClient @@ -430,6 +432,17 @@ struct ListClient #define UMODE_ADMIN 0x2000 /* Admin on server */ #define UMODE_SSLCLIENT 0x4000 /* using SSL */ +/* oper-controlled privledge umodes. */ +#define UMODE_OVERRIDE 0x20000 + +/* umode/oper mode macros */ +#define IsOper(x) ((x)->umodes & UMODE_OPER) +#define IsAdmin(x) ((x)->umodes & UMODE_ADMIN) +#define IsHelper(x) ((x)->umodes & UMODE_HELPER) +#define IsAnyOper(x) ((x)->umodes & (UMODE_OPER|UMODE_HELPER)) + +#define IsOverride(x) ((x)->umodes & UMODE_OVERRIDE) + /* overflow flags */ /* EARLIER FLAGS ARE IN s_newconf.h */ #define FLAGS2_EXEMPTRESV 0x00400000 diff --git a/include/s_conf.h b/include/s_conf.h index 625bfde..636f5e7 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -217,10 +217,12 @@ struct config_file_entry int global_snotices; int operspy_dont_care_user_info; int secret_channels_in_whois; + int expire_override_time; }; struct config_channel_entry { + char * autochanmodes; int use_except; int use_invex; int use_knock; diff --git a/include/s_newconf.h b/include/s_newconf.h index 03e887d..e55d8ec 100644 --- a/include/s_newconf.h +++ b/include/s_newconf.h @@ -164,6 +164,7 @@ extern void cluster_generic(struct Client *, const char *, int cltype, #define IsOperSpy(x) (HasPrivilege((x), "oper:spy")) #define IsOperInvis(x) (HasPrivilege((x), "oper:hidden")) #define IsOperRemoteBan(x) (HasPrivilege((x), "oper:remoteban")) +#define IsOperOverride(x) HasPrivilege(x, "oper:override") #define IsOperMassNotice(x) (HasPrivilege((x), "oper:mass_notice")) extern struct oper_conf *make_oper_conf(void); @@ -175,6 +176,20 @@ extern struct oper_conf *find_oper_conf(const char *username, const char *host, extern const char *get_oper_privs(int flags); +struct mode_table +{ + const char *name; + int mode; +}; + +struct oper_flags +{ + int flag; + const char *name; + char has; + char hasnt; +}; + struct server_conf { char *name; diff --git a/modules/m_info.c b/modules/m_info.c index 746ae41..53b0026 100644 --- a/modules/m_info.c +++ b/modules/m_info.c @@ -175,6 +175,12 @@ static struct InfoStruct info_table[] = { &ConfigFileEntry.dots_in_ident, "Number of permissable dots in an ident" }, + { + "expire_override_time", + OUTPUT_DECIMAL, + &ConfigFileEntry.expire_override_time, + "Period of time after which to unset user mode +p" + }, { "failed_oper_notice", OUTPUT_BOOLEAN, @@ -326,6 +332,12 @@ static struct InfoStruct info_table[] = { &ServerInfo.network_desc, "Network description" }, + { + "autochanmodes", + OUTPUT_STRING, + &ConfigChannel.autochanmodes, + "Channelmodes set on channel creation" + }, { "nick_delay", OUTPUT_DECIMAL, diff --git a/modules/m_privs.c b/modules/m_privs.c index 1d24aad..c87bb0d 100644 --- a/modules/m_privs.c +++ b/modules/m_privs.c @@ -53,13 +53,6 @@ mapi_clist_av1 privs_clist[] = { NULL }; -/* XXX this is a copy, not so nice */ -struct mode_table -{ - const char *name; - int mode; -}; - /* there is no such table like this anywhere else */ static struct mode_table auth_client_table[] = { {"resv_exempt", FLAGS2_EXEMPTRESV }, diff --git a/src/channel.c b/src/channel.c index 1e35f3d..d00be83 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1705,8 +1705,22 @@ void user_join(struct Client * client_p, struct Client * source_p, const char * if(flags & CHFL_CHANOP) { chptr->channelts = rb_current_time(); - chptr->mode.mode |= MODE_TOPICLIMIT; - chptr->mode.mode |= MODE_NOPRIVMSGS; + + /* autochanmodes stuff */ + if(ConfigChannel.autochanmodes) + { + char * ch; + for(ch = ConfigChannel.autochanmodes; *ch; *ch++) + { + chptr->mode.mode |= chmode_table[*ch].mode_type; + } + } + else + { + chptr->mode.mode |= MODE_TOPICLIMIT; + chptr->mode.mode |= MODE_NOPRIVMSGS; + } + modes = channel_modes(chptr, &me); sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s %s", diff --git a/src/client.c b/src/client.c index b3f33c3..cad1b7f 100644 --- a/src/client.c +++ b/src/client.c @@ -232,6 +232,12 @@ free_local_client(struct Client *client_p) } rb_free(client_p->localClient->auth_user); + + if(client_p->localClient->override_timeout_event) + { + rb_event_delete(client_p->localClient->override_timeout_event); + } + rb_free(client_p->localClient->challenge); rb_free(client_p->localClient->fullcaps); rb_free(client_p->localClient->opername); diff --git a/src/newconf.c b/src/newconf.c index 168de2d..2f333fe 100644 --- a/src/newconf.c +++ b/src/newconf.c @@ -286,12 +286,6 @@ conf_set_modules_path(void *data) #endif } -struct mode_table -{ - const char *name; - int mode; -}; - /* *INDENT-OFF* */ static struct mode_table umode_table[] = { {"callerid", UMODE_CALLERID }, @@ -303,6 +297,7 @@ static struct mode_table umode_table[] = { {"servnotice", UMODE_SERVNOTICE}, {"wallop", UMODE_WALLOP }, {"operwall", UMODE_OPERWALL }, + {"override", UMODE_OVERRIDE }, {"noctcp", UMODE_NOCTCP }, {"noinvite", UMODE_NOINVITE }, {"bot", UMODE_BOT }, @@ -2199,11 +2194,13 @@ static struct ConfEntry conf_general_table[] = { "ts_warn_delta", CF_TIME, NULL, 0, &ConfigFileEntry.ts_warn_delta }, { "use_whois_actually", CF_YESNO, NULL, 0, &ConfigFileEntry.use_whois_actually }, { "warn_no_nline", CF_YESNO, NULL, 0, &ConfigFileEntry.warn_no_nline }, + { "expire_override_time", CF_TIME, NULL, 0, &ConfigFileEntry.expire_override_time }, { "\0", 0, NULL, 0, NULL } }; static struct ConfEntry conf_channel_table[] = { + { "autochanmodes", CF_QSTRING, NULL, 0, &ConfigChannel.autochanmodes }, { "default_split_user_count", CF_INT, NULL, 0, &ConfigChannel.default_split_user_count }, { "default_split_server_count", CF_INT, NULL, 0, &ConfigChannel.default_split_server_count }, { "burst_topicwho", CF_YESNO, NULL, 0, &ConfigChannel.burst_topicwho }, diff --git a/src/s_conf.c b/src/s_conf.c index dcdd30d..40a18b0 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -746,6 +746,7 @@ set_default_conf(void) ConfigFileEntry.oper_only_umodes = UMODE_SERVNOTICE; ConfigFileEntry.oper_snomask = SNO_GENERAL; + ConfigChannel.autochanmodes = rb_strdup("nt"); ConfigChannel.use_except = YES; ConfigChannel.use_invex = YES; ConfigChannel.use_knock = YES; @@ -783,6 +784,7 @@ set_default_conf(void) ConfigFileEntry.reject_duration = 120; ConfigFileEntry.throttle_count = 4; ConfigFileEntry.throttle_duration = 60; + ConfigFileEntry.expire_override_time = 300; ServerInfo.default_max_clients = MAXCONNECTIONS; diff --git a/src/s_user.c b/src/s_user.c index 441012c..8c9683e 100644 --- a/src/s_user.c +++ b/src/s_user.c @@ -109,7 +109,7 @@ int user_modes[256] = { 0, /* m */ 0, /* n */ UMODE_OPER, /* o */ - 0, /* p */ + UMODE_OVERRIDE, /* p */ 0, /* q */ 0, /* r */ UMODE_SERVNOTICE, /* s */ @@ -881,6 +881,15 @@ report_and_set_user_flags(struct Client *source_p, struct ConfItem *aconf) } } +static void +expire_umode_p(void *data) +{ + struct Client *source_p = data; + char *parv[4] = {source_p->name, source_p->name, "-p", NULL}; + source_p->localClient->override_timeout_event = NULL; + user_mode(source_p, source_p, 3, parv); +} + static void show_other_user_mode(struct Client *source_p, struct Client *target_p) { @@ -1138,6 +1147,12 @@ user_mode(struct Client *client_p, struct Client *source_p, int parc, const char source_p->umodes &= ~UMODE_ADMIN; } + if(MyConnect(source_p) && (source_p->umodes & UMODE_OVERRIDE) && (!IsOperOverride(source_p))) + { + sendto_one_notice(source_p, ":*** You need oper and the override flag for +p"); + source_p->umodes &= ~UMODE_OVERRIDE; + } + /* let modules providing usermodes know that we've changed our usermode --nenolod */ hdata.client = source_p; hdata.oldumodes = setflags; @@ -1157,6 +1172,17 @@ user_mode(struct Client *client_p, struct Client *source_p, int parc, const char sendto_one_numeric(source_p, RPL_SNOMASK, form_str(RPL_SNOMASK), construct_snobuf(source_p->snomask)); + if(ConfigFileEntry.expire_override_time && MyClient(source_p) && (source_p->umodes & ~setflags) & UMODE_OVERRIDE) + { + source_p->localClient->override_timeout_event = + rb_event_addonce("expire_override", expire_umode_p, source_p, ConfigFileEntry.expire_override_time); + } + else if(MyClient(source_p) && source_p->localClient->override_timeout_event && (setflags & ~source_p->umodes) & UMODE_OVERRIDE) + { + rb_event_delete(source_p->localClient->override_timeout_event); + source_p->localClient->override_timeout_event = NULL; + } + return (0); }