X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc-mode.c;h=89a070429afef1b8645e30c64820db12ad26f8f3;hp=79ab2ebe94beaa41b904b01b1493a83d125e5e25;hb=HEAD;hpb=d314c75a37f0132a1a16658494d0f60a0c0083f2 diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index 79ab2ebe..89a07042 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2023 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -206,6 +206,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) case 'b': /* Block private msgs */ case 'C': /* Only messages from clients sharing a channel */ case 'i': /* Invisible */ + case 'I': /* Hide channel list from WHOIS */ case 's': /* Server messages */ case 'w': /* Wallops messages */ x[0] = *mode_ptr; @@ -280,7 +281,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) break; default: if (Client_Type(Client) != CLIENT_SERVER) { - Log(LOG_DEBUG, + LogDebug( "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID(Origin)); @@ -291,7 +292,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) *mode_ptr); x[0] = '\0'; } else { - Log(LOG_DEBUG, + LogDebug( "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...", set ? '+' : '-', *mode_ptr, Client_ID(Origin), Client_ID(Target)); @@ -378,37 +379,44 @@ Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel) char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN]; const char *mode_ptr; - /* Member or not? -- That's the question! */ - if (!Channel_IsMemberOf(Channel, Origin)) - return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG, - Client_ID(Origin), Channel_Name(Channel), Channel_Modes(Channel)); - - /* The sender is a member: generate extended reply */ - strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes)); - mode_ptr = the_modes; - the_args[0] = '\0'; - - while(*mode_ptr) { - switch(*mode_ptr) { - case 'l': - snprintf(argadd, sizeof(argadd), " %lu", Channel_MaxUsers(Channel)); - strlcat(the_args, argadd, sizeof(the_args)); - break; - case 'k': - strlcat(the_args, " ", sizeof(the_args)); - strlcat(the_args, Channel_Key(Channel), sizeof(the_args)); - break; + if (!Channel_IsMemberOf(Channel, Origin)) { + /* Not a member: "simple" mode reply */ + if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG, + Client_ID(Origin), Channel_Name(Channel), + Channel_Modes(Channel))) + return DISCONNECTED; + } else { + /* The sender is a member: generate extended reply */ + strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes)); + mode_ptr = the_modes; + the_args[0] = '\0'; + + while(*mode_ptr) { + switch(*mode_ptr) { + case 'l': + snprintf(argadd, sizeof(argadd), " %lu", + Channel_MaxUsers(Channel)); + strlcat(the_args, argadd, sizeof(the_args)); + break; + case 'k': + strlcat(the_args, " ", sizeof(the_args)); + strlcat(the_args, Channel_Key(Channel), + sizeof(the_args)); + break; + } + mode_ptr++; } - mode_ptr++; + if (the_args[0]) + strlcat(the_modes, the_args, sizeof(the_modes)); + + if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG, + Client_ID(Origin), Channel_Name(Channel), + the_modes)) + return DISCONNECTED; } - if (the_args[0]) - strlcat(the_modes, the_args, sizeof(the_modes)); - if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG, - Client_ID(Origin), Channel_Name(Channel), - the_modes)) - return DISCONNECTED; #ifndef STRICT_RFC + /* Channel creation time */ if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG, Client_ID(Origin), Channel_Name(Channel), Channel_CreationTime(Channel))) @@ -567,11 +575,13 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Client_ID(Origin), Channel_Name(Channel)); goto chan_exit; } + /* fall through */ 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 'N': /* Can't change nick while on this channel */ case 'Q': /* No kicks */ case 't': /* Topic locked */ if(is_oper || is_machine || is_owner || @@ -600,33 +610,43 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Channel_Name(Channel)); break; } - if (arg_arg > mode_arg) { - if (is_oper || is_machine || is_owner || - is_admin || is_op || is_halfop) { - Channel_ModeDel(Channel, 'k'); - Channel_SetKey(Channel, - Req->argv[arg_arg]); - strlcpy(argadd, Channel_Key(Channel), - sizeof(argadd)); - x[0] = *mode_ptr; - } else { + if (arg_arg <= mode_arg) { + if (is_machine) + Log(LOG_ERR, + "Got MODE +k without key for \"%s\" from \"%s\"! Ignored.", + Channel_Name(Channel), Client_ID(Origin)); + else connected = IRC_WriteErrClient(Origin, - ERR_CHANOPRIVSNEEDED_MSG, + ERR_NEEDMOREPARAMS_MSG, + Client_ID(Origin), Req->command); + goto chan_exit; + } + if (!Req->argv[arg_arg][0] || strchr(Req->argv[arg_arg], ' ')) { + if (is_machine) + Log(LOG_ERR, + "Got invalid key on MODE +k for \"%s\" from \"%s\"! Ignored.", + Channel_Name(Channel), Client_ID(Origin)); + else + connected = IRC_WriteErrClient(Origin, + ERR_INVALIDMODEPARAM_MSG, Client_ID(Origin), - Channel_Name(Channel)); - } - Req->argv[arg_arg][0] = '\0'; - arg_arg++; + Channel_Name(Channel), 'k'); + goto chan_exit; + } + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { + Channel_ModeDel(Channel, 'k'); + Channel_SetKey(Channel, Req->argv[arg_arg]); + strlcpy(argadd, Channel_Key(Channel), sizeof(argadd)); + x[0] = *mode_ptr; } else { -#ifdef STRICT_RFC - /* Only send error message in "strict" mode, - * this is how ircd2.11 and others behave ... */ connected = IRC_WriteErrClient(Origin, - ERR_NEEDMOREPARAMS_MSG, - Client_ID(Origin), Req->command); -#endif - goto chan_exit; + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); } + Req->argv[arg_arg][0] = '\0'; + arg_arg++; break; case 'l': /* Member limit */ if (Mode_Limit_Reached(Client, mode_arg_count++)) @@ -642,35 +662,44 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Channel_Name(Channel)); break; } - if (arg_arg > mode_arg) { - 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'); - Channel_SetMaxUsers(Channel, l); - snprintf(argadd, sizeof(argadd), - "%ld", l); - x[0] = *mode_ptr; - } - } else { + if (arg_arg <= mode_arg) { + if (is_machine) + Log(LOG_ERR, + "Got MODE +l without limit for \"%s\" from \"%s\"! Ignored.", + Channel_Name(Channel), Client_ID(Origin)); + else connected = IRC_WriteErrClient(Origin, - ERR_CHANOPRIVSNEEDED_MSG, + ERR_NEEDMOREPARAMS_MSG, + Client_ID(Origin), Req->command); + goto chan_exit; + } + l = atol(Req->argv[arg_arg]); + if (l <= 0 || l >= 0xFFFF) { + if (is_machine) + Log(LOG_ERR, + "Got MODE +l with invalid limit for \"%s\" from \"%s\"! Ignored.", + Channel_Name(Channel), Client_ID(Origin)); + else + connected = IRC_WriteErrClient(Origin, + ERR_INVALIDMODEPARAM_MSG, Client_ID(Origin), - Channel_Name(Channel)); - } - Req->argv[arg_arg][0] = '\0'; - arg_arg++; + Channel_Name(Channel), 'l'); + goto chan_exit; + } + if (is_oper || is_machine || is_owner || + is_admin || is_op || is_halfop) { + Channel_ModeDel(Channel, 'l'); + Channel_SetMaxUsers(Channel, l); + snprintf(argadd, sizeof(argadd), "%ld", l); + x[0] = *mode_ptr; } else { -#ifdef STRICT_RFC - /* Only send error message in "strict" mode, - * this is how ircd2.11 and others behave ... */ connected = IRC_WriteErrClient(Origin, - ERR_NEEDMOREPARAMS_MSG, - Client_ID(Origin), Req->command); -#endif - goto chan_exit; + ERR_CHANOPRIVSNEEDED_MSG, + Client_ID(Origin), + Channel_Name(Channel)); } + Req->argv[arg_arg][0] = '\0'; + arg_arg++; break; case 'O': /* IRC operators only */ if (set) { @@ -712,6 +741,14 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) break; /* --- Channel user modes --- */ case 'q': /* Owner */ + if(!is_oper && !is_machine && !is_owner) { + connected = IRC_WriteErrClient(Origin, + ERR_CHANOPPRIVTOOLOW_MSG, + Client_ID(Origin), + Channel_Name(Channel)); + goto chan_exit; + } + /* fall through */ case 'a': /* Channel admin */ if(!is_oper && !is_machine && !is_owner && !is_admin) { connected = IRC_WriteErrClient(Origin, @@ -720,6 +757,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Channel_Name(Channel)); goto chan_exit; } + /* fall through */ case 'o': /* Channel operator */ if(!is_oper && !is_machine && !is_owner && !is_admin && !is_op) { @@ -729,6 +767,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Channel_Name(Channel)); goto chan_exit; } + /* fall through */ case 'h': /* Half Op */ if(!is_oper && !is_machine && !is_owner && !is_admin && !is_op) { @@ -738,6 +777,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Channel_Name(Channel)); goto chan_exit; } + /* fall through */ case 'v': /* Voice */ if (arg_arg > mode_arg) { if (is_oper || is_machine || is_owner || @@ -814,7 +854,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) break; default: if (Client_Type(Client) != CLIENT_SERVER) { - Log(LOG_DEBUG, + LogDebug( "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID(Origin), Channel_Name(Channel)); @@ -824,7 +864,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) Channel_Name(Channel)); x[0] = '\0'; } else { - Log(LOG_DEBUG, + LogDebug( "Handling unknown mode \"%c%c\" from \"%s\" on %s ...", set ? '+' : '-', *mode_ptr, Client_ID(Origin), Channel_Name(Channel)); @@ -895,7 +935,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Client_Type(Client) == CLIENT_SERVER) { /* MODE requests for local channels from other servers * are definitely invalid! */ - if (Channel_IsLocal(Channel)) { + if (Channel_IsLocal(Channel) && Client != Client_ThisServer()) { Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored."); return CONNECTED; } @@ -1009,15 +1049,15 @@ Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, switch (what) { case 'I': - if (!Channel_AddInvite(Channel, mask, false)) + if (!Channel_AddInvite(Channel, mask, false, Client_ID(Client))) return CONNECTED; break; case 'b': - if (!Channel_AddBan(Channel, mask)) + if (!Channel_AddBan(Channel, mask, Client_ID(Client))) return CONNECTED; break; case 'e': - if (!Channel_AddExcept(Channel, mask)) + if (!Channel_AddExcept(Channel, mask, Client_ID(Client))) return CONNECTED; break; }