X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc.c;h=ad8c0506905eca3fdaf5787914be740b7a4b9e21;hp=dbce773b72810972a1f67f50a9f3a68eeda75115;hb=52ccba5d1e8cd2e648cf3c14598332bde6b9910d;hpb=fa15eb169814c1ca434e49464d6f5d150057ae31 diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index dbce773b..ad8c0506 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2015 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 @@ -16,26 +16,27 @@ * IRC commands */ -#include "imp.h" #include #include #include +#include +#include #include "ngircd.h" #include "conn-func.h" #include "conf.h" #include "channel.h" -#include "conn-encoding.h" -#include "defines.h" +#ifdef ICONV +# include "conn-encoding.h" +#endif #include "irc-macros.h" #include "irc-write.h" #include "log.h" #include "match.h" #include "messages.h" #include "parse.h" -#include "tool.h" +#include "op.h" -#include "exp.h" #include "irc.h" static char *Option_String PARAMS((CONN_ID Idx)); @@ -111,7 +112,7 @@ IRC_ERROR(CLIENT *Client, REQUEST *Req) /** * Handler for the IRC "KILL" command. * - * This function implements the IRC command "KILL" wich is used to selectively + * This function implements the IRC command "KILL" which is used to selectively * disconnect clients. It can be used by IRC operators and servers, for example * to "solve" nick collisions after netsplits. See RFC 2812 section 3.7.1. * @@ -127,18 +128,14 @@ IRC_ERROR(CLIENT *Client, REQUEST *Req) GLOBAL bool IRC_KILL(CLIENT *Client, REQUEST *Req) { - CLIENT *prefix, *c; - char reason[COMMAND_LEN], *msg; - CONN_ID my_conn, conn; + CLIENT *prefix; + char reason[COMMAND_LEN]; assert (Client != NULL); assert (Req != NULL); - if (Client_Type(Client) != CLIENT_SERVER && !Client_OperByMe(Client)) - return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, - Client_ID(Client)); - - _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 2) + if (Client_Type(Client) != CLIENT_SERVER && !Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); /* Get prefix (origin); use the client if no prefix is given. */ if (Req->prefix) @@ -168,59 +165,8 @@ IRC_KILL(CLIENT *Client, REQUEST *Req) else strlcpy(reason, Req->argv[1], sizeof(reason)); - /* Inform other servers */ - IRC_WriteStrServersPrefix(Client, prefix, "KILL %s :%s", - Req->argv[0], reason); - - /* Save ID of this connection */ - my_conn = Client_Conn( Client ); - - /* Do we host such a client? */ - c = Client_Search( Req->argv[0] ); - if (c) { - if (Client_Type(c) != CLIENT_USER - && Client_Type(c) != CLIENT_GOTNICK) { - /* Target of this KILL is not a regular user, this is - * invalid! So we ignore this case if we received a - * regular KILL from the network and try to kill the - * client/connection anyway (but log an error!) if the - * origin is the local server. */ - - if (Client != Client_ThisServer()) { - /* Invalid KILL received from remote */ - if (Client_Type(c) == CLIENT_SERVER) - msg = ERR_CANTKILLSERVER_MSG; - else - msg = ERR_NOPRIVILEGES_MSG; - return IRC_WriteStrClient(Client, msg, - Client_ID(Client)); - } - - Log(LOG_ERR, - "Got KILL for invalid client type: %d, \"%s\"!", - Client_Type( c ), Req->argv[0] ); - } - - /* Kill the client NOW: - * - Close the local connection (if there is one), - * - Destroy the CLIENT structure for remote clients. - * Note: Conn_Close() removes the CLIENT structure as well. */ - conn = Client_Conn( c ); - if(conn > NONE) - Conn_Close(conn, NULL, reason, true); - else - Client_Destroy(c, NULL, reason, false); - } - else - Log(LOG_NOTICE, "Client with nick \"%s\" is unknown here.", - Req->argv[0]); - - /* Are we still connected or were we killed, too? */ - if (my_conn > NONE && Conn_GetClient(my_conn)) - return CONNECTED; - else - return DISCONNECTED; -} /* IRC_KILL */ + return IRC_KillClient(Client, prefix, Req->argv[0], reason); +} /** * Handler for the IRC "NOTICE" command. @@ -278,13 +224,6 @@ IRC_TRACE(CLIENT *Client, REQUEST *Req) assert(Client != NULL); assert(Req != NULL); - IRC_SetPenalty(Client, 3); - - /* Bad number of arguments? */ - if (Req->argc > 1) - return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, - Client_ID(Client), Req->command); - _IRC_GET_SENDER_OR_RETURN_(from, Req, Client) _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from) @@ -301,7 +240,7 @@ IRC_TRACE(CLIENT *Client, REQUEST *Req) PACKAGE_VERSION, Client_ID(target), Client_ID(Client_NextHop(target)), Option_String(idx2), - time(NULL) - Conn_StartTime(idx2), + (long)(time(NULL) - Conn_StartTime(idx2)), Conn_SendQ(idx), Conn_SendQ(idx2))) return DISCONNECTED; @@ -329,7 +268,7 @@ IRC_TRACE(CLIENT *Client, REQUEST *Req) return DISCONNECTED; } if (Client_Type(c) == CLIENT_USER - && strchr(Client_Modes(c), 'o')) { + && Client_HasMode(c, 'o')) { /* IRC Operator */ if (!IRC_WriteStrClient(from, RPL_TRACEOPERATOR_MSG, @@ -360,10 +299,6 @@ IRC_HELP(CLIENT *Client, REQUEST *Req) assert(Client != NULL); assert(Req != NULL); - IRC_SetPenalty(Client, 2); - - _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1) - if ((Req->argc == 0 && array_bytes(&Conf_Helptext) > 0) || (Req->argc >= 1 && strcasecmp(Req->argv[0], "Commands") != 0)) { /* Help text available and requested */ @@ -385,6 +320,85 @@ IRC_HELP(CLIENT *Client, REQUEST *Req) return CONNECTED; } /* IRC_HELP */ +/** + * Kill an client identified by its nick name. + * + * Please note that after killig a client, its CLIENT cond CONNECTION + * structures are invalid. So the caller must make sure on its own not to + * access data of probably killed clients after calling this function! + * + * @param Client The client from which the command leading to the KILL has + * been received, or NULL. The KILL will no be forwarded in this + * direction. Only relevant when From is set, too. + * @param From The client from which the command originated, or NULL for + the local server. + * @param Nick The nick name to kill. + * @param Reason Text to send as reason to the client and other servers. + */ +GLOBAL bool +IRC_KillClient(CLIENT *Client, CLIENT *From, const char *Nick, const char *Reason) +{ + const char *msg; + CONN_ID my_conn = NONE, conn; + CLIENT *c; + + assert(Nick != NULL); + assert(Reason != NULL); + + /* Do we know such a client in the network? */ + c = Client_Search(Nick); + if (!c) { + LogDebug("Client with nick \"%s\" is unknown, not forwaring.", Nick); + return CONNECTED; + } + + /* Inform other servers */ + IRC_WriteStrServersPrefix(From ? Client : NULL, + From ? From : Client_ThisServer(), + "KILL %s :%s", Nick, Reason); + + if (Client_Type(c) != CLIENT_USER && Client_Type(c) != CLIENT_GOTNICK) { + /* Target of this KILL is not a regular user, this is + * invalid! So we ignore this case if we received a + * regular KILL from the network and try to kill the + * client/connection anyway (but log an error!) if the + * origin is the local server. */ + + if (Client != Client_ThisServer()) { + /* Invalid KILL received from remote */ + if (Client_Type(c) == CLIENT_SERVER) + msg = ERR_CANTKILLSERVER_MSG; + else + msg = ERR_NOPRIVILEGES_MSG; + return IRC_WriteErrClient(Client, msg, Client_ID(Client)); + } + + Log(LOG_ERR, + "Got KILL for invalid client type: %d, \"%s\"!", + Client_Type(c), Nick); + } + + /* Save ID of this connection */ + if (Client) + my_conn = Client_Conn(Client); + + /* Kill the client NOW: + * - Close the local connection (if there is one), + * - Destroy the CLIENT structure for remote clients. + * Note: Conn_Close() removes the CLIENT structure as well. */ + conn = Client_Conn(c); + if(conn > NONE) + Conn_Close(conn, NULL, Reason, true); + else + Client_Destroy(c, NULL, Reason, false); + + /* Are we still connected or were we killed, too? */ + if (my_conn > NONE && Conn_GetClient(my_conn)) + return CONNECTED; + else + return DISCONNECTED; +} + /** * Send help for a given topic to the client. * @@ -450,6 +464,12 @@ Help(CLIENT *Client, const char *Topic) return CONNECTED; } +/** + * Get pointer to a static string representing the connection "options". + * + * @param Idx Connection index. + * @return Pointer to static (global) string buffer. + */ static char * #ifdef ZLIB Option_String(CONN_ID Idx) @@ -458,18 +478,22 @@ Option_String(UNUSED CONN_ID Idx) #endif { static char option_txt[8]; -#ifdef ZLIB UINT16 options; - options = Conn_Options(Idx); -#endif + assert(Idx != NONE); + options = Conn_Options(Idx); strcpy(option_txt, "F"); /* No idea what this means, but the * original ircd sends it ... */ +#ifdef SSL_SUPPORT + if(options & CONN_SSL) /* SSL encrypted link */ + strlcat(option_txt, "s", sizeof(option_txt)); +#endif #ifdef ZLIB - if(options & CONN_ZIP) /* zlib compression supported. */ - strcat(option_txt, "z"); + if(options & CONN_ZIP) /* zlib compression enabled */ + strlcat(option_txt, "z", sizeof(option_txt)); #endif + LogDebug(" *** %d: %d = %s", Idx, options, option_txt); return option_txt; } /* Option_String */ @@ -490,28 +514,28 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) if (Req->argc == 0) { if (!SendErrors) return CONNECTED; - return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, + return IRC_WriteErrClient(Client, ERR_NORECIPIENT_MSG, Client_ID(Client), Req->command); } if (Req->argc == 1) { if (!SendErrors) return CONNECTED; - return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG, + return IRC_WriteErrClient(Client, ERR_NOTEXTTOSEND_MSG, Client_ID(Client)); } if (Req->argc > 2) { if (!SendErrors) return CONNECTED; - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); } - if (Client_Type(Client) == CLIENT_SERVER) + if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) from = Client_Search(Req->prefix); else from = Client; if (!from) - return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix); #ifdef ICONV @@ -606,7 +630,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) #else if (Client_Type(cl) != ForceType) { #endif - if (SendErrors && !IRC_WriteStrClient( + if (SendErrors && !IRC_WriteErrClient( from, ERR_NOSUCHNICK_MSG,Client_ID(from), currentTarget)) return DISCONNECTED; @@ -627,7 +651,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) !Client_HasMode(from, 'o') && !(Client_Type(from) == CLIENT_SERVER) && !(Client_Type(from) == CLIENT_SERVICE)) { - if (SendErrors && !IRC_WriteStrClient(from, + if (SendErrors && !IRC_WriteErrClient(from, ERR_NONONREG_MSG, Client_ID(from), Client_ID(cl))) return DISCONNECTED; @@ -643,7 +667,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) cl2chan = Channel_NextChannelOf(cl, cl2chan); } if (!cl2chan) { - if (SendErrors && !IRC_WriteStrClient( + if (SendErrors && !IRC_WriteErrClient( from, ERR_NOTONSAMECHANNEL_MSG, Client_ID(from), Client_ID(cl))) return DISCONNECTED; @@ -652,7 +676,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) } if (SendErrors && (Client_Type(Client) != CLIENT_SERVER) - && strchr(Client_Modes(cl), 'a')) { + && Client_HasMode(cl, 'a')) { /* Target is away */ if (!IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from), @@ -683,7 +707,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) } else { if (!SendErrors) return CONNECTED; - if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG, + if (!IRC_WriteErrClient(from, ERR_NOSUCHNICK_MSG, Client_ID(from), currentTarget)) return DISCONNECTED; } @@ -708,10 +732,10 @@ Send_Message_Mask(CLIENT * from, char * command, char * targetMask, cl = NULL; - if (strchr(Client_Modes(from), 'o') == NULL) { + if (!Client_HasMode(from, 'o')) { if (!SendErrors) return true; - return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG, + return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG, Client_ID(from)); } @@ -726,7 +750,7 @@ Send_Message_Mask(CLIENT * from, char * command, char * targetMask, { if (!SendErrors) return true; - return IRC_WriteStrClient(from, ERR_WILDTOPLEVEL, targetMask); + return IRC_WriteErrClient(from, ERR_WILDTOPLEVEL, targetMask); } /* #: hostmask, see RFC 2812, sec. 3.3.1 */