Annotation of ircnowd/src/ngircd/parse.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2018 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * IRC command parser and validator.
! 17: */
! 18:
! 19: #include <assert.h>
! 20: #include <stdlib.h>
! 21: #include <string.h>
! 22: #include <strings.h>
! 23:
! 24: #include "ngircd.h"
! 25: #include "conn-func.h"
! 26: #include "conf.h"
! 27: #include "channel.h"
! 28: #include "log.h"
! 29: #include "messages.h"
! 30:
! 31: #include "parse.h"
! 32:
! 33: #include "irc.h"
! 34: #include "irc-cap.h"
! 35: #include "irc-channel.h"
! 36: #ifdef ICONV
! 37: # include "irc-encoding.h"
! 38: #endif
! 39: #include "irc-info.h"
! 40: #include "irc-login.h"
! 41: #include "irc-metadata.h"
! 42: #include "irc-mode.h"
! 43: #include "irc-op.h"
! 44: #include "irc-oper.h"
! 45: #include "irc-server.h"
! 46: #include "irc-write.h"
! 47: #include "numeric.h"
! 48:
! 49: struct _NUMERIC {
! 50: int numeric;
! 51: bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
! 52: };
! 53:
! 54:
! 55: static COMMAND My_Commands[] =
! 56: {
! 57: #define _CMD(name, func, type, min, max, penalty) \
! 58: { (name), (func), (type), (min), (max), (penalty), 0, 0, 0 }
! 59: _CMD("ADMIN", IRC_ADMIN, CLIENT_USER|CLIENT_SERVER, 0, 1, 1),
! 60: _CMD("AWAY", IRC_AWAY, CLIENT_USER, 0, 1, 0),
! 61: _CMD("CAP", IRC_CAP, CLIENT_ANY, 1, 2, 0),
! 62: _CMD("CONNECT", IRC_CONNECT, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 63: #ifdef STRICT_RFC
! 64: _CMD("DIE", IRC_DIE, CLIENT_USER, 0, 0, 0),
! 65: #else
! 66: _CMD("DIE", IRC_DIE, CLIENT_USER, 0, 1, 0),
! 67: #endif
! 68: _CMD("DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 1, 1, 0),
! 69: _CMD("ERROR", IRC_ERROR, CLIENT_ANY, 0, -1, 0),
! 70: _CMD("GLINE", IRC_xLINE, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 71: _CMD("HELP", IRC_HELP, CLIENT_USER, 0, 1, 2),
! 72: _CMD("INFO", IRC_INFO, CLIENT_USER|CLIENT_SERVER, 0, 1, 2),
! 73: _CMD("INVITE", IRC_INVITE, CLIENT_USER|CLIENT_SERVER, 2, 2, 1),
! 74: _CMD("ISON", IRC_ISON, CLIENT_USER, 1, -1, 0),
! 75: _CMD("JOIN", IRC_JOIN, CLIENT_USER|CLIENT_SERVER, 1, 2, 0),
! 76: _CMD("KICK", IRC_KICK, CLIENT_USER|CLIENT_SERVER, 2, 3, 0),
! 77: _CMD("KILL", IRC_KILL, CLIENT_USER|CLIENT_SERVER, 2, 2, 0),
! 78: _CMD("KLINE", IRC_xLINE, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 79: _CMD("LINKS", IRC_LINKS, CLIENT_USER|CLIENT_SERVER, 0, 2, 1),
! 80: _CMD("LIST", IRC_LIST, CLIENT_USER|CLIENT_SERVER, 0, 2, 2),
! 81: _CMD("LUSERS", IRC_LUSERS, CLIENT_USER|CLIENT_SERVER, 0, 2, 1),
! 82: _CMD("METADATA", IRC_METADATA, CLIENT_SERVER, 3, 3, 0),
! 83: _CMD("MODE", IRC_MODE, CLIENT_USER|CLIENT_SERVER, 1, -1, 1),
! 84: _CMD("MOTD", IRC_MOTD, CLIENT_USER|CLIENT_SERVER, 0, 1, 3),
! 85: _CMD("NAMES", IRC_NAMES, CLIENT_USER|CLIENT_SERVER, 0, 2, 1),
! 86: _CMD("NICK", IRC_NICK, CLIENT_ANY, 0, -1, 0),
! 87: _CMD("NJOIN", IRC_NJOIN, CLIENT_SERVER, 2, 2, 0),
! 88: _CMD("NOTICE", IRC_NOTICE, CLIENT_ANY, 0, -1, 0),
! 89: _CMD("OPER", IRC_OPER, CLIENT_USER, 2, 2, 0),
! 90: _CMD("PART", IRC_PART, CLIENT_USER|CLIENT_SERVER, 1, 2, 0),
! 91: _CMD("PASS", IRC_PASS, CLIENT_ANY, 0, -1, 0),
! 92: _CMD("PING", IRC_PING, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 93: _CMD("PONG", IRC_PONG, CLIENT_ANY, 0, -1, 0),
! 94: _CMD("PRIVMSG", IRC_PRIVMSG, CLIENT_USER|CLIENT_SERVER, 0, 2, 0),
! 95: _CMD("QUIT", IRC_QUIT, CLIENT_ANY, 0, 1, 0),
! 96: _CMD("REHASH", IRC_REHASH, CLIENT_USER, 0, 0, 0),
! 97: _CMD("RESTART", IRC_RESTART, CLIENT_USER, 0, 0, 0),
! 98: _CMD("SERVER", IRC_SERVER, CLIENT_ANY, 0, -1, 0),
! 99: _CMD("SERVICE", IRC_SERVICE, CLIENT_ANY, 6, 6, 0),
! 100: _CMD("SERVLIST", IRC_SERVLIST, CLIENT_USER, 0, 2, 1),
! 101: _CMD("SQUERY", IRC_SQUERY, CLIENT_USER|CLIENT_SERVER, 0, 2, 0),
! 102: _CMD("SQUIT", IRC_SQUIT, CLIENT_USER|CLIENT_SERVER, 2, 2, 0),
! 103: _CMD("STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 2, 2),
! 104: _CMD("SVSNICK", IRC_SVSNICK, CLIENT_SERVER, 2, 2, 0),
! 105: _CMD("SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 106: _CMD("TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 1, 1),
! 107: _CMD("TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 1, 2, 1),
! 108: _CMD("TRACE", IRC_TRACE, CLIENT_USER|CLIENT_SERVER, 0, 1, 3),
! 109: _CMD("USER", IRC_USER, CLIENT_ANY, 0, -1, 0),
! 110: _CMD("USERHOST", IRC_USERHOST, CLIENT_USER, 1, -1, 1),
! 111: _CMD("USERS", IRC_USERS, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 112: _CMD("VERSION", IRC_VERSION, CLIENT_USER|CLIENT_SERVER, 0, 1, 1),
! 113: _CMD("WALLOPS", IRC_WALLOPS, CLIENT_USER|CLIENT_SERVER, 1, 1, 0),
! 114: _CMD("WEBIRC", IRC_WEBIRC, CLIENT_UNKNOWN, 4, 5, 0),
! 115: _CMD("WHO", IRC_WHO, CLIENT_USER, 0, 2, 1),
! 116: _CMD("WHOIS", IRC_WHOIS, CLIENT_USER|CLIENT_SERVER, 0, -1, 1),
! 117: _CMD("WHOWAS", IRC_WHOWAS, CLIENT_USER|CLIENT_SERVER, 0, -1, 0),
! 118:
! 119: #ifdef IRCPLUS
! 120: _CMD("CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, -1, 0),
! 121: # ifdef ICONV
! 122: _CMD("CHARCONV", IRC_CHARCONV, CLIENT_USER, 1, 1, 0),
! 123: # endif
! 124: #endif
! 125:
! 126: #ifndef STRICT_RFC
! 127: _CMD("GET", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, -1, 0),
! 128: _CMD("POST", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, -1, 0),
! 129: #endif
! 130: _CMD(NULL, NULL, 0, 0, 0, 0) /* End-Mark */
! 131: #undef _CMD
! 132: };
! 133:
! 134: static void Init_Request PARAMS(( REQUEST *Req ));
! 135:
! 136: static bool Validate_Prefix PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
! 137: static bool Validate_Command PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
! 138: static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
! 139:
! 140: static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
! 141:
! 142: static bool ScrubCTCP PARAMS((char *Request));
! 143:
! 144: /**
! 145: * Return the pointer to the global "IRC command structure".
! 146: * This structure, an array of type "COMMAND" describes all the IRC commands
! 147: * implemented by ngIRCd and how to handle them.
! 148: * @return Pointer to the global command structure.
! 149: */
! 150: GLOBAL COMMAND *
! 151: Parse_GetCommandStruct( void )
! 152: {
! 153: return My_Commands;
! 154: } /* Parse_GetCommandStruct */
! 155:
! 156:
! 157: /**
! 158: * Parse a command ("request") received from a client.
! 159: *
! 160: * This function is called after the connection layer received a valid CR+LF
! 161: * terminated line of text: we assume that this is a valid IRC command and
! 162: * try to do something useful with it :-)
! 163: *
! 164: * All errors are reported to the client from which the command has been
! 165: * received, and if the error is fatal this connection is closed down.
! 166: *
! 167: * This function is able to parse the syntax as described in RFC 2812,
! 168: * section 2.3.
! 169: *
! 170: * @param Idx Index of the connection from which the command has been received.
! 171: * @param Request NULL terminated line of text (the "command").
! 172: * @return CONNECTED on success (valid command or "regular" error), DISCONNECTED
! 173: * if a fatal error occurred and the connection has been shut down.
! 174: */
! 175: GLOBAL bool
! 176: Parse_Request( CONN_ID Idx, char *Request )
! 177: {
! 178: REQUEST req;
! 179: char *start, *ptr;
! 180: bool closed;
! 181:
! 182: assert( Idx >= 0 );
! 183: assert( Request != NULL );
! 184:
! 185: #ifdef SNIFFER
! 186: if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " <- connection %d: '%s'.", Idx, Request );
! 187: #endif
! 188:
! 189: Init_Request( &req );
! 190:
! 191: /* remove leading & trailing whitespace */
! 192: ngt_TrimStr( Request );
! 193:
! 194: if (Conf_ScrubCTCP && ScrubCTCP(Request))
! 195: return true;
! 196:
! 197: if (Request[0] == ':') {
! 198: /* Prefix */
! 199: req.prefix = Request + 1;
! 200: ptr = strchr( Request, ' ' );
! 201: if( ! ptr )
! 202: {
! 203: LogDebug("Connection %d: Parse error: prefix without command!?", Idx);
! 204: return Conn_WriteStr(Idx, "ERROR :Prefix without command");
! 205: }
! 206: *ptr = '\0';
! 207: #ifndef STRICT_RFC
! 208: /* ignore multiple spaces between prefix and command */
! 209: while( *(ptr + 1) == ' ' ) ptr++;
! 210: #endif
! 211: start = ptr + 1;
! 212: }
! 213: else start = Request;
! 214:
! 215: ptr = strchr( start, ' ' );
! 216: if( ptr )
! 217: {
! 218: *ptr = '\0';
! 219: #ifndef STRICT_RFC
! 220: /* ignore multiple spaces between parameters */
! 221: while( *(ptr + 1) == ' ' ) ptr++;
! 222: #endif
! 223: }
! 224: req.command = start;
! 225:
! 226: /* Arguments, Parameters */
! 227: if( ptr )
! 228: {
! 229: start = ptr + 1;
! 230: while( start )
! 231: {
! 232: if( start[0] == ':' )
! 233: {
! 234: req.argv[req.argc] = start + 1;
! 235: ptr = NULL;
! 236: }
! 237: else
! 238: {
! 239: req.argv[req.argc] = start;
! 240: ptr = strchr( start, ' ' );
! 241: if( ptr )
! 242: {
! 243: *ptr = '\0';
! 244: #ifndef STRICT_RFC
! 245: while( *(ptr + 1) == ' ' ) ptr++;
! 246: #endif
! 247: }
! 248: }
! 249:
! 250: req.argc++;
! 251:
! 252: if( start[0] == ':' ) break;
! 253: if( req.argc > 14 ) break;
! 254:
! 255: if( ptr ) start = ptr + 1;
! 256: else start = NULL;
! 257: }
! 258: }
! 259:
! 260: if(!Validate_Prefix(Idx, &req, &closed))
! 261: return !closed;
! 262: if(!Validate_Command(Idx, &req, &closed))
! 263: return !closed;
! 264: if(!Validate_Args(Idx, &req, &closed))
! 265: return !closed;
! 266:
! 267: return Handle_Request(Idx, &req);
! 268: } /* Parse_Request */
! 269:
! 270:
! 271: /**
! 272: * Initialize request structure.
! 273: * @param Req Request structure to be initialized.
! 274: */
! 275: static void
! 276: Init_Request( REQUEST *Req )
! 277: {
! 278: int i;
! 279:
! 280: assert( Req != NULL );
! 281:
! 282: Req->prefix = NULL;
! 283: Req->command = NULL;
! 284: for( i = 0; i < 15; Req->argv[i++] = NULL );
! 285: Req->argc = 0;
! 286: } /* Init_Request */
! 287:
! 288:
! 289: static bool
! 290: Validate_Prefix( CONN_ID Idx, REQUEST *Req, bool *Closed )
! 291: {
! 292: CLIENT *client, *c;
! 293:
! 294: assert( Idx >= 0 );
! 295: assert( Req != NULL );
! 296:
! 297: *Closed = false;
! 298:
! 299: client = Conn_GetClient( Idx );
! 300: assert( client != NULL );
! 301:
! 302: if (!Req->prefix && Client_Type(client) == CLIENT_SERVER
! 303: && !(Conn_Options(Idx) & CONN_RFC1459)
! 304: && strcasecmp(Req->command, "ERROR") != 0
! 305: && strcasecmp(Req->command, "PING") != 0)
! 306: {
! 307: Log(LOG_ERR,
! 308: "Received command without prefix (connection %d, command \"%s\")!?",
! 309: Idx, Req->command);
! 310: if (!Conn_WriteStr(Idx, "ERROR :Prefix missing"))
! 311: *Closed = true;
! 312: return false;
! 313: }
! 314:
! 315: if (!Req->prefix)
! 316: return true;
! 317:
! 318: /* only validate if this connection is already registered */
! 319: if (Client_Type(client) != CLIENT_USER
! 320: && Client_Type(client) != CLIENT_SERVER
! 321: && Client_Type(client) != CLIENT_SERVICE) {
! 322: /* not registered, ignore prefix */
! 323: Req->prefix = NULL;
! 324: return true;
! 325: }
! 326:
! 327: /* check if client in prefix is known */
! 328: c = Client_Search(Req->prefix);
! 329: if (!c) {
! 330: if (Client_Type(client) != CLIENT_SERVER) {
! 331: Log(LOG_ERR,
! 332: "Ignoring command with invalid prefix \"%s\" from \"%s\" (connection %d, command \"%s\")!",
! 333: Req->prefix, Client_ID(client), Idx, Req->command);
! 334: if (!Conn_WriteStr(Idx,
! 335: "ERROR :Invalid prefix \"%s\"",
! 336: Req->prefix))
! 337: *Closed = true;
! 338: IRC_SetPenalty(client, 2);
! 339: } else
! 340: LogDebug("Ignoring command with invalid prefix \"%s\" from \"%s\" (connection %d, command \"%s\")!",
! 341: Req->prefix, Client_ID(client), Idx, Req->command);
! 342: return false;
! 343: }
! 344:
! 345: /* check if the client named in the prefix is expected
! 346: * to come from that direction */
! 347: if (Client_NextHop(c) != client) {
! 348: if (Client_Type(client) != CLIENT_SERVER) {
! 349: Log(LOG_ERR,
! 350: "Spoofed prefix \"%s\" from \"%s\" (connection %d, command \"%s\"), closing connection!",
! 351: Req->prefix, Client_ID(client), Idx, Req->command);
! 352: Conn_Close(Idx, NULL, "Spoofed prefix", true);
! 353: *Closed = true;
! 354: } else {
! 355: Log(LOG_WARNING,
! 356: "Ignoring command with spoofed prefix \"%s\" from \"%s\" (connection %d, command \"%s\")!",
! 357: Req->prefix, Client_ID(client), Idx, Req->command);
! 358: }
! 359: return false;
! 360: }
! 361:
! 362: return true;
! 363: } /* Validate_Prefix */
! 364:
! 365:
! 366: static bool
! 367: Validate_Command( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed )
! 368: {
! 369: assert( Idx >= 0 );
! 370: assert( Req != NULL );
! 371: *Closed = false;
! 372:
! 373: return true;
! 374: } /* Validate_Command */
! 375:
! 376:
! 377: static bool
! 378: #ifdef STRICT_RFC
! 379: Validate_Args(CONN_ID Idx, REQUEST *Req, bool *Closed)
! 380: #else
! 381: Validate_Args(UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed)
! 382: #endif
! 383: {
! 384: #ifdef STRICT_RFC
! 385: int i;
! 386: #endif
! 387:
! 388: *Closed = false;
! 389:
! 390: #ifdef STRICT_RFC
! 391: assert( Idx >= 0 );
! 392: assert( Req != NULL );
! 393:
! 394: /* CR and LF are never allowed in command parameters.
! 395: * But since we do accept lines terminated only with CR or LF in
! 396: * "non-RFC-compliant mode" (besides the correct CR+LF combination),
! 397: * this check can only trigger in "strict RFC" mode; therefore we
! 398: * optimize it away otherwise ... */
! 399: for (i = 0; i < Req->argc; i++) {
! 400: if (strchr(Req->argv[i], '\r') || strchr(Req->argv[i], '\n')) {
! 401: Log(LOG_ERR,
! 402: "Invalid character(s) in parameter (connection %d, command %s)!?",
! 403: Idx, Req->command);
! 404: if (!Conn_WriteStr(Idx,
! 405: "ERROR :Invalid character(s) in parameter!"))
! 406: *Closed = true;
! 407: return false;
! 408: }
! 409: }
! 410: #endif
! 411:
! 412: return true;
! 413: } /* Validate_Args */
! 414:
! 415:
! 416: /* Command is a status code ("numeric") from another server */
! 417: static bool
! 418: Handle_Numeric(CLIENT *client, REQUEST *Req)
! 419: {
! 420: static const struct _NUMERIC Numerics[] = {
! 421: { 5, IRC_Num_ISUPPORT },
! 422: { 20, NULL },
! 423: { 376, IRC_Num_ENDOFMOTD }
! 424: };
! 425: int i, num;
! 426: char str[COMMAND_LEN];
! 427: CLIENT *prefix, *target = NULL;
! 428:
! 429: /* Determine target */
! 430: if (Req->argc > 0) {
! 431: if (strcmp(Req->argv[0], "*") != 0)
! 432: target = Client_Search(Req->argv[0]);
! 433: else
! 434: target = Client_ThisServer();
! 435: }
! 436:
! 437: if (!target) {
! 438: /* Status code without target!? */
! 439: if (Req->argc > 0)
! 440: Log(LOG_WARNING,
! 441: "Unknown target for status code %s: \"%s\"",
! 442: Req->command, Req->argv[0]);
! 443: else
! 444: Log(LOG_WARNING,
! 445: "Unknown target for status code %s!",
! 446: Req->command);
! 447: return true;
! 448: }
! 449: if (target == Client_ThisServer()) {
! 450: /* This server is the target of the numeric */
! 451: num = atoi(Req->command);
! 452:
! 453: for (i = 0; i < (int) C_ARRAY_SIZE(Numerics); i++) {
! 454: if (num == Numerics[i].numeric) {
! 455: if (!Numerics[i].function)
! 456: return CONNECTED;
! 457: return Numerics[i].function(client, Req);
! 458: }
! 459: }
! 460:
! 461: LogDebug("Ignored status code %s from \"%s\".",
! 462: Req->command, Client_ID(client));
! 463: return true;
! 464: }
! 465:
! 466: /* Determine source */
! 467: if (!Req->prefix) {
! 468: Log(LOG_WARNING,
! 469: "Got status code %s from \"%s\" without prefix!?",
! 470: Req->command, Client_ID(client));
! 471: return true;
! 472: }
! 473:
! 474: prefix = Client_Search(Req->prefix);
! 475: if (! prefix) { /* Oops, unknown prefix!? */
! 476: Log(LOG_WARNING, "Got status code %s from unknown source: \"%s\"", Req->command, Req->prefix);
! 477: return true;
! 478: }
! 479:
! 480: /* Forward status code */
! 481: strlcpy(str, Req->command, sizeof(str));
! 482: for (i = 0; i < Req->argc; i++) {
! 483: if (i < Req->argc - 1)
! 484: strlcat(str, " ", sizeof(str));
! 485: else
! 486: strlcat(str, " :", sizeof(str));
! 487: strlcat(str, Req->argv[i], sizeof(str));
! 488: }
! 489: return IRC_WriteStrClientPrefix(target, prefix, "%s", str);
! 490: }
! 491:
! 492: static bool
! 493: Handle_Request( CONN_ID Idx, REQUEST *Req )
! 494: {
! 495: CLIENT *client;
! 496: bool result = CONNECTED;
! 497: int client_type;
! 498: COMMAND *cmd;
! 499:
! 500: assert( Idx >= 0 );
! 501: assert( Req != NULL );
! 502: assert( Req->command != NULL );
! 503:
! 504: client = Conn_GetClient( Idx );
! 505: assert( client != NULL );
! 506:
! 507: /* Numeric? */
! 508: client_type = Client_Type(client);
! 509: if ((client_type == CLIENT_SERVER ||
! 510: client_type == CLIENT_UNKNOWNSERVER)
! 511: && strlen(Req->command) == 3 && atoi(Req->command) > 1)
! 512: return Handle_Numeric(client, Req);
! 513:
! 514: cmd = My_Commands;
! 515: while (cmd->name) {
! 516: if (strcasecmp(Req->command, cmd->name) != 0) {
! 517: cmd++;
! 518: continue;
! 519: }
! 520:
! 521: if (!(client_type & cmd->type)) {
! 522: if (client_type == CLIENT_USER
! 523: && cmd->type & CLIENT_SERVER)
! 524: return IRC_WriteErrClient(client,
! 525: ERR_NOTREGISTEREDSERVER_MSG,
! 526: Client_ID(client));
! 527: else
! 528: return IRC_WriteErrClient(client,
! 529: ERR_NOTREGISTERED_MSG,
! 530: Client_ID(client));
! 531: }
! 532:
! 533: if (cmd->penalty)
! 534: IRC_SetPenalty(client, cmd->penalty);
! 535:
! 536: if (Req->argc < cmd->min_argc ||
! 537: (cmd->max_argc != -1 && Req->argc > cmd->max_argc))
! 538: return IRC_WriteErrClient(client, ERR_NEEDMOREPARAMS_MSG,
! 539: Client_ID(client), Req->command);
! 540:
! 541: /* Command is allowed for this client: call it and count
! 542: * generated bytes in output */
! 543: Conn_ResetWCounter();
! 544: result = (cmd->function)(client, Req);
! 545: cmd->bytes += Conn_WCounter();
! 546:
! 547: /* Adjust counters */
! 548: if (client_type != CLIENT_SERVER)
! 549: cmd->lcount++;
! 550: else
! 551: cmd->rcount++;
! 552:
! 553: /* Return result of command (CONNECTED/DISCONNECTED). */
! 554: return result;
! 555: }
! 556:
! 557: if (client_type != CLIENT_USER &&
! 558: client_type != CLIENT_SERVER &&
! 559: client_type != CLIENT_SERVICE )
! 560: return true;
! 561:
! 562: LogDebug("Connection %d: Unknown command \"%s\", %d %s,%s prefix.",
! 563: Client_Conn( client ), Req->command, Req->argc,
! 564: Req->argc == 1 ? "parameter" : "parameters",
! 565: Req->prefix ? "" : " no" );
! 566:
! 567: /* Unknown command and registered connection: generate error: */
! 568: if (client_type != CLIENT_SERVER)
! 569: result = IRC_WriteErrClient(client, ERR_UNKNOWNCOMMAND_MSG,
! 570: Client_ID(client), Req->command);
! 571:
! 572: return result;
! 573: } /* Handle_Request */
! 574:
! 575:
! 576: /**
! 577: * Check if incoming messages contains CTCP commands and should be dropped.
! 578: *
! 579: * @param Request NULL terminated incoming command.
! 580: * @returns true, when the message should be dropped.
! 581: */
! 582: static bool
! 583: ScrubCTCP(char *Request)
! 584: {
! 585: static const char me_cmd[] = "ACTION ";
! 586: static const char ctcp_char = 0x1;
! 587: bool dropCommand = false;
! 588: char *ptr = Request;
! 589: char *ptrEnd = strchr(Request, '\0');
! 590:
! 591: if (Request[0] == ':' && ptrEnd > ptr)
! 592: ptr++;
! 593:
! 594: while (ptr != ptrEnd && *ptr != ':')
! 595: ptr++;
! 596:
! 597: if ((ptrEnd - ptr) > 1) {
! 598: ptr++;
! 599: if (*ptr == ctcp_char) {
! 600: dropCommand = true;
! 601: ptr++;
! 602: /* allow /me commands */
! 603: if ((size_t)(ptrEnd - ptr) >= strlen(me_cmd)
! 604: && !strncmp(ptr, me_cmd, strlen(me_cmd)))
! 605: dropCommand = false;
! 606: }
! 607: }
! 608: return dropCommand;
! 609: }
! 610:
! 611: /* -eof- */
CVSweb