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