[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     ! 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