diff --git a/extensions/umode_noctcp.c b/extensions/umode_noctcp.c index bb1b6490..0a485733 100644 --- a/extensions/umode_noctcp.c +++ b/extensions/umode_noctcp.c @@ -42,6 +42,9 @@ mapi_hfn_list_av1 umode_noctcp_hfnlist[] = { static void umode_noctcp_process(hook_data_privmsg_user *data) { + if (!MyClient(data->target_p)) + return; + if (data->approved || data->msgtype == MESSAGE_TYPE_NOTICE) { return; } diff --git a/help/opers/umode b/help/opers/umode index e961a738..178752e6 100644 --- a/help/opers/umode +++ b/help/opers/umode @@ -18,6 +18,7 @@ User modes: (* designates that the umode is oper only) * +z - Can see operwalls. ? +C - Prevents you from receiving CTCPs other than ACTION. +D - Deaf - ignores all channel messages. + +G - Allow users with common channels to bypass "caller id" mode. +Q - Prevents you from being affected by channel forwarding. +R - Prevents unidentified users that you have not accepted from messaging you. diff --git a/help/users/umode b/help/users/umode index 71b01305..b3b5b444 100644 --- a/help/users/umode +++ b/help/users/umode @@ -13,6 +13,7 @@ User modes: (? designates that the umode is provided by an extension +w - Can see oper wallops. ? +C - Prevents you from receiving CTCPs other than ACTION. +D - Deaf - ignores all channel messages. + +G - Allow users with common channels to bypass "caller id" mode. +Q - Prevents you from being affected by channel forwarding. +R - Prevents unidentified users that you have not accepted from messaging you. diff --git a/include/client.h b/include/client.h index 0f132160..e43838b9 100644 --- a/include/client.h +++ b/include/client.h @@ -444,7 +444,6 @@ struct ListClient #define UMODE_WALLOP 0x0002 /* send wallops to them */ #define UMODE_OPERWALL 0x0004 /* Operwalls */ #define UMODE_INVISIBLE 0x0008 /* makes user invisible */ -#define UMODE_CALLERID 0x0010 /* block unless caller id's */ #define UMODE_LOCOPS 0x0020 /* show locops */ #define UMODE_SERVICE 0x0040 #define UMODE_DEAF 0x0080 @@ -535,7 +534,6 @@ struct ListClient #define SendLocops(x) ((x)->umodes & UMODE_LOCOPS) #define SendServNotice(x) ((x)->umodes & UMODE_SERVNOTICE) #define SendOperwall(x) ((x)->umodes & UMODE_OPERWALL) -#define IsSetCallerId(x) ((x)->umodes & UMODE_CALLERID) #define IsService(x) ((x)->umodes & UMODE_SERVICE) #define IsDeaf(x) ((x)->umodes & UMODE_DEAF) #define IsNoForward(x) ((x)->umodes & UMODE_NOFORWARD) diff --git a/include/messages.h b/include/messages.h index d37bf327..1fa36d82 100644 --- a/include/messages.h +++ b/include/messages.h @@ -217,9 +217,9 @@ #define NUMERIC_STR_713 "%s :Channel is open." #define NUMERIC_STR_714 ":%s 714 %s %s :You are already on that channel." #define NUMERIC_STR_715 ":%s 715 %s :KNOCKs are disabled." -#define NUMERIC_STR_716 "%s :is in +g mode (server-side ignore.)" +#define NUMERIC_STR_716 "%s :is in %s mode (server-side ignore.)" #define NUMERIC_STR_717 "%s :has been informed that you messaged them." -#define NUMERIC_STR_718 ":%s 718 %s %s %s@%s :is messaging you, and you have umode +g." +#define NUMERIC_STR_718 ":%s 718 %s %s %s@%s :is messaging you, and you have umode %s." #define NUMERIC_STR_720 ":%s 720 %s :Start of OPER MOTD" #define NUMERIC_STR_721 ":%s 721 %s :%s" #define NUMERIC_STR_722 ":%s 722 %s :End of OPER MOTD" diff --git a/include/supported.h b/include/supported.h index 27d8e07a..2a77f095 100644 --- a/include/supported.h +++ b/include/supported.h @@ -44,5 +44,6 @@ extern const char *isupport_intptr(const void *); extern const char *isupport_boolean(const void *); extern const char *isupport_string(const void *); extern const char *isupport_stringptr(const void *); +extern const char *isupport_umode(const void *); #endif /* INCLUDED_supported_h */ diff --git a/ircd/newconf.c b/ircd/newconf.c index 6f8a3b58..9e200fd7 100644 --- a/ircd/newconf.c +++ b/ircd/newconf.c @@ -316,7 +316,6 @@ struct mode_table /* *INDENT-OFF* */ static struct mode_table umode_table[] = { - {"callerid", UMODE_CALLERID }, {"deaf", UMODE_DEAF }, {"invisible", UMODE_INVISIBLE }, {"locops", UMODE_LOCOPS }, diff --git a/ircd/s_user.c b/ircd/s_user.c index cb4cf9db..bda9bca8 100644 --- a/ircd/s_user.c +++ b/ircd/s_user.c @@ -97,7 +97,7 @@ int user_modes[256] = { 0, /* d */ 0, /* e */ 0, /* f */ - UMODE_CALLERID, /* g */ + 0, /* g */ 0, /* h */ UMODE_INVISIBLE, /* i */ 0, /* j */ diff --git a/ircd/supported.c b/ircd/supported.c index 09de6ce0..35c6ea93 100644 --- a/ircd/supported.c +++ b/ircd/supported.c @@ -223,7 +223,7 @@ isupport_stringptr(const void *ptr) return *(char * const *)ptr; } -static const char * +const char * isupport_umode(const void *ptr) { const char *str; @@ -318,7 +318,6 @@ init_isupport(void) add_isupport("MODES", isupport_intptr, &maxmodes); add_isupport("NETWORK", isupport_stringptr, &ServerInfo.network_name); add_isupport("STATUSMSG", isupport_string, "@+"); - add_isupport("CALLERID", isupport_umode, "g"); add_isupport("CASEMAPPING", isupport_string, "rfc1459"); add_isupport("NICKLEN", isupport_nicklen, NULL); add_isupport("MAXNICKLEN", isupport_intptr, &maxnicklen); diff --git a/modules/Makefile.am b/modules/Makefile.am index 7f532db7..d7005577 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -15,6 +15,7 @@ auto_load_mod_LTLIBRARIES = \ cap_server_time.la \ chm_nocolour.la \ chm_noctcp.la \ + um_callerid.la \ um_regonlymsg.la \ m_accept.la \ m_admin.la \ diff --git a/modules/core/m_message.c b/modules/core/m_message.c index e329e7bf..d146eab8 100644 --- a/modules/core/m_message.c +++ b/modules/core/m_message.c @@ -718,32 +718,6 @@ msg_client(enum message_type msgtype, if(MyClient(source_p)) { - /* - * XXX: Controversial? Allow target users to send replies - * through a +g. Rationale is that people can presently use +g - * as a way to taunt users, e.g. harass them and hide behind +g - * as a way of griefing. --nenolod - */ - if(msgtype != MESSAGE_TYPE_NOTICE && - IsSetCallerId(source_p) && - !accept_message(target_p, source_p) && - !IsOper(target_p)) - { - if(rb_dlink_list_length(&source_p->localClient->allow_list) < - (unsigned long)ConfigFileEntry.max_accept) - { - rb_dlinkAddAlloc(target_p, &source_p->localClient->allow_list); - rb_dlinkAddAlloc(source_p, &target_p->on_allow_list); - } - else - { - sendto_one_numeric(source_p, ERR_OWNMODE, - form_str(ERR_OWNMODE), - target_p->name, "+g"); - return; - } - } - /* reset idle time for message only if its not to self * and its not a notice */ if(msgtype != MESSAGE_TYPE_NOTICE) @@ -791,22 +765,22 @@ msg_client(enum message_type msgtype, sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY), target_p->name, target_p->user->away); + hdata.msgtype = msgtype; + hdata.source_p = source_p; + hdata.target_p = target_p; + hdata.text = text; + hdata.approved = 0; + + call_hook(h_privmsg_user, &hdata); + + /* buffer location may have changed. */ + text = hdata.text; + + if (hdata.approved != 0) + return; + if(MyClient(target_p)) { - hdata.msgtype = msgtype; - hdata.source_p = source_p; - hdata.target_p = target_p; - hdata.text = text; - hdata.approved = 0; - - call_hook(h_privmsg_user, &hdata); - - /* buffer location may have changed. */ - text = hdata.text; - - if (hdata.approved != 0) - return; - if (EmptyString(text)) { /* could be empty after colour stripping and @@ -816,50 +790,8 @@ msg_client(enum message_type msgtype, return; } - /* XXX Controversial? allow opers always to send through a +g */ - if(!IsServer(source_p) && IsSetCallerId(target_p)) - { - /* Here is the anti-flood bot/spambot code -db */ - if(accept_message(source_p, target_p) || IsOper(source_p)) - { - add_reply_target(target_p, source_p); - sendto_one(target_p, ":%s!%s@%s %s %s :%s", - source_p->name, - source_p->username, - source_p->host, cmdname[msgtype], target_p->name, text); - } - else - { - /* check for accept, flag recipient incoming message */ - if(msgtype != MESSAGE_TYPE_NOTICE) - { - sendto_one_numeric(source_p, ERR_TARGUMODEG, - form_str(ERR_TARGUMODEG), - target_p->name); - } - - if((target_p->localClient->last_caller_id_time + - ConfigFileEntry.caller_id_wait) < rb_current_time()) - { - if(msgtype != MESSAGE_TYPE_NOTICE) - sendto_one_numeric(source_p, RPL_TARGNOTIFY, - form_str(RPL_TARGNOTIFY), - target_p->name); - - add_reply_target(target_p, source_p); - sendto_one(target_p, form_str(RPL_UMODEGMSG), - me.name, target_p->name, source_p->name, - source_p->username, source_p->host); - - target_p->localClient->last_caller_id_time = rb_current_time(); - } - } - } - else - { - add_reply_target(target_p, source_p); - sendto_anywhere(target_p, source_p, cmdname[msgtype], ":%s", text); - } + add_reply_target(target_p, source_p); + sendto_anywhere(target_p, source_p, cmdname[msgtype], ":%s", text); } else sendto_anywhere(target_p, source_p, cmdname[msgtype], ":%s", text); diff --git a/modules/m_invite.c b/modules/m_invite.c index bbdee565..0b882aab 100644 --- a/modules/m_invite.c +++ b/modules/m_invite.c @@ -201,30 +201,6 @@ m_invite(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source if(MyConnect(target_p)) { - if(!IsOper(source_p) && IsSetCallerId(target_p) && !accept_message(source_p, target_p)) - { - sendto_one_numeric(source_p, ERR_TARGUMODEG, - form_str(ERR_TARGUMODEG), - target_p->name); - - if((target_p->localClient->last_caller_id_time + - ConfigFileEntry.caller_id_wait) < rb_current_time()) - { - sendto_one_numeric(source_p, RPL_TARGNOTIFY, - form_str(RPL_TARGNOTIFY), - target_p->name); - - add_reply_target(target_p, source_p); - sendto_one(target_p, form_str(RPL_UMODEGMSG), - me.name, target_p->name, source_p->name, - source_p->username, source_p->host); - - target_p->localClient->last_caller_id_time = rb_current_time(); - } - - return; - } - hdata.chptr = chptr; hdata.msptr = msptr; hdata.client = source_p; diff --git a/modules/um_callerid.c b/modules/um_callerid.c new file mode 100644 index 00000000..1e7a9e75 --- /dev/null +++ b/modules/um_callerid.c @@ -0,0 +1,250 @@ +/* + * modules/um_callerid.c + * Copyright (c) 2020 Ariadne Conill + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stdinc.h" +#include "modules.h" +#include "hook.h" +#include "client.h" +#include "ircd.h" +#include "send.h" +#include "hash.h" +#include "s_conf.h" +#include "s_user.h" +#include "s_serv.h" +#include "numeric.h" +#include "privilege.h" +#include "s_newconf.h" +#include "hook.h" +#include "supported.h" +#include "logger.h" + +static int +um_callerid_modinit(void) +{ + user_modes['g'] = find_umode_slot(); + if (!user_modes['g']) + { + ierror("um_callerid: unable to allocate usermode slot for +g; unloading module."); + return -1; + } + + user_modes['G'] = find_umode_slot(); + if (!user_modes['G']) + { + user_modes['g'] = 0; + + ierror("um_callerid: unable to allocate usermode slot for +G; unloading module."); + return -1; + } + + construct_umodebuf(); + + add_isupport("CALLERID", isupport_umode, "g"); + + return 0; +} + +static void +um_callerid_moddeinit(void) +{ + user_modes['g'] = 0; + user_modes['G'] = 0; + construct_umodebuf(); + + delete_isupport("CALLERID"); +} + +#define IsSetStrictCallerID(c) ((c->umodes & user_modes['g']) == user_modes['g']) +#define IsSetRelaxedCallerID(c) ((c->umodes & user_modes['G']) == user_modes['G']) +#define IsSetAnyCallerID(c) (IsSetStrictCallerID(c) || IsSetRelaxedCallerID(c)) + +static const char um_callerid_desc[] = + "Provides usermodes +g and +G which restrict messages from unauthorized users."; + +static bool +has_common_channel(struct Client *source_p, struct Client *target_p) +{ + rb_dlink_node *ptr; + + RB_DLINK_FOREACH(ptr, source_p->user->channel.head) + { + struct membership *msptr = ptr->data; + if (IsMember(target_p, msptr->chptr)) + return true; + } + + return false; +} + +static bool +allow_message(struct Client *source_p, struct Client *target_p) +{ + if (!MyClient(target_p)) + return true; + + if (!IsSetAnyCallerID(target_p)) + return true; + + if (IsSetRelaxedCallerID(target_p) && has_common_channel(source_p, target_p) && !IsSetStrictCallerID(target_p)) + return true; + + if (IsServer(source_p)) + return true; + + /* XXX: controversial? allow opers to send through +g */ + if (IsOper(source_p)) + return true; + + if (accept_message(source_p, target_p)) + return true; + + return false; +} + +static void +send_callerid_notice(enum message_type msgtype, struct Client *source_p, struct Client *target_p) +{ + if (!MyClient(target_p)) + return; + + if (msgtype == MESSAGE_TYPE_NOTICE) + return; + + sendto_one_numeric(source_p, ERR_TARGUMODEG, form_str(ERR_TARGUMODEG), + target_p->name, IsSetStrictCallerID(target_p) ? "+g" : "+G"); + + if ((target_p->localClient->last_caller_id_time + ConfigFileEntry.caller_id_wait) < rb_current_time()) + { + sendto_one_numeric(source_p, RPL_TARGNOTIFY, form_str(RPL_TARGNOTIFY), + target_p->name); + + sendto_one(target_p, form_str(RPL_UMODEGMSG), + me.name, target_p->name, source_p->name, + source_p->username, source_p->host, IsSetStrictCallerID(target_p) ? "+g" : "+G"); + + target_p->localClient->last_caller_id_time = rb_current_time(); + } +} + +static bool +add_callerid_accept_for_source(enum message_type msgtype, struct Client *source_p, struct Client *target_p) +{ + /* only do this on source_p's server */ + if (!MyClient(source_p)) + return true; + + /* + * XXX: Controversial? Allow target users to send replies + * through a +g. Rationale is that people can presently use +g + * as a way to taunt users, e.g. harass them and hide behind +g + * as a way of griefing. --nenolod + */ + if(msgtype != MESSAGE_TYPE_NOTICE && + IsSetAnyCallerID(source_p) && + !accept_message(target_p, source_p) && + !IsOper(target_p)) + { + if(rb_dlink_list_length(&source_p->localClient->allow_list) < + (unsigned long)ConfigFileEntry.max_accept) + { + rb_dlinkAddAlloc(target_p, &source_p->localClient->allow_list); + rb_dlinkAddAlloc(source_p, &target_p->on_allow_list); + } + else + { + sendto_one_numeric(source_p, ERR_OWNMODE, + form_str(ERR_OWNMODE), + target_p->name, IsSetStrictCallerID(target_p) ? "+g" : "+G"); + return false; + } + } + + return true; +} + +static void +h_hdl_invite(void *vdata) +{ + hook_data_channel_approval *data = vdata; + struct Client *source_p = data->client; + struct Client *target_p = data->target; + static char errorbuf[BUFSIZE]; + + if (data->approved) + return; + + if (!add_callerid_accept_for_source(MESSAGE_TYPE_PRIVMSG, source_p, target_p)) + { + data->approved = ERR_TARGUMODEG; + return; + } + + if (allow_message(source_p, target_p)) + return; + + snprintf(errorbuf, sizeof errorbuf, form_str(ERR_TARGUMODEG), + target_p->name, IsSetStrictCallerID(target_p) ? "+g" : "+G"); + + data->approved = ERR_TARGUMODEG; + data->error = errorbuf; +} + +static void +h_hdl_privmsg_user(void *vdata) +{ + hook_data_privmsg_user *data = vdata; + enum message_type msgtype = data->msgtype; + struct Client *source_p = data->source_p; + struct Client *target_p = data->target_p; + + if (data->approved) + return; + + if (!add_callerid_accept_for_source(msgtype, source_p, target_p)) + { + data->approved = ERR_TARGUMODEG; + return; + } + + if (allow_message(source_p, target_p)) + return; + + send_callerid_notice(msgtype, source_p, target_p); + + data->approved = ERR_TARGUMODEG; +} + +static mapi_hfn_list_av1 um_callerid_hfnlist[] = { + { "invite", h_hdl_invite }, + { "privmsg_user", h_hdl_privmsg_user }, + { NULL, NULL } +}; + +DECLARE_MODULE_AV2(um_callerid, um_callerid_modinit, um_callerid_moddeinit, + NULL, NULL, um_callerid_hfnlist, NULL, NULL, um_callerid_desc);