X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Firc-mode.c;h=1cf19afc2bf437f19a2887509e12851c932a7951;hb=40e3daf560799df1d16629b35078979583cb4349;hp=71557201d8d938f4a5ff65416f50eb487f78333d;hpb=a072180c9262f8a1c6bba6b8f0613bccc2863f48;p=ngircd-alex.git diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index 71557201..1cf19afc 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -36,6 +36,8 @@ #include "irc-mode.h" +static void Announce_Client_Hostname PARAMS((CLIENT *Origin, CLIENT *Client)); + static bool Client_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target)); static bool Channel_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin, @@ -215,6 +217,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) /* Validate modes */ x[0] = '\0'; switch (*mode_ptr) { + case 'b': /* Block private msgs */ case 'C': /* Only messages from clients sharing a channel */ case 'i': /* Invisible */ case 's': /* Server messages */ @@ -257,6 +260,15 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); break; + case 'q': /* KICK-protected user */ + if (!set || Client_Type(Client) == CLIENT_SERVER + || Client_OperByMe(Origin)) + x[0] = 'q'; + else + ok = IRC_WriteStrClient(Origin, + ERR_NOPRIVILEGES_MSG, + Client_ID(Origin)); + break; case 'r': /* Restricted (only settable) */ if (set || Client_Type(Client) == CLIENT_SERVER) x[0] = 'r'; @@ -278,9 +290,15 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) ok = IRC_WriteStrClient(Origin, ERR_RESTRICTED_MSG, Client_ID(Origin)); - else + else if (!set || Conf_CloakHostModeX[0] + || Client_Type(Client) == CLIENT_SERVER + || Client_OperByMe(Client)) { x[0] = 'x'; send_RPL_HOSTHIDDEN_MSG = true; + } else + ok = IRC_WriteStrClient(Origin, + ERR_NOPRIVILEGES_MSG, + Client_ID(Origin)); break; default: if (Client_Type(Client) != CLIENT_SERVER) { @@ -351,9 +369,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) Client_ID(Target), the_modes); if (send_RPL_HOSTHIDDEN_MSG) - IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG, - Client_ID(Client), - Client_HostnameCloaked(Client)); + Announce_Client_Hostname(Origin, Client); } LogDebug("%s \"%s\": Mode change, now \"%s\".", Client_TypeText(Target), Client_Mask(Target), @@ -365,6 +381,27 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) } /* Client_Mode */ +/** + * Announce changed client hostname in the network. + * + * @param Client The client of which the hostname changed. + */ +static void +Announce_Client_Hostname(CLIENT *Origin, CLIENT *Client) +{ + assert(Client != NULL); + + /* Inform the client itself */ + IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG, Client_ID(Client), + Client_HostnameCloaked(Client)); + + /* Inform other servers in the network */ + IRC_WriteStrServersPrefixFlag(Origin, Client_ThisServer(), 'M', + "METADATA %s host :%s", Client_ID(Client), + Client_HostnameCloaked(Client)); +} + + static bool Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel) { @@ -418,13 +455,16 @@ static bool Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) { char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], - argadd[CLIENT_PASS_LEN], *mode_ptr; - bool connected, set, skiponce, retval, onchannel, modeok, use_servermode; + argadd[CLIENT_PASS_LEN], *mode_ptr, *o_mode_ptr; + bool connected, set, skiponce, retval, use_servermode, + is_halfop, is_op, is_admin, is_owner, is_machine, is_oper; int mode_arg, arg_arg, mode_arg_count = 0; CLIENT *client; long l; size_t len; + is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false; + if (Channel_IsModeless(Channel)) return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG, Client_ID(Client), Channel_Name(Channel)); @@ -433,10 +473,20 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Req->argc <= 1) return Channel_Mode_Answer_Request(Origin, Channel); - Channel_CheckAdminRights(Channel, Client, Origin, - &onchannel, &modeok, &use_servermode); + /* Check if origin is oper and opers can use mode */ + use_servermode = Conf_OperServerMode; + if(Client_OperByMe(Client) && Conf_OperCanMode) { + is_oper = true; + } + + /* Check if client is a server/service */ + if(Client_Type(Client) == CLIENT_SERVER || + Client_Type(Client) == CLIENT_SERVICE) { + is_machine = true; + } - if (!onchannel && !modeok) + /* Check if client is member of channel or an oper or an server/service */ + if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine) return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG, Client_ID(Origin), Channel_Name(Channel)); @@ -515,21 +565,46 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (arg_arg >= Req->argc) arg_arg = -1; + if(!is_machine) { + o_mode_ptr = Channel_UserModes(Channel, Client); + while( *o_mode_ptr ) { + if ( *o_mode_ptr == 'q') + is_owner = true; + if ( *o_mode_ptr == 'a') + is_admin = true; + if ( *o_mode_ptr == 'o') + is_op = true; + if ( *o_mode_ptr == 'h') + is_halfop = true; + o_mode_ptr++; + } + } + /* Validate modes */ x[0] = '\0'; argadd[0] = '\0'; client = NULL; switch (*mode_ptr) { /* --- Channel modes --- */ + case 'R': /* Registered users only */ + case 's': /* Secret channel */ + case 'z': /* Secure connections only */ + if(!is_oper && !is_machine && !is_owner && + !is_admin && !is_op) { + connected = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), Channel_Name(Channel)); + goto chan_exit; + } case 'i': /* Invite only */ + case 'V': /* Invite disallow */ case 'M': /* Only identified nicks can write */ case 'm': /* Moderated */ case 'n': /* Only members can write */ - case 'R': /* Registered users only */ - case 's': /* Secret channel */ + case 'Q': /* No kicks */ case 't': /* Topic locked */ - case 'z': /* Secure connections only */ - if (modeok) + if(is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) x[0] = *mode_ptr; else connected = IRC_WriteStrClient(Origin, @@ -540,7 +615,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Mode_Limit_Reached(Client, mode_arg_count++)) goto chan_exit; if (!set) { - if (modeok) + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) x[0] = *mode_ptr; else connected = IRC_WriteStrClient(Origin, @@ -550,7 +626,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) break; } if (arg_arg > mode_arg) { - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { Channel_ModeDel(Channel, 'k'); Channel_SetKey(Channel, Req->argv[arg_arg]); @@ -576,7 +653,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Mode_Limit_Reached(Client, mode_arg_count++)) goto chan_exit; if (!set) { - if (modeok) + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) x[0] = *mode_ptr; else connected = IRC_WriteStrClient(Origin, @@ -586,7 +664,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) break; } if (arg_arg > mode_arg) { - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { l = atol(Req->argv[arg_arg]); if (l > 0 && l < 0xFFFF) { Channel_ModeDel(Channel, 'l'); @@ -611,61 +690,82 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) } break; case 'O': /* IRC operators only */ - if (modeok) { + if (set) { /* Only IRC operators are allowed to * set the 'O' channel mode! */ - if (set && !(Client_OperByMe(Client) - || Client_Type(Client) == CLIENT_SERVER)) + if(is_oper || is_machine) + x[0] = 'O'; + else connected = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); - else - x[0] = 'O'; - } else + } else if(is_oper || is_machine || is_owner || + is_admin || is_op) + x[0] = 'O'; + else connected = IRC_WriteStrClient(Origin, - ERR_CHANOPRIVSNEEDED_MSG, - Client_ID(Origin), - Channel_Name(Channel)); - break; + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + break; case 'P': /* Persistent channel */ - if (modeok) { + if (set) { /* Only IRC operators are allowed to * set the 'P' channel mode! */ - if (set && !(Client_OperByMe(Client) - || Client_Type(Client) == CLIENT_SERVER)) + if(is_oper || is_machine) + x[0] = 'P'; + else connected = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin)); - else - x[0] = 'P'; - } else + } else if(is_oper || is_machine || is_owner || + is_admin || is_op) + x[0] = 'P'; + else connected = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel)); break; /* --- Channel user modes --- */ - case 'a': - case 'h': - case 'q': - if (Client_Type(Client) != CLIENT_SERVER) { + case 'q': /* Owner */ + case 'a': /* Channel admin */ + if(!is_oper && !is_machine && !is_owner && !is_admin) { connected = IRC_WriteStrClient(Origin, - ERR_CHANOPRIVSNEEDED_MSG, + ERR_CHANOPPRIVTOOLOW_MSG, Client_ID(Origin), Channel_Name(Channel)); goto chan_exit; } case 'o': /* Channel operator */ + if(!is_oper && !is_machine && !is_owner && + !is_admin && !is_op) { + connected = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + goto chan_exit; + } + case 'h': /* Half Op */ + if(!is_oper && !is_machine && !is_owner && + !is_admin && !is_op) { + connected = IRC_WriteStrClient(Origin, + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + goto chan_exit; + } case 'v': /* Voice */ if (arg_arg > mode_arg) { - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { client = Client_Search(Req->argv[arg_arg]); if (client) x[0] = *mode_ptr; else - connected = IRC_WriteStrClient(Client, + connected = IRC_WriteStrClient(Origin, ERR_NOSUCHNICK_MSG, - Client_ID(Client), + Client_ID(Origin), Req->argv[arg_arg]); } else { connected = IRC_WriteStrClient(Origin, @@ -690,7 +790,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) goto chan_exit; if (arg_arg > mode_arg) { /* modify list */ - if (modeok) { + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { connected = set ? Add_To_List(*mode_ptr, Origin, Client, Channel,