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

Annotation of ircnowd/src/ngircd/irc-login.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:  * Login and logout
        !            17:  */
        !            18:
        !            19: #include <assert.h>
        !            20: #include <ctype.h>
        !            21: #include <stdlib.h>
        !            22: #include <string.h>
        !            23: #include <strings.h>
        !            24: #include <time.h>
        !            25:
        !            26: #include "conn-func.h"
        !            27: #include "conf.h"
        !            28: #include "channel.h"
        !            29: #include "log.h"
        !            30: #include "login.h"
        !            31: #include "messages.h"
        !            32: #include "parse.h"
        !            33: #include "irc.h"
        !            34: #include "irc-macros.h"
        !            35: #include "irc-write.h"
        !            36:
        !            37: #include "irc-login.h"
        !            38:
        !            39: static void Change_Nick PARAMS((CLIENT * Origin, CLIENT * Target, char *NewNick,
        !            40:                                bool InformClient));
        !            41:
        !            42: /**
        !            43:  * Handler for the IRC "PASS" command.
        !            44:  *
        !            45:  * @param Client The client from which this command has been received.
        !            46:  * @param Req Request structure with prefix and all parameters.
        !            47:  * @return CONNECTED or DISCONNECTED.
        !            48:  */
        !            49: GLOBAL bool
        !            50: IRC_PASS( CLIENT *Client, REQUEST *Req )
        !            51: {
        !            52:        char *type, *orig_flags;
        !            53:        int protohigh, protolow;
        !            54:
        !            55:        assert( Client != NULL );
        !            56:        assert( Req != NULL );
        !            57:
        !            58:        /* Return an error if this is not a local client */
        !            59:        if (Client_Conn(Client) <= NONE)
        !            60:                return IRC_WriteErrClient(Client, ERR_UNKNOWNCOMMAND_MSG,
        !            61:                                          Client_ID(Client), Req->command);
        !            62:
        !            63:        if (Client_Type(Client) == CLIENT_UNKNOWN && Req->argc == 1) {
        !            64:                /* Not yet registered "unknown" connection, PASS with one
        !            65:                 * argument: either a regular client, service, or server
        !            66:                 * using the old RFC 1459 section 4.1.1 syntax. */
        !            67:                LogDebug("Connection %d: got PASS command (RFC 1459) ...",
        !            68:                         Client_Conn(Client));
        !            69:        } else if ((Client_Type(Client) == CLIENT_UNKNOWN ||
        !            70:                    Client_Type(Client) == CLIENT_UNKNOWNSERVER) &&
        !            71:                   (Req->argc == 3 || Req->argc == 4)) {
        !            72:                /* Not yet registered "unknown" connection or outgoing server
        !            73:                 * link, PASS with three or four argument: server using the
        !            74:                 * RFC 2813 section 4.1.1 syntax. */
        !            75:                LogDebug("Connection %d: got PASS command (RFC 2813, new server link) ...",
        !            76:                         Client_Conn(Client));
        !            77:        } else if (Client_Type(Client) == CLIENT_UNKNOWN ||
        !            78:                   Client_Type(Client) == CLIENT_UNKNOWNSERVER) {
        !            79:                /* Unregistered connection, but wrong number of arguments: */
        !            80:                return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
        !            81:                                          Client_ID(Client), Req->command);
        !            82:        } else {
        !            83:                /* Registered connection, PASS command is not allowed! */
        !            84:                return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
        !            85:                                          Client_ID(Client));
        !            86:        }
        !            87:
        !            88:        Conn_SetPassword(Client_Conn(Client), Req->argv[0]);
        !            89:
        !            90:        /* Protocol version */
        !            91:        if (Req->argc >= 2 && strlen(Req->argv[1]) >= 4) {
        !            92:                char c2, c4;
        !            93:
        !            94:                c2 = Req->argv[1][2];
        !            95:                c4 = Req->argv[1][4];
        !            96:
        !            97:                Req->argv[1][4] = '\0';
        !            98:                protolow = atoi(&Req->argv[1][2]);
        !            99:                Req->argv[1][2] = '\0';
        !           100:                protohigh = atoi(Req->argv[1]);
        !           101:
        !           102:                Req->argv[1][2] = c2;
        !           103:                Req->argv[1][4] = c4;
        !           104:
        !           105:                Client_SetType(Client, CLIENT_GOTPASS_2813);
        !           106:        } else {
        !           107:                protohigh = protolow = 0;
        !           108:                Client_SetType(Client, CLIENT_GOTPASS);
        !           109:        }
        !           110:
        !           111:        /* Protocol type, see doc/Protocol.txt */
        !           112:        if (Req->argc >= 2 && strlen(Req->argv[1]) > 4)
        !           113:                type = &Req->argv[1][4];
        !           114:        else
        !           115:                type = NULL;
        !           116:
        !           117:        /* Protocol flags/options */
        !           118:        if (Req->argc >= 4)
        !           119:                orig_flags = Req->argv[3];
        !           120:        else
        !           121:                orig_flags = "";
        !           122:
        !           123:        /* Implementation, version and IRC+ flags */
        !           124:        if (Req->argc >= 3) {
        !           125:                char *impl, *ptr, *serverver, *flags;
        !           126:
        !           127:                impl = Req->argv[2];
        !           128:                ptr = strchr(impl, '|');
        !           129:                if (ptr)
        !           130:                        *ptr = '\0';
        !           131:
        !           132:                if (type && strcmp(type, PROTOIRCPLUS) == 0) {
        !           133:                        /* The peer seems to be a server which supports the
        !           134:                         * IRC+ protocol (see doc/Protocol.txt). */
        !           135:                        serverver = ptr ? ptr + 1 : "?";
        !           136:                        flags = strchr(ptr ? serverver : impl, ':');
        !           137:                        if (flags) {
        !           138:                                *flags = '\0';
        !           139:                                flags++;
        !           140:                        } else
        !           141:                                flags = "";
        !           142:                        Log(LOG_INFO,
        !           143:                            "Peer on connection %d announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").",
        !           144:                            Client_Conn(Client), impl, serverver,
        !           145:                            protohigh, protolow, flags);
        !           146:                } else {
        !           147:                        /* The peer seems to be a server supporting the
        !           148:                         * "original" IRC protocol (RFC 2813). */
        !           149:                        if (strchr(orig_flags, 'Z'))
        !           150:                                flags = "Z";
        !           151:                        else
        !           152:                                flags = "";
        !           153:                        Log(LOG_INFO,
        !           154:                            "Peer on connection %d announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").",
        !           155:                            Client_Conn(Client), impl,
        !           156:                            protohigh, protolow, flags);
        !           157:                }
        !           158:                Client_SetFlags(Client, flags);
        !           159:        }
        !           160:
        !           161:        return CONNECTED;
        !           162: } /* IRC_PASS */
        !           163:
        !           164: /**
        !           165:  * Handler for the IRC "NICK" command.
        !           166:  *
        !           167:  * @param Client The client from which this command has been received.
        !           168:  * @param Req Request structure with prefix and all parameters.
        !           169:  * @return CONNECTED or DISCONNECTED.
        !           170:  */
        !           171: GLOBAL bool
        !           172: IRC_NICK( CLIENT *Client, REQUEST *Req )
        !           173: {
        !           174:        CLIENT *intr_c, *target, *c;
        !           175:        CHANNEL *chan;
        !           176:        char *nick, *user, *hostname, *modes, *info;
        !           177:        int token, hops;
        !           178:
        !           179:        assert( Client != NULL );
        !           180:        assert( Req != NULL );
        !           181:
        !           182:        /* Some IRC clients, for example BitchX, send the NICK and USER
        !           183:         * commands in the wrong order ... */
        !           184:        if(Client_Type(Client) == CLIENT_UNKNOWN
        !           185:            || Client_Type(Client) == CLIENT_GOTPASS
        !           186:            || Client_Type(Client) == CLIENT_GOTNICK
        !           187: #ifndef STRICT_RFC
        !           188:            || Client_Type(Client) == CLIENT_GOTUSER
        !           189: #endif
        !           190:            || Client_Type(Client) == CLIENT_USER
        !           191:            || Client_Type(Client) == CLIENT_SERVICE
        !           192:            || (Client_Type(Client) == CLIENT_SERVER && Req->argc == 1))
        !           193:        {
        !           194:                /* User registration or change of nickname */
        !           195:                _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 1)
        !           196:
        !           197:                /* Search "target" client */
        !           198:                if (Client_Type(Client) == CLIENT_SERVER) {
        !           199:                        _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
        !           200:                        target = Client_Search(Req->prefix);
        !           201:                        if (!target)
        !           202:                                return IRC_WriteErrClient(Client,
        !           203:                                                          ERR_NOSUCHNICK_MSG,
        !           204:                                                          Client_ID(Client),
        !           205:                                                          Req->argv[0]);
        !           206:                } else {
        !           207:                        /* Is this a restricted client? */
        !           208:                        if (Client_HasMode(Client, 'r'))
        !           209:                                return IRC_WriteErrClient(Client,
        !           210:                                                          ERR_RESTRICTED_MSG,
        !           211:                                                          Client_ID(Client));
        !           212:                        target = Client;
        !           213:                }
        !           214:
        !           215: #ifndef STRICT_RFC
        !           216:                /* If the clients tries to change to its own nickname we won't
        !           217:                 * do anything. This is how the original ircd behaves and some
        !           218:                 * clients (for example Snak) expect it to be like this.
        !           219:                 * But I doubt that this is "really the right thing" ... */
        !           220:                if (strcmp(Client_ID(target), Req->argv[0]) == 0)
        !           221:                        return CONNECTED;
        !           222: #endif
        !           223:
        !           224:                /* Check that the new nickname is available. Special case:
        !           225:                 * the client only changes from/to upper to lower case. */
        !           226:                if (strcasecmp(Client_ID(target), Req->argv[0]) != 0) {
        !           227:                        if (!Client_CheckNick(target, Req->argv[0]))
        !           228:                                return CONNECTED;
        !           229:                }
        !           230:
        !           231:                if (Client_Type(target) != CLIENT_USER &&
        !           232:                    Client_Type(target) != CLIENT_SERVICE &&
        !           233:                    Client_Type(target) != CLIENT_SERVER) {
        !           234:                        /* New client */
        !           235:                        LogDebug("Connection %d: got valid NICK command ...",
        !           236:                             Client_Conn( Client ));
        !           237:
        !           238:                        /* Register new nickname of this client */
        !           239:                        Client_SetID( target, Req->argv[0] );
        !           240:
        !           241: #ifndef STRICT_RFC
        !           242:                        if (Conf_AuthPing) {
        !           243: #ifdef HAVE_ARC4RANDOM
        !           244:                                Conn_SetAuthPing(Client_Conn(Client), arc4random());
        !           245: #else
        !           246:                                Conn_SetAuthPing(Client_Conn(Client), rand());
        !           247: #endif
        !           248:                                Conn_WriteStr(Client_Conn(Client), "PING :%ld",
        !           249:                                        Conn_GetAuthPing(Client_Conn(Client)));
        !           250:                                LogDebug("Connection %d: sent AUTH PING %ld ...",
        !           251:                                        Client_Conn(Client),
        !           252:                                        Conn_GetAuthPing(Client_Conn(Client)));
        !           253:                        }
        !           254: #endif
        !           255:
        !           256:                        /* If we received a valid USER command already then
        !           257:                         * register the new client! */
        !           258:                        if( Client_Type( Client ) == CLIENT_GOTUSER )
        !           259:                                return Login_User( Client );
        !           260:                        else
        !           261:                                Client_SetType( Client, CLIENT_GOTNICK );
        !           262:                } else {
        !           263:                        /* Nickname change */
        !           264:
        !           265:                        /* Check that the user isn't on any channels set +N */
        !           266:                        if(Client_Type(Client) == CLIENT_USER &&
        !           267:                           !Client_HasMode(Client, 'o')) {
        !           268:                                chan = Channel_First();
        !           269:                                while (chan) {
        !           270:                                        if(Channel_HasMode(chan, 'N') &&
        !           271:                                           Channel_IsMemberOf(chan, Client))
        !           272:                                                return IRC_WriteErrClient(Client,
        !           273:                                                                          ERR_NONICKCHANGE_MSG,
        !           274:                                                                          Client_ID(Client),
        !           275:                                                                          Channel_Name(chan));
        !           276:                                        chan = Channel_Next(chan);
        !           277:                                }
        !           278:                        }
        !           279:
        !           280:                        Change_Nick(Client, target, Req->argv[0],
        !           281:                                    Client_Type(Client) == CLIENT_USER ? true : false);
        !           282:                        IRC_SetPenalty(target, 2);
        !           283:                }
        !           284:
        !           285:                return CONNECTED;
        !           286:        } else if(Client_Type(Client) == CLIENT_SERVER ||
        !           287:                  Client_Type(Client) == CLIENT_SERVICE) {
        !           288:                /* Server or service introduces new client */
        !           289:
        !           290:                /* Bad number of parameters? */
        !           291:                if (Req->argc != 2 && Req->argc != 7)
        !           292:                        return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
        !           293:                                                  Client_ID(Client), Req->command);
        !           294:
        !           295:                if (Req->argc >= 7) {
        !           296:                        /* RFC 2813 compatible syntax */
        !           297:                        nick = Req->argv[0];
        !           298:                        hops = atoi(Req->argv[1]);
        !           299:                        user = Req->argv[2];
        !           300:                        hostname = Req->argv[3];
        !           301:                        token = atoi(Req->argv[4]);
        !           302:                        modes = Req->argv[5] + 1;
        !           303:                        info = Req->argv[6];
        !           304:                } else {
        !           305:                        /* RFC 1459 compatible syntax */
        !           306:                        nick = Req->argv[0];
        !           307:                        hops = 1;
        !           308:                        user = Req->argv[0];
        !           309:                        hostname = Client_ID(Client);
        !           310:                        token = atoi(Req->argv[1]);
        !           311:                        modes = "";
        !           312:                        info = Req->argv[0];
        !           313:                }
        !           314:
        !           315:                c = Client_Search(nick);
        !           316:                if(c) {
        !           317:                        /*
        !           318:                         * the new nick is already present on this server:
        !           319:                         * the new and the old one have to be disconnected now.
        !           320:                         */
        !           321:                        Log(LOG_ERR,
        !           322:                            "Server %s introduces already registered nick \"%s\"!",
        !           323:                            Client_ID(Client), Req->argv[0]);
        !           324:                        return IRC_KillClient(Client, NULL, Req->argv[0],
        !           325:                                              "Nick collision");
        !           326:                }
        !           327:
        !           328:                /* Find the Server this client is connected to */
        !           329:                intr_c = Client_GetFromToken(Client, token);
        !           330:                if (!intr_c) {
        !           331:                        Log(LOG_ERR,
        !           332:                            "Server %s introduces nick \"%s\" on unknown server!?",
        !           333:                            Client_ID(Client), Req->argv[0]);
        !           334:                        return IRC_KillClient(Client, NULL, Req->argv[0],
        !           335:                                              "Unknown server");
        !           336:                }
        !           337:
        !           338:                c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname,
        !           339:                                         token, modes, info, true);
        !           340:                if (!c) {
        !           341:                        /* Out of memory, we need to disconnect client to keep
        !           342:                         * network state consistent! */
        !           343:                        Log(LOG_ALERT,
        !           344:                            "Can't create client structure! (on connection %d)",
        !           345:                            Client_Conn(Client));
        !           346:                        return IRC_KillClient(Client, NULL, Req->argv[0],
        !           347:                                              "Server error");
        !           348:                }
        !           349:
        !           350:                /* RFC 2813: client is now fully registered, inform all the
        !           351:                 * other servers about the new user.
        !           352:                 * RFC 1459: announce the new client only after receiving the
        !           353:                 * USER command, first we need more information! */
        !           354:                if (Req->argc < 7) {
        !           355:                        LogDebug("Client \"%s\" is being registered (RFC 1459) ...",
        !           356:                                 Client_Mask(c));
        !           357:                        Client_SetType(c, CLIENT_GOTNICK);
        !           358:                } else
        !           359:                        Client_Introduce(Client, c, CLIENT_USER);
        !           360:
        !           361:                return CONNECTED;
        !           362:        }
        !           363:        else
        !           364:                return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
        !           365:                                          Client_ID(Client));
        !           366: } /* IRC_NICK */
        !           367:
        !           368: /**
        !           369:  * Handler for the IRC "SVSNICK" command.
        !           370:  *
        !           371:  * @param Client The client from which this command has been received.
        !           372:  * @param Req Request structure with prefix and all parameters.
        !           373:  * @return CONNECTED or DISCONNECTED.
        !           374:  */
        !           375: GLOBAL bool
        !           376: IRC_SVSNICK(CLIENT *Client, REQUEST *Req)
        !           377: {
        !           378:        CLIENT *from, *target;
        !           379:
        !           380:        assert(Client != NULL);
        !           381:        assert(Req != NULL);
        !           382:
        !           383:        _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
        !           384:
        !           385:        /* Search the originator */
        !           386:        from = Client_Search(Req->prefix);
        !           387:        if (!from)
        !           388:                from = Client;
        !           389:
        !           390:        /* Search the target */
        !           391:        target = Client_Search(Req->argv[0]);
        !           392:        if (!target || Client_Type(target) != CLIENT_USER)
        !           393:                return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
        !           394:                                          Client_ID(Client), Req->argv[0]);
        !           395:
        !           396:        if (Client_Conn(target) <= NONE) {
        !           397:                /* We have to forward the message to the server handling
        !           398:                 * this user; this is required to make sure all servers
        !           399:                 * in the network do follow the nick name change! */
        !           400:                return IRC_WriteStrClientPrefix(Client_NextHop(target), from,
        !           401:                                                "SVSNICK %s %s",
        !           402:                                                Req->argv[0], Req->argv[1]);
        !           403:        }
        !           404:
        !           405:        /* Make sure that the new nickname is valid */
        !           406:        if (!Client_CheckNick(from, Req->argv[1]))
        !           407:                return CONNECTED;
        !           408:
        !           409:        Change_Nick(from, target, Req->argv[1], true);
        !           410:        return CONNECTED;
        !           411: }
        !           412:
        !           413: /**
        !           414:  * Handler for the IRC "USER" command.
        !           415:  *
        !           416:  * @param Client The client from which this command has been received.
        !           417:  * @param Req Request structure with prefix and all parameters.
        !           418:  * @return CONNECTED or DISCONNECTED.
        !           419:  */
        !           420: GLOBAL bool
        !           421: IRC_USER(CLIENT * Client, REQUEST * Req)
        !           422: {
        !           423:        CLIENT *c;
        !           424:        char *ptr;
        !           425:
        !           426:        assert(Client != NULL);
        !           427:        assert(Req != NULL);
        !           428:
        !           429:        if (Client_Type(Client) == CLIENT_GOTNICK ||
        !           430: #ifndef STRICT_RFC
        !           431:            Client_Type(Client) == CLIENT_UNKNOWN ||
        !           432: #endif
        !           433:            Client_Type(Client) == CLIENT_GOTPASS)
        !           434:        {
        !           435:                /* New connection */
        !           436:                _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4)
        !           437:
        !           438:                /* User name: only alphanumeric characters and limited
        !           439:                   punctuation is allowed.*/
        !           440:                ptr = Req->argv[0];
        !           441:                while (*ptr) {
        !           442:                        if (!isalnum((int)*ptr) &&
        !           443:                            *ptr != '+' && *ptr != '-' && *ptr != '@' &&
        !           444:                            *ptr != '.' && *ptr != '_') {
        !           445:                                Conn_Close(Client_Conn(Client), NULL,
        !           446:                                           "Invalid user name", true);
        !           447:                                return DISCONNECTED;
        !           448:                        }
        !           449:                        ptr++;
        !           450:                }
        !           451:
        !           452:                /* Save the received username for authentication, and use
        !           453:                 * it up to the first '@' as default user name (like ircd2.11,
        !           454:                 * bahamut, ircd-seven, ...), prefixed with '~', if needed: */
        !           455:                Client_SetOrigUser(Client, Req->argv[0]);
        !           456:                ptr = strchr(Req->argv[0], '@');
        !           457:                if (ptr)
        !           458:                        *ptr = '\0';
        !           459: #ifdef IDENTAUTH
        !           460:                ptr = Client_User(Client);
        !           461:                if (!ptr || !*ptr || *ptr == '~')
        !           462:                        Client_SetUser(Client, Req->argv[0], false);
        !           463: #else
        !           464:                Client_SetUser(Client, Req->argv[0], false);
        !           465: #endif
        !           466:
        !           467:                /* "Real name" or user info text: Don't set it to the empty
        !           468:                 * string, the original ircd can't deal with such "real names"
        !           469:                 * (e. g. "USER user * * :") ... */
        !           470:                if (*Req->argv[3])
        !           471:                        Client_SetInfo(Client, Req->argv[3]);
        !           472:                else
        !           473:                        Client_SetInfo(Client, "-");
        !           474:
        !           475:                LogDebug("Connection %d: got valid USER command ...",
        !           476:                    Client_Conn(Client));
        !           477:                if (Client_Type(Client) == CLIENT_GOTNICK)
        !           478:                        return Login_User(Client);
        !           479:                else
        !           480:                        Client_SetType(Client, CLIENT_GOTUSER);
        !           481:                return CONNECTED;
        !           482:
        !           483:        } else if (Client_Type(Client) == CLIENT_SERVER ||
        !           484:                   Client_Type(Client) == CLIENT_SERVICE) {
        !           485:                /* Server/service updating an user */
        !           486:                _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4)
        !           487:                _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
        !           488:
        !           489:                c = Client_Search(Req->prefix);
        !           490:                if (!c)
        !           491:                        return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
        !           492:                                                  Client_ID(Client),
        !           493:                                                  Req->prefix);
        !           494:
        !           495:                Client_SetUser(c, Req->argv[0], true);
        !           496:                Client_SetOrigUser(c, Req->argv[0]);
        !           497:                Client_SetHostname(c, Req->argv[1]);
        !           498:                Client_SetInfo(c, Req->argv[3]);
        !           499:
        !           500:                LogDebug("Connection %d: got valid USER command for \"%s\".",
        !           501:                         Client_Conn(Client), Client_Mask(c));
        !           502:
        !           503:                /* RFC 1459 style user registration?
        !           504:                 * Introduce client to network: */
        !           505:                if (Client_Type(c) == CLIENT_GOTNICK)
        !           506:                        Client_Introduce(Client, c, CLIENT_USER);
        !           507:
        !           508:                return CONNECTED;
        !           509:        } else if (Client_Type(Client) == CLIENT_USER) {
        !           510:                /* Already registered connection */
        !           511:                return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
        !           512:                                          Client_ID(Client));
        !           513:        } else {
        !           514:                /* Unexpected/invalid connection state? */
        !           515:                return IRC_WriteErrClient(Client, ERR_NOTREGISTERED_MSG,
        !           516:                                          Client_ID(Client));
        !           517:        }
        !           518: } /* IRC_USER */
        !           519:
        !           520: /**
        !           521:  * Handler for the IRC "SERVICE" command.
        !           522:  *
        !           523:  * At the moment ngIRCd doesn't support directly linked services, so this
        !           524:  * function returns ERR_ERRONEUSNICKNAME when the SERVICE command has not been
        !           525:  * received from a peer server.
        !           526:  *
        !           527:  * @param Client The client from which this command has been received.
        !           528:  * @param Req Request structure with prefix and all parameters.
        !           529:  * @return CONNECTED or DISCONNECTED.
        !           530:  */
        !           531: GLOBAL bool
        !           532: IRC_SERVICE(CLIENT *Client, REQUEST *Req)
        !           533: {
        !           534:        CLIENT *c, *intr_c;
        !           535:        char *nick, *user, *host, *info, *modes, *ptr;
        !           536:        int token, hops;
        !           537:
        !           538:        assert(Client != NULL);
        !           539:        assert(Req != NULL);
        !           540:
        !           541:        if (Client_Type(Client) != CLIENT_GOTPASS &&
        !           542:            Client_Type(Client) != CLIENT_SERVER)
        !           543:                return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
        !           544:                                          Client_ID(Client));
        !           545:
        !           546:        if (Client_Type(Client) != CLIENT_SERVER)
        !           547:                return IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
        !           548:                                  Client_ID(Client), Req->argv[0]);
        !           549:
        !           550:        nick = Req->argv[0];
        !           551:        user = NULL; host = NULL;
        !           552:        token = atoi(Req->argv[1]);
        !           553:        hops = atoi(Req->argv[4]);
        !           554:        info = Req->argv[5];
        !           555:
        !           556:        /* Validate service name ("nickname") */
        !           557:        c = Client_Search(nick);
        !           558:        if(c) {
        !           559:                /* Nickname collision: disconnect (KILL) both clients! */
        !           560:                Log(LOG_ERR,
        !           561:                    "Server %s introduces already registered service \"%s\"!",
        !           562:                    Client_ID(Client), nick);
        !           563:                return IRC_KillClient(Client, NULL, nick, "Nick collision");
        !           564:        }
        !           565:
        !           566:        /* Get the server to which the service is connected */
        !           567:        intr_c = Client_GetFromToken(Client, token);
        !           568:        if (! intr_c) {
        !           569:                Log(LOG_ERR,
        !           570:                    "Server %s introduces service \"%s\" on unknown server!?",
        !           571:                    Client_ID(Client), nick);
        !           572:                return IRC_KillClient(Client, NULL, nick, "Unknown server");
        !           573:        }
        !           574:
        !           575:        /* Get user and host name */
        !           576:        ptr = strchr(nick, '@');
        !           577:        if (ptr) {
        !           578:                *ptr = '\0';
        !           579:                host = ++ptr;
        !           580:        }
        !           581:        if (!host)
        !           582:                host = Client_Hostname(intr_c);
        !           583:        ptr = strchr(nick, '!');
        !           584:        if (ptr) {
        !           585:                *ptr = '\0';
        !           586:                user = ++ptr;
        !           587:        }
        !           588:        if (!user)
        !           589:                user = nick;
        !           590:
        !           591:        /* According to RFC 2812/2813 parameter 4 <type> "is currently reserved
        !           592:         * for future usage"; but we use it to transfer the modes and check
        !           593:         * that the first character is a '+' sign and ignore it otherwise. */
        !           594:        modes = (Req->argv[3][0] == '+') ? ++Req->argv[3] : "";
        !           595:
        !           596:        c = Client_NewRemoteUser(intr_c, nick, hops, user, host,
        !           597:                                 token, modes, info, true);
        !           598:        if (! c) {
        !           599:                /* Couldn't create client structure, so KILL the service to
        !           600:                 * keep network status consistent ... */
        !           601:                Log(LOG_ALERT,
        !           602:                    "Can't create client structure! (on connection %d)",
        !           603:                    Client_Conn(Client));
        !           604:                return IRC_KillClient(Client, NULL, nick, "Server error");
        !           605:        }
        !           606:
        !           607:        Client_Introduce(Client, c, CLIENT_SERVICE);
        !           608:        return CONNECTED;
        !           609: } /* IRC_SERVICE */
        !           610:
        !           611: /**
        !           612:  * Handler for the IRC "WEBIRC" command.
        !           613:  *
        !           614:  * @param Client The client from which this command has been received.
        !           615:  * @param Req Request structure with prefix and all parameters.
        !           616:  * @return CONNECTED or DISCONNECTED.
        !           617:  */
        !           618: GLOBAL bool
        !           619: IRC_WEBIRC(CLIENT *Client, REQUEST *Req)
        !           620: {
        !           621:        if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0)
        !           622:                return IRC_WriteErrClient(Client, ERR_PASSWDMISMATCH_MSG,
        !           623:                                          Client_ID(Client));
        !           624:
        !           625:        LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s",
        !           626:                 Client_Conn(Client), Req->argv[1], Req->argv[2], Req->argv[3]);
        !           627:
        !           628:        Client_SetUser(Client, Req->argv[1], true);
        !           629:        Client_SetOrigUser(Client, Req->argv[1]);
        !           630:        if (Conf_DNS)
        !           631:                Client_SetHostname(Client, Req->argv[2]);
        !           632:        else
        !           633:                Client_SetHostname(Client, Req->argv[3]);
        !           634:        Client_SetIPAText(Client, Req->argv[3]);
        !           635:
        !           636:        return CONNECTED;
        !           637: } /* IRC_WEBIRC */
        !           638:
        !           639: /**
        !           640:  * Handler for the IRC "QUIT" command.
        !           641:  *
        !           642:  * @param Client The client from which this command has been received.
        !           643:  * @param Req Request structure with prefix and all parameters.
        !           644:  * @return CONNECTED or DISCONNECTED.
        !           645:  */
        !           646: GLOBAL bool
        !           647: IRC_QUIT( CLIENT *Client, REQUEST *Req )
        !           648: {
        !           649:        CLIENT *target;
        !           650:        char quitmsg[COMMAND_LEN];
        !           651:
        !           652:        assert(Client != NULL);
        !           653:        assert(Req != NULL);
        !           654:
        !           655:        if (Req->argc == 1)
        !           656:                strlcpy(quitmsg, Req->argv[0], sizeof quitmsg);
        !           657:
        !           658:        if (Client_Type(Client) == CLIENT_SERVER) {
        !           659:                /* Server */
        !           660:                _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
        !           661:
        !           662:                target = Client_Search(Req->prefix);
        !           663:                if (!target) {
        !           664:                        Log(LOG_WARNING,
        !           665:                            "Got QUIT from %s for unknown client!?",
        !           666:                            Client_ID(Client));
        !           667:                        return CONNECTED;
        !           668:                }
        !           669:
        !           670:                if (target != Client) {
        !           671:                        Client_Destroy(target, "Got QUIT command",
        !           672:                                       Req->argc == 1 ? quitmsg : NULL, true);
        !           673:                        return CONNECTED;
        !           674:                } else {
        !           675:                        Conn_Close(Client_Conn(Client), "Got QUIT command",
        !           676:                                   Req->argc == 1 ? quitmsg : NULL, true);
        !           677:                        return DISCONNECTED;
        !           678:                }
        !           679:        } else {
        !           680:                if (Req->argc == 1 && quitmsg[0] != '\"') {
        !           681:                        /* " " to avoid confusion */
        !           682:                        strlcpy(quitmsg, "\"", sizeof quitmsg);
        !           683:                        strlcat(quitmsg, Req->argv[0], sizeof quitmsg-1);
        !           684:                        strlcat(quitmsg, "\"", sizeof quitmsg );
        !           685:                }
        !           686:
        !           687:                /* User, Service, or not yet registered */
        !           688:                Conn_Close(Client_Conn(Client), "Got QUIT command",
        !           689:                           Req->argc == 1 ? quitmsg : NULL, true);
        !           690:
        !           691:                return DISCONNECTED;
        !           692:        }
        !           693: } /* IRC_QUIT */
        !           694:
        !           695: #ifndef STRICT_RFC
        !           696:
        !           697: /**
        !           698:  * Handler for HTTP command, e.g. GET and POST
        !           699:  *
        !           700:  * We handle these commands here to avoid the quite long timeout when
        !           701:  * some user tries to access this IRC daemon using an web browser ...
        !           702:  *
        !           703:  * @param Client The client from which this command has been received.
        !           704:  * @param Req Request structure with prefix and all parameters.
        !           705:  * @return CONNECTED or DISCONNECTED.
        !           706:  */
        !           707: GLOBAL bool
        !           708: IRC_QUIT_HTTP( CLIENT *Client, REQUEST *Req )
        !           709: {
        !           710:        Req->argc = 1;
        !           711:        Req->argv[0] = "Oops, HTTP request received? This is IRC!";
        !           712:        return IRC_QUIT(Client, Req);
        !           713: } /* IRC_QUIT_HTTP */
        !           714:
        !           715: #endif
        !           716:
        !           717: /**
        !           718:  * Handler for the IRC "PING" command.
        !           719:  *
        !           720:  * @param Client The client from which this command has been received.
        !           721:  * @param Req Request structure with prefix and all parameters.
        !           722:  * @return CONNECTED or DISCONNECTED.
        !           723:  */
        !           724: GLOBAL bool
        !           725: IRC_PING(CLIENT *Client, REQUEST *Req)
        !           726: {
        !           727:        CLIENT *target, *from;
        !           728:
        !           729:        assert(Client != NULL);
        !           730:        assert(Req != NULL);
        !           731:
        !           732:        if (Req->argc < 1)
        !           733:                return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG,
        !           734:                                          Client_ID(Client));
        !           735: #ifdef STRICT_RFC
        !           736:        /* Don't ignore additional arguments when in "strict" mode */
        !           737:        _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
        !           738: #endif
        !           739:
        !           740:        if (Req->argc > 1) {
        !           741:                /* A target has been specified ... */
        !           742:                target = Client_Search(Req->argv[1]);
        !           743:
        !           744:                if (!target || Client_Type(target) != CLIENT_SERVER)
        !           745:                        return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
        !           746:                                        Client_ID(Client), Req->argv[1]);
        !           747:
        !           748:                if (target != Client_ThisServer()) {
        !           749:                        /* Ok, we have to forward the PING */
        !           750:                        if (Client_Type(Client) == CLIENT_SERVER) {
        !           751:                                _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
        !           752:                                from = Client_Search(Req->prefix);
        !           753:                        } else
        !           754:                                from = Client;
        !           755:                        if (!from)
        !           756:                                return IRC_WriteErrClient(Client,
        !           757:                                                ERR_NOSUCHSERVER_MSG,
        !           758:                                                Client_ID(Client), Req->prefix);
        !           759:
        !           760:                        return IRC_WriteStrClientPrefix(target, from,
        !           761:                                        "PING %s :%s", Req->argv[0],
        !           762:                                        Req->argv[1] );
        !           763:                }
        !           764:        }
        !           765:
        !           766:        if (Client_Type(Client) == CLIENT_SERVER) {
        !           767:                if (Req->prefix)
        !           768:                        from = Client_Search(Req->prefix);
        !           769:                else
        !           770:                        from = Client;
        !           771:        } else
        !           772:                from = Client_ThisServer();
        !           773:        if (!from)
        !           774:                return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
        !           775:                                        Client_ID(Client), Req->prefix);
        !           776:
        !           777:        Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...",
        !           778:            Client_Conn(Client));
        !           779:
        !           780: #ifdef STRICT_RFC
        !           781:        return IRC_WriteStrClient(Client, "PONG %s :%s",
        !           782:                Client_ID(from), Client_ID(Client));
        !           783: #else
        !           784:        /* Some clients depend on the argument being returned in the PONG
        !           785:         * reply (not mentioned in any RFC, though) */
        !           786:        return IRC_WriteStrClient(Client, "PONG %s :%s",
        !           787:                Client_ID(from), Req->argv[0]);
        !           788: #endif
        !           789: } /* IRC_PING */
        !           790:
        !           791: /**
        !           792:  * Handler for the IRC "PONG" command.
        !           793:  *
        !           794:  * @param Client The client from which this command has been received.
        !           795:  * @param Req Request structure with prefix and all parameters.
        !           796:  * @return CONNECTED or DISCONNECTED.
        !           797:  */
        !           798: GLOBAL bool
        !           799: IRC_PONG(CLIENT *Client, REQUEST *Req)
        !           800: {
        !           801:        CLIENT *target, *from;
        !           802:        CONN_ID conn;
        !           803: #ifndef STRICT_RFC
        !           804:        long auth_ping;
        !           805: #endif
        !           806:        char *s;
        !           807:
        !           808:        assert(Client != NULL);
        !           809:        assert(Req != NULL);
        !           810:
        !           811:        /* Wrong number of arguments? */
        !           812:        if (Req->argc < 1) {
        !           813:                if (Client_Type(Client) == CLIENT_USER)
        !           814:                        return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG,
        !           815:                                                  Client_ID(Client));
        !           816:                else
        !           817:                        return CONNECTED;
        !           818:        }
        !           819:        if (Client_Type(Client) == CLIENT_USER) {
        !           820:                _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
        !           821:        }
        !           822:
        !           823:        /* Forward? */
        !           824:        if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) {
        !           825:                _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
        !           826:
        !           827:                target = Client_Search(Req->argv[0]);
        !           828:                if (!target)
        !           829:                        return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
        !           830:                                        Client_ID(Client), Req->argv[0]);
        !           831:
        !           832:                from = Client_Search(Req->prefix);
        !           833:
        !           834:                if (target != Client_ThisServer() && target != from) {
        !           835:                        /* Ok, we have to forward the message. */
        !           836:                        if (!from)
        !           837:                                return IRC_WriteErrClient(Client,
        !           838:                                                ERR_NOSUCHSERVER_MSG,
        !           839:                                                Client_ID(Client), Req->prefix);
        !           840:
        !           841:                        if (Client_Type(Client_NextHop(target)) != CLIENT_SERVER)
        !           842:                                s = Client_ID(from);
        !           843:                        else
        !           844:                                s = Req->argv[0];
        !           845:                        return IRC_WriteStrClientPrefix(target, from,
        !           846:                                 "PONG %s :%s", s, Req->argv[1]);
        !           847:                }
        !           848:        }
        !           849:
        !           850:        /* The connection timestamp has already been updated when the data has
        !           851:         * been read from so socket, so we don't need to update it here. */
        !           852:
        !           853:        conn = Client_Conn(Client);
        !           854:
        !           855: #ifndef STRICT_RFC
        !           856:        /* Check authentication PING-PONG ... */
        !           857:        auth_ping = Conn_GetAuthPing(conn);
        !           858:        if (auth_ping) {
        !           859:                LogDebug("AUTH PONG: waiting for token \"%ld\", got \"%s\" ...",
        !           860:                         auth_ping, Req->argv[0]);
        !           861:                if (auth_ping == atol(Req->argv[0])) {
        !           862:                        Conn_SetAuthPing(conn, 0);
        !           863:                        if (Client_Type(Client) == CLIENT_WAITAUTHPING)
        !           864:                                Login_User(Client);
        !           865:                } else
        !           866:                        if (!IRC_WriteStrClient(Client,
        !           867:                                        "NOTICE %s :To connect, type /QUOTE PONG %ld",
        !           868:                                        Client_ID(Client), auth_ping))
        !           869:                                return DISCONNECTED;
        !           870:        }
        !           871: #endif
        !           872:
        !           873:        if (Client_Type(Client) == CLIENT_SERVER && Conn_LastPing(conn) == 0) {
        !           874:                Log(LOG_INFO,
        !           875:                    "Synchronization with \"%s\" done (connection %d): %ld second%s [%ld users, %ld channels].",
        !           876:                    Client_ID(Client), conn,
        !           877:                    (long)(time(NULL) - Conn_GetSignon(conn)),
        !           878:                    time(NULL) - Conn_GetSignon(conn) == 1 ? "" : "s",
        !           879:                    Client_UserCount(), Channel_CountVisible(NULL));
        !           880:        }
        !           881: #ifdef DEBUG
        !           882:        else {
        !           883:                if (Conn_LastPing(conn) > 1)
        !           884:                        LogDebug("Connection %d: received PONG. Lag: %ld seconds.",
        !           885:                                 conn, (long)(time(NULL) - Conn_LastPing(conn)));
        !           886:                else
        !           887:                        LogDebug("Got unexpected PONG on connection %d. Ignored.",
        !           888:                                 conn);
        !           889:        }
        !           890: #endif
        !           891:
        !           892:        /* We got a PONG, so signal that none is pending on this connection. */
        !           893:        Conn_UpdatePing(conn, 1);
        !           894:        return CONNECTED;
        !           895: } /* IRC_PONG */
        !           896:
        !           897: /**
        !           898:  * Change the nickname of a client.
        !           899:  *
        !           900:  * @param Origin The client which caused the nickname change.
        !           901:  * @param Target The client of which the nickname should be changed.
        !           902:  * @param NewNick The new nickname.
        !           903:  */
        !           904: static void
        !           905: Change_Nick(CLIENT *Origin, CLIENT *Target, char *NewNick, bool InformClient)
        !           906: {
        !           907:        if (Client_Conn(Target) > NONE) {
        !           908:                /* Local client */
        !           909:                Log(LOG_INFO,
        !           910:                    "%s \"%s\" changed nick (connection %d): \"%s\" -> \"%s\".",
        !           911:                    Client_TypeText(Target), Client_Mask(Target),
        !           912:                    Client_Conn(Target), Client_ID(Target), NewNick);
        !           913:                Conn_UpdateIdle(Client_Conn(Target));
        !           914:        } else {
        !           915:                /* Remote client */
        !           916:                LogDebug("%s \"%s\" changed nick: \"%s\" -> \"%s\".",
        !           917:                         Client_TypeText(Target),
        !           918:                         Client_Mask(Target), Client_ID(Target), NewNick);
        !           919:        }
        !           920:
        !           921:        /* Inform all servers and users (which have to know) of the new name */
        !           922:        if (InformClient) {
        !           923:                IRC_WriteStrClientPrefix(Target, Target, "NICK :%s", NewNick);
        !           924:                IRC_WriteStrServersPrefix(NULL, Target, "NICK :%s", NewNick);
        !           925:        } else
        !           926:                IRC_WriteStrServersPrefix(Origin, Target, "NICK :%s", NewNick);
        !           927:        IRC_WriteStrRelatedPrefix(Target, Target, false, "NICK :%s", NewNick);
        !           928:
        !           929:        /* Register old nickname for WHOWAS queries */
        !           930:        Client_RegisterWhowas(Target);
        !           931:
        !           932:        /* Save new nickname */
        !           933:        Client_SetID(Target, NewNick);
        !           934: }
        !           935:
        !           936: /* -eof- */

CVSweb