[BACK]Return to parse.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

Annotation of ircnowd/src/ngircd/parse.c, Revision 1.1.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