[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

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