2002-02-28 00:26:21 +01:00
|
|
|
/*
|
|
|
|
* ngIRCd -- The Next Generation IRC Daemon
|
2014-03-17 02:13:15 +01:00
|
|
|
* Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
|
2002-02-28 00:26:21 +01:00
|
|
|
*
|
2002-12-12 13:24:18 +01:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
* Please read the file COPYING, README and AUTHORS for more information.
|
2002-02-28 00:26:21 +01:00
|
|
|
*/
|
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "portab.h"
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2010-12-27 17:14:14 +01:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* Login and logout
|
|
|
|
*/
|
|
|
|
|
2002-02-28 00:26:21 +01:00
|
|
|
#include <assert.h>
|
2012-09-26 23:28:13 +02:00
|
|
|
#include <ctype.h>
|
2002-02-28 00:26:21 +01:00
|
|
|
#include <stdlib.h>
|
2012-04-29 12:36:23 +02:00
|
|
|
#include <string.h>
|
2004-01-17 04:17:49 +01:00
|
|
|
#include <strings.h>
|
2014-03-17 02:28:39 +01:00
|
|
|
#include <time.h>
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2002-12-30 18:15:42 +01:00
|
|
|
#include "conn-func.h"
|
2002-12-30 01:01:42 +01:00
|
|
|
#include "conf.h"
|
2002-05-27 15:09:26 +02:00
|
|
|
#include "channel.h"
|
2002-02-28 00:26:21 +01:00
|
|
|
#include "log.h"
|
2012-03-31 15:38:46 +02:00
|
|
|
#include "login.h"
|
2002-02-28 00:26:21 +01:00
|
|
|
#include "messages.h"
|
2002-05-27 15:09:26 +02:00
|
|
|
#include "parse.h"
|
2003-01-08 23:28:12 +01:00
|
|
|
#include "irc.h"
|
2013-07-30 21:18:42 +02:00
|
|
|
#include "irc-macros.h"
|
2002-05-27 15:09:26 +02:00
|
|
|
#include "irc-write.h"
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2014-03-17 18:02:57 +01:00
|
|
|
#include "irc-login.h"
|
|
|
|
|
2012-11-02 17:50:31 +01:00
|
|
|
static void Change_Nick PARAMS((CLIENT * Origin, CLIENT * Target, char *NewNick,
|
|
|
|
bool InformClient));
|
2012-11-02 14:36:29 +01:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
/**
|
2010-12-29 14:09:46 +01:00
|
|
|
* Handler for the IRC "PASS" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2006-10-01 21:05:00 +02:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2002-05-27 15:09:26 +02:00
|
|
|
IRC_PASS( CLIENT *Client, REQUEST *Req )
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
2006-10-01 21:05:00 +02:00
|
|
|
char *type, *orig_flags;
|
|
|
|
int protohigh, protolow;
|
|
|
|
|
2002-02-28 00:26:21 +01:00
|
|
|
assert( Client != NULL );
|
|
|
|
assert( Req != NULL );
|
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
/* Return an error if this is not a local client */
|
|
|
|
if (Client_Conn(Client) <= NONE)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_UNKNOWNCOMMAND_MSG,
|
2006-10-01 21:05:00 +02:00
|
|
|
Client_ID(Client), Req->command);
|
2008-08-13 01:55:32 +02:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
if (Client_Type(Client) == CLIENT_UNKNOWN && Req->argc == 1) {
|
|
|
|
/* Not yet registered "unknown" connection, PASS with one
|
|
|
|
* argument: either a regular client, service, or server
|
|
|
|
* using the old RFC 1459 section 4.1.1 syntax. */
|
2008-08-14 23:23:04 +02:00
|
|
|
LogDebug("Connection %d: got PASS command (RFC 1459) ...",
|
2006-10-01 21:05:00 +02:00
|
|
|
Client_Conn(Client));
|
|
|
|
} else if ((Client_Type(Client) == CLIENT_UNKNOWN ||
|
|
|
|
Client_Type(Client) == CLIENT_UNKNOWNSERVER) &&
|
|
|
|
(Req->argc == 3 || Req->argc == 4)) {
|
|
|
|
/* Not yet registered "unknown" connection or outgoing server
|
|
|
|
* link, PASS with three or four argument: server using the
|
|
|
|
* RFC 2813 section 4.1.1 syntax. */
|
2008-08-14 23:23:04 +02:00
|
|
|
LogDebug("Connection %d: got PASS command (RFC 2813, new server link) ...",
|
2006-10-01 21:05:00 +02:00
|
|
|
Client_Conn(Client));
|
|
|
|
} else if (Client_Type(Client) == CLIENT_UNKNOWN ||
|
|
|
|
Client_Type(Client) == CLIENT_UNKNOWNSERVER) {
|
|
|
|
/* Unregistered connection, but wrong number of arguments: */
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
|
2006-10-01 21:05:00 +02:00
|
|
|
Client_ID(Client), Req->command);
|
|
|
|
} else {
|
|
|
|
/* Registered connection, PASS command is not allowed! */
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
|
2006-10-01 21:05:00 +02:00
|
|
|
Client_ID(Client));
|
|
|
|
}
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2012-08-23 17:07:08 +02:00
|
|
|
Conn_SetPassword(Client_Conn(Client), Req->argv[0]);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
/* Protocol version */
|
|
|
|
if (Req->argc >= 2 && strlen(Req->argv[1]) >= 4) {
|
|
|
|
int c2, c4;
|
|
|
|
|
|
|
|
c2 = Req->argv[1][2];
|
|
|
|
c4 = Req->argv[1][4];
|
2002-09-03 22:39:54 +02:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
Req->argv[1][4] = '\0';
|
|
|
|
protolow = atoi(&Req->argv[1][2]);
|
|
|
|
Req->argv[1][2] = '\0';
|
|
|
|
protohigh = atoi(Req->argv[1]);
|
2008-08-13 01:55:32 +02:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
Req->argv[1][2] = c2;
|
|
|
|
Req->argv[1][4] = c4;
|
2008-08-14 23:23:04 +02:00
|
|
|
|
|
|
|
Client_SetType(Client, CLIENT_GOTPASS_2813);
|
|
|
|
} else {
|
2006-10-01 21:05:00 +02:00
|
|
|
protohigh = protolow = 0;
|
2008-08-14 23:23:04 +02:00
|
|
|
Client_SetType(Client, CLIENT_GOTPASS);
|
|
|
|
}
|
2006-10-01 21:05:00 +02:00
|
|
|
|
|
|
|
/* Protocol type, see doc/Protocol.txt */
|
|
|
|
if (Req->argc >= 2 && strlen(Req->argv[1]) > 4)
|
|
|
|
type = &Req->argv[1][4];
|
|
|
|
else
|
|
|
|
type = NULL;
|
2008-08-13 01:55:32 +02:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
/* Protocol flags/options */
|
|
|
|
if (Req->argc >= 4)
|
|
|
|
orig_flags = Req->argv[3];
|
|
|
|
else
|
|
|
|
orig_flags = "";
|
2002-09-02 21:04:30 +02:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
/* Implementation, version and IRC+ flags */
|
|
|
|
if (Req->argc >= 3) {
|
|
|
|
char *impl, *ptr, *serverver, *flags;
|
2002-11-27 00:07:24 +01:00
|
|
|
|
2002-09-02 21:04:30 +02:00
|
|
|
impl = Req->argv[2];
|
2006-10-01 21:05:00 +02:00
|
|
|
ptr = strchr(impl, '|');
|
|
|
|
if (ptr)
|
|
|
|
*ptr = '\0';
|
2002-09-02 21:04:30 +02:00
|
|
|
|
2006-10-01 21:05:00 +02:00
|
|
|
if (type && strcmp(type, PROTOIRCPLUS) == 0) {
|
|
|
|
/* The peer seems to be a server which supports the
|
|
|
|
* IRC+ protocol (see doc/Protocol.txt). */
|
2011-01-23 18:38:36 +01:00
|
|
|
serverver = ptr ? ptr + 1 : "?";
|
|
|
|
flags = strchr(ptr ? serverver : impl, ':');
|
2006-10-01 21:05:00 +02:00
|
|
|
if (flags) {
|
2002-09-02 21:04:30 +02:00
|
|
|
*flags = '\0';
|
|
|
|
flags++;
|
2006-10-01 21:05:00 +02:00
|
|
|
} else
|
|
|
|
flags = "";
|
|
|
|
Log(LOG_INFO,
|
2013-02-22 15:15:22 +01:00
|
|
|
"Peer on connection %d announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").",
|
2011-01-16 23:24:41 +01:00
|
|
|
Client_Conn(Client), impl, serverver,
|
|
|
|
protohigh, protolow, flags);
|
2006-10-01 21:05:00 +02:00
|
|
|
} else {
|
|
|
|
/* The peer seems to be a server supporting the
|
|
|
|
* "original" IRC protocol (RFC 2813). */
|
|
|
|
if (strchr(orig_flags, 'Z'))
|
|
|
|
flags = "Z";
|
|
|
|
else
|
|
|
|
flags = "";
|
|
|
|
Log(LOG_INFO,
|
2011-01-16 23:24:41 +01:00
|
|
|
"Peer on connection %d announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").",
|
|
|
|
Client_Conn(Client), impl,
|
|
|
|
protohigh, protolow, flags);
|
2002-09-02 21:04:30 +02:00
|
|
|
}
|
2006-10-01 21:05:00 +02:00
|
|
|
Client_SetFlags(Client, flags);
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
2006-10-01 21:05:00 +02:00
|
|
|
|
|
|
|
return CONNECTED;
|
2002-02-28 00:26:21 +01:00
|
|
|
} /* IRC_PASS */
|
|
|
|
|
2005-05-18 01:24:43 +02:00
|
|
|
/**
|
2010-12-29 14:09:46 +01:00
|
|
|
* Handler for the IRC "NICK" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2005-05-18 01:24:43 +02:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2002-05-27 15:09:26 +02:00
|
|
|
IRC_NICK( CLIENT *Client, REQUEST *Req )
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
|
|
|
CLIENT *intr_c, *target, *c;
|
2015-06-24 16:37:56 +02:00
|
|
|
CHANNEL *chan;
|
2008-08-13 02:00:54 +02:00
|
|
|
char *nick, *user, *hostname, *modes, *info;
|
|
|
|
int token, hops;
|
2002-02-28 00:26:21 +01:00
|
|
|
|
|
|
|
assert( Client != NULL );
|
|
|
|
assert( Req != NULL );
|
|
|
|
|
2005-05-18 01:24:43 +02:00
|
|
|
/* Some IRC clients, for example BitchX, send the NICK and USER
|
|
|
|
* commands in the wrong order ... */
|
2008-08-16 17:33:53 +02:00
|
|
|
if(Client_Type(Client) == CLIENT_UNKNOWN
|
|
|
|
|| Client_Type(Client) == CLIENT_GOTPASS
|
|
|
|
|| Client_Type(Client) == CLIENT_GOTNICK
|
|
|
|
#ifndef STRICT_RFC
|
|
|
|
|| Client_Type(Client) == CLIENT_GOTUSER
|
2002-02-28 00:26:21 +01:00
|
|
|
#endif
|
2008-08-16 17:33:53 +02:00
|
|
|
|| Client_Type(Client) == CLIENT_USER
|
|
|
|
|| Client_Type(Client) == CLIENT_SERVICE
|
|
|
|
|| (Client_Type(Client) == CLIENT_SERVER && Req->argc == 1))
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
2005-05-18 01:24:43 +02:00
|
|
|
/* User registration or change of nickname */
|
2013-07-30 21:18:42 +02:00
|
|
|
_IRC_ARGC_EQ_OR_RETURN_(Client, Req, 1)
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-05-18 01:24:43 +02:00
|
|
|
/* Search "target" client */
|
2013-07-30 21:18:42 +02:00
|
|
|
if (Client_Type(Client) == CLIENT_SERVER) {
|
|
|
|
target = Client_Search(Req->prefix);
|
|
|
|
if (!target)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client,
|
|
|
|
ERR_NOSUCHNICK_MSG,
|
|
|
|
Client_ID(Client),
|
|
|
|
Req->argv[0]);
|
2013-07-30 21:18:42 +02:00
|
|
|
} else {
|
2005-05-18 01:24:43 +02:00
|
|
|
/* Is this a restricted client? */
|
2013-08-06 23:37:21 +02:00
|
|
|
if (Client_HasMode(Client, 'r'))
|
|
|
|
return IRC_WriteErrClient(Client,
|
|
|
|
ERR_RESTRICTED_MSG,
|
|
|
|
Client_ID(Client));
|
2002-02-28 00:26:21 +01:00
|
|
|
target = Client;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef STRICT_RFC
|
2005-05-18 01:24:43 +02:00
|
|
|
/* If the clients tries to change to its own nickname we won't
|
|
|
|
* do anything. This is how the original ircd behaves and some
|
|
|
|
* clients (for example Snak) expect it to be like this.
|
|
|
|
* But I doubt that this is "really the right thing" ... */
|
2013-07-30 21:18:42 +02:00
|
|
|
if (strcmp(Client_ID(target), Req->argv[0]) == 0)
|
2005-05-18 01:24:43 +02:00
|
|
|
return CONNECTED;
|
2002-02-28 00:26:21 +01:00
|
|
|
#endif
|
2002-04-08 18:37:50 +02:00
|
|
|
|
2005-05-18 01:24:43 +02:00
|
|
|
/* Check that the new nickname is available. Special case:
|
|
|
|
* the client only changes from/to upper to lower case. */
|
2013-07-30 21:18:42 +02:00
|
|
|
if (strcasecmp(Client_ID(target), Req->argv[0]) != 0) {
|
|
|
|
if (!Client_CheckNick(target, Req->argv[0]))
|
2005-05-18 01:24:43 +02:00
|
|
|
return CONNECTED;
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
|
2008-08-16 17:33:53 +02:00
|
|
|
if (Client_Type(target) != CLIENT_USER &&
|
|
|
|
Client_Type(target) != CLIENT_SERVICE &&
|
|
|
|
Client_Type(target) != CLIENT_SERVER) {
|
2005-05-18 01:24:43 +02:00
|
|
|
/* New client */
|
2009-01-10 00:44:34 +01:00
|
|
|
LogDebug("Connection %d: got valid NICK command ...",
|
2005-05-18 01:24:43 +02:00
|
|
|
Client_Conn( Client ));
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-05-18 01:24:43 +02:00
|
|
|
/* Register new nickname of this client */
|
2002-02-28 00:26:21 +01:00
|
|
|
Client_SetID( target, Req->argv[0] );
|
|
|
|
|
2011-03-27 19:33:48 +02:00
|
|
|
#ifndef STRICT_RFC
|
|
|
|
if (Conf_AuthPing) {
|
2013-10-16 12:15:27 +02:00
|
|
|
#ifdef HAVE_ARC4RANDOM
|
|
|
|
Conn_SetAuthPing(Client_Conn(Client), arc4random());
|
|
|
|
#else
|
2011-06-26 23:39:20 +02:00
|
|
|
Conn_SetAuthPing(Client_Conn(Client), rand());
|
2013-10-16 12:15:27 +02:00
|
|
|
#endif
|
2015-01-20 22:44:36 +01:00
|
|
|
Conn_WriteStr(Client_Conn(Client), "PING :%ld",
|
2011-03-27 19:33:48 +02:00
|
|
|
Conn_GetAuthPing(Client_Conn(Client)));
|
|
|
|
LogDebug("Connection %d: sent AUTH PING %ld ...",
|
|
|
|
Client_Conn(Client),
|
|
|
|
Conn_GetAuthPing(Client_Conn(Client)));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-05-18 01:24:43 +02:00
|
|
|
/* If we received a valid USER command already then
|
|
|
|
* register the new client! */
|
|
|
|
if( Client_Type( Client ) == CLIENT_GOTUSER )
|
2012-03-31 15:38:46 +02:00
|
|
|
return Login_User( Client );
|
2005-05-18 01:24:43 +02:00
|
|
|
else
|
|
|
|
Client_SetType( Client, CLIENT_GOTNICK );
|
2008-08-16 17:33:53 +02:00
|
|
|
} else {
|
2005-05-18 01:24:43 +02:00
|
|
|
/* Nickname change */
|
2015-06-24 16:37:56 +02:00
|
|
|
|
|
|
|
/* Check that the user isn't on any channels set +N */
|
2015-06-24 21:28:27 +02:00
|
|
|
if(!Client_HasMode(Client, 'o')) {
|
|
|
|
chan = Channel_First();
|
|
|
|
while (chan) {
|
|
|
|
if(Channel_IsMemberOf(chan, Client) &&
|
|
|
|
Channel_HasMode(chan, 'N'))
|
|
|
|
return IRC_WriteErrClient(Client,
|
|
|
|
ERR_NONICKCHANGE_MSG,
|
|
|
|
Client_ID(Client),
|
|
|
|
Channel_Name(chan));
|
|
|
|
chan = Channel_Next(chan);
|
|
|
|
}
|
2015-06-24 16:37:56 +02:00
|
|
|
}
|
|
|
|
|
2012-11-02 17:50:31 +01:00
|
|
|
Change_Nick(Client, target, Req->argv[0],
|
|
|
|
Client_Type(Client) == CLIENT_USER ? true : false);
|
2012-11-02 14:36:29 +01:00
|
|
|
IRC_SetPenalty(target, 2);
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return CONNECTED;
|
2008-08-13 02:00:54 +02:00
|
|
|
} else if(Client_Type(Client) == CLIENT_SERVER ||
|
|
|
|
Client_Type(Client) == CLIENT_SERVICE) {
|
|
|
|
/* Server or service introduces new client */
|
|
|
|
|
|
|
|
/* Bad number of parameters? */
|
2013-11-06 19:28:09 +01:00
|
|
|
if (Req->argc != 2 && Req->argc != 7)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
|
2008-08-13 02:00:54 +02:00
|
|
|
Client_ID(Client), Req->command);
|
|
|
|
|
|
|
|
if (Req->argc >= 7) {
|
2008-08-13 16:52:35 +02:00
|
|
|
/* RFC 2813 compatible syntax */
|
2008-08-13 02:00:54 +02:00
|
|
|
nick = Req->argv[0];
|
|
|
|
hops = atoi(Req->argv[1]);
|
|
|
|
user = Req->argv[2];
|
|
|
|
hostname = Req->argv[3];
|
|
|
|
token = atoi(Req->argv[4]);
|
|
|
|
modes = Req->argv[5] + 1;
|
|
|
|
info = Req->argv[6];
|
|
|
|
} else {
|
2008-08-13 16:52:35 +02:00
|
|
|
/* RFC 1459 compatible syntax */
|
2008-08-13 02:00:54 +02:00
|
|
|
nick = Req->argv[0];
|
|
|
|
hops = 1;
|
|
|
|
user = Req->argv[0];
|
|
|
|
hostname = Client_ID(Client);
|
|
|
|
token = atoi(Req->argv[1]);
|
|
|
|
modes = "";
|
|
|
|
info = Req->argv[0];
|
|
|
|
}
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2008-08-13 02:00:54 +02:00
|
|
|
c = Client_Search(nick);
|
|
|
|
if(c) {
|
2009-04-21 08:40:10 +02:00
|
|
|
/*
|
|
|
|
* the new nick is already present on this server:
|
|
|
|
* the new and the old one have to be disconnected now.
|
|
|
|
*/
|
2013-10-01 12:13:17 +02:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Server %s introduces already registered nick \"%s\"!",
|
|
|
|
Client_ID(Client), Req->argv[0]);
|
|
|
|
return IRC_KillClient(Client, NULL, Req->argv[0],
|
|
|
|
"Nick collision");
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
|
2009-04-21 08:40:10 +02:00
|
|
|
/* Find the Server this client is connected to */
|
2008-08-13 02:00:54 +02:00
|
|
|
intr_c = Client_GetFromToken(Client, token);
|
2013-07-30 21:18:42 +02:00
|
|
|
if (!intr_c) {
|
2013-10-01 12:13:17 +02:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Server %s introduces nick \"%s\" on unknown server!?",
|
|
|
|
Client_ID(Client), Req->argv[0]);
|
|
|
|
return IRC_KillClient(Client, NULL, Req->argv[0],
|
|
|
|
"Unknown server");
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
|
2008-08-13 02:00:54 +02:00
|
|
|
c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname,
|
|
|
|
token, modes, info, true);
|
2013-07-30 21:18:42 +02:00
|
|
|
if (!c) {
|
|
|
|
/* Out of memory, we need to disconnect client to keep
|
|
|
|
* network state consistent! */
|
|
|
|
Log(LOG_ALERT,
|
|
|
|
"Can't create client structure! (on connection %d)",
|
|
|
|
Client_Conn(Client));
|
2013-10-01 12:13:17 +02:00
|
|
|
return IRC_KillClient(Client, NULL, Req->argv[0],
|
|
|
|
"Server error");
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
|
2008-08-13 21:55:22 +02:00
|
|
|
/* RFC 2813: client is now fully registered, inform all the
|
|
|
|
* other servers about the new user.
|
|
|
|
* RFC 1459: announce the new client only after receiving the
|
|
|
|
* USER command, first we need more information! */
|
2008-08-16 01:24:35 +02:00
|
|
|
if (Req->argc < 7) {
|
2010-05-14 19:43:08 +02:00
|
|
|
LogDebug("Client \"%s\" is being registered (RFC 1459) ...",
|
2008-08-13 21:55:22 +02:00
|
|
|
Client_Mask(c));
|
|
|
|
Client_SetType(c, CLIENT_GOTNICK);
|
2008-08-16 01:24:35 +02:00
|
|
|
} else
|
2012-03-31 15:24:30 +02:00
|
|
|
Client_Introduce(Client, c, CLIENT_USER);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
|
|
|
return CONNECTED;
|
|
|
|
}
|
2013-07-30 21:18:42 +02:00
|
|
|
else
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
|
2013-07-30 21:18:42 +02:00
|
|
|
Client_ID(Client));
|
2002-02-28 00:26:21 +01:00
|
|
|
} /* IRC_NICK */
|
|
|
|
|
2012-11-02 17:50:31 +01:00
|
|
|
/**
|
|
|
|
* Handler for the IRC "SVSNICK" command.
|
|
|
|
*
|
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
|
|
|
*/
|
|
|
|
GLOBAL bool
|
|
|
|
IRC_SVSNICK(CLIENT *Client, REQUEST *Req)
|
|
|
|
{
|
|
|
|
CLIENT *from, *target;
|
|
|
|
|
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Req != NULL);
|
|
|
|
|
|
|
|
/* Search the originator */
|
|
|
|
from = Client_Search(Req->prefix);
|
|
|
|
if (!from)
|
|
|
|
from = Client;
|
|
|
|
|
|
|
|
/* Search the target */
|
|
|
|
target = Client_Search(Req->argv[0]);
|
2013-11-06 19:28:09 +01:00
|
|
|
if (!target || Client_Type(target) != CLIENT_USER)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
|
2012-11-02 17:50:31 +01:00
|
|
|
Client_ID(Client), Req->argv[0]);
|
|
|
|
|
|
|
|
if (Client_Conn(target) <= NONE) {
|
|
|
|
/* We have to forward the message to the server handling
|
|
|
|
* this user; this is required to make sure all servers
|
|
|
|
* in the network do follow the nick name change! */
|
|
|
|
return IRC_WriteStrClientPrefix(Client_NextHop(target), from,
|
|
|
|
"SVSNICK %s %s",
|
|
|
|
Req->argv[0], Req->argv[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure that the new nickname is valid */
|
|
|
|
if (!Client_CheckNick(from, Req->argv[1]))
|
|
|
|
return CONNECTED;
|
|
|
|
|
|
|
|
Change_Nick(from, target, Req->argv[1], true);
|
|
|
|
return CONNECTED;
|
|
|
|
}
|
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
/**
|
2010-12-29 14:09:46 +01:00
|
|
|
* Handler for the IRC "USER" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2008-08-13 02:24:06 +02:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2008-08-13 02:24:06 +02:00
|
|
|
IRC_USER(CLIENT * Client, REQUEST * Req)
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
2008-08-13 02:24:06 +02:00
|
|
|
CLIENT *c;
|
2005-03-19 19:43:48 +01:00
|
|
|
char *ptr;
|
2003-12-27 14:01:12 +01:00
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Req != NULL);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
if (Client_Type(Client) == CLIENT_GOTNICK ||
|
2002-02-28 00:26:21 +01:00
|
|
|
#ifndef STRICT_RFC
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_Type(Client) == CLIENT_UNKNOWN ||
|
2002-02-28 00:26:21 +01:00
|
|
|
#endif
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_Type(Client) == CLIENT_GOTPASS)
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
2008-08-13 02:24:06 +02:00
|
|
|
/* New connection */
|
2013-07-30 21:18:42 +02:00
|
|
|
_IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4)
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2012-09-14 17:56:38 +02:00
|
|
|
/* User name: only alphanumeric characters and limited
|
|
|
|
punctuation is allowed.*/
|
2012-06-01 23:57:51 +02:00
|
|
|
ptr = Req->argv[0];
|
|
|
|
while (*ptr) {
|
2012-11-12 22:39:57 +01:00
|
|
|
if (!isalnum((int)*ptr) &&
|
2013-02-11 13:57:54 +01:00
|
|
|
*ptr != '+' && *ptr != '-' && *ptr != '@' &&
|
2012-09-26 23:28:13 +02:00
|
|
|
*ptr != '.' && *ptr != '_') {
|
2012-06-01 23:57:51 +02:00
|
|
|
Conn_Close(Client_Conn(Client), NULL,
|
|
|
|
"Invalid user name", true);
|
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
2013-02-11 13:57:54 +01:00
|
|
|
/* Save the received username for authentication, and use
|
|
|
|
* it up to the first '@' as default user name (like ircd2.11,
|
|
|
|
* bahamut, ircd-seven, ...), prefixed with '~', if needed: */
|
|
|
|
Client_SetOrigUser(Client, Req->argv[0]);
|
|
|
|
ptr = strchr(Req->argv[0], '@');
|
|
|
|
if (ptr)
|
|
|
|
*ptr = '\0';
|
2003-12-27 14:01:12 +01:00
|
|
|
#ifdef IDENTAUTH
|
2008-08-13 02:24:06 +02:00
|
|
|
ptr = Client_User(Client);
|
|
|
|
if (!ptr || !*ptr || *ptr == '~')
|
|
|
|
Client_SetUser(Client, Req->argv[0], false);
|
2004-02-04 20:56:04 +01:00
|
|
|
#else
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_SetUser(Client, Req->argv[0], false);
|
2004-02-04 20:56:04 +01:00
|
|
|
#endif
|
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
/* "Real name" or user info text: Don't set it to the empty
|
|
|
|
* string, the original ircd can't deal with such "real names"
|
|
|
|
* (e. g. "USER user * * :") ... */
|
|
|
|
if (*Req->argv[3])
|
|
|
|
Client_SetInfo(Client, Req->argv[3]);
|
|
|
|
else
|
|
|
|
Client_SetInfo(Client, "-");
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
LogDebug("Connection %d: got valid USER command ...",
|
|
|
|
Client_Conn(Client));
|
|
|
|
if (Client_Type(Client) == CLIENT_GOTNICK)
|
2012-03-31 15:38:46 +02:00
|
|
|
return Login_User(Client);
|
2008-08-13 02:24:06 +02:00
|
|
|
else
|
|
|
|
Client_SetType(Client, CLIENT_GOTUSER);
|
2002-02-28 00:26:21 +01:00
|
|
|
return CONNECTED;
|
2008-08-13 02:24:06 +02:00
|
|
|
|
|
|
|
} else if (Client_Type(Client) == CLIENT_SERVER ||
|
|
|
|
Client_Type(Client) == CLIENT_SERVICE) {
|
|
|
|
/* Server/service updating an user */
|
2013-07-30 21:18:42 +02:00
|
|
|
_IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4)
|
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
c = Client_Search(Req->prefix);
|
|
|
|
if (!c)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_ID(Client),
|
|
|
|
Req->prefix);
|
|
|
|
|
|
|
|
Client_SetUser(c, Req->argv[0], true);
|
2010-07-11 17:03:43 +02:00
|
|
|
Client_SetOrigUser(c, Req->argv[0]);
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_SetHostname(c, Req->argv[1]);
|
|
|
|
Client_SetInfo(c, Req->argv[3]);
|
|
|
|
|
|
|
|
LogDebug("Connection %d: got valid USER command for \"%s\".",
|
|
|
|
Client_Conn(Client), Client_Mask(c));
|
2008-08-13 21:55:22 +02:00
|
|
|
|
2008-08-16 01:24:35 +02:00
|
|
|
/* RFC 1459 style user registration?
|
|
|
|
* Introduce client to network: */
|
|
|
|
if (Client_Type(c) == CLIENT_GOTNICK)
|
2012-03-31 15:24:30 +02:00
|
|
|
Client_Introduce(Client, c, CLIENT_USER);
|
2008-08-13 21:55:22 +02:00
|
|
|
|
2008-08-13 02:24:06 +02:00
|
|
|
return CONNECTED;
|
|
|
|
} else if (Client_Type(Client) == CLIENT_USER) {
|
|
|
|
/* Already registered connection */
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_ID(Client));
|
|
|
|
} else {
|
|
|
|
/* Unexpected/invalid connection state? */
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOTREGISTERED_MSG,
|
2008-08-13 02:24:06 +02:00
|
|
|
Client_ID(Client));
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
} /* IRC_USER */
|
|
|
|
|
2008-05-05 18:06:43 +02:00
|
|
|
/**
|
2010-12-29 14:09:46 +01:00
|
|
|
* Handler for the IRC "SERVICE" command.
|
|
|
|
*
|
2008-08-17 17:29:41 +02:00
|
|
|
* At the moment ngIRCd doesn't support directly linked services, so this
|
|
|
|
* function returns ERR_ERRONEUSNICKNAME when the SERVICE command has not been
|
|
|
|
* received from a peer server.
|
2010-12-29 14:09:46 +01:00
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2008-05-05 18:06:43 +02:00
|
|
|
*/
|
|
|
|
GLOBAL bool
|
|
|
|
IRC_SERVICE(CLIENT *Client, REQUEST *Req)
|
|
|
|
{
|
2008-08-17 17:29:41 +02:00
|
|
|
CLIENT *c, *intr_c;
|
|
|
|
char *nick, *user, *host, *info, *modes, *ptr;
|
|
|
|
int token, hops;
|
|
|
|
|
2008-05-05 18:06:43 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Req != NULL);
|
|
|
|
|
2008-08-17 17:29:41 +02:00
|
|
|
if (Client_Type(Client) != CLIENT_GOTPASS &&
|
2013-08-06 23:37:21 +02:00
|
|
|
Client_Type(Client) != CLIENT_SERVER)
|
|
|
|
return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
|
2008-05-05 18:06:43 +02:00
|
|
|
Client_ID(Client));
|
|
|
|
|
2008-08-17 17:29:41 +02:00
|
|
|
if (Client_Type(Client) != CLIENT_SERVER)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
|
2008-05-05 18:06:43 +02:00
|
|
|
Client_ID(Client), Req->argv[0]);
|
2008-08-17 17:29:41 +02:00
|
|
|
|
|
|
|
nick = Req->argv[0];
|
|
|
|
user = NULL; host = NULL;
|
|
|
|
token = atoi(Req->argv[1]);
|
|
|
|
hops = atoi(Req->argv[4]);
|
|
|
|
info = Req->argv[5];
|
|
|
|
|
2012-11-02 14:30:19 +01:00
|
|
|
/* Validate service name ("nickname") */
|
2008-08-17 17:29:41 +02:00
|
|
|
c = Client_Search(nick);
|
|
|
|
if(c) {
|
2013-08-04 13:33:10 +02:00
|
|
|
/* Nickname collision: disconnect (KILL) both clients! */
|
2013-10-01 12:13:17 +02:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Server %s introduces already registered service \"%s\"!",
|
2008-08-17 17:29:41 +02:00
|
|
|
Client_ID(Client), nick);
|
2013-10-01 12:13:17 +02:00
|
|
|
return IRC_KillClient(Client, NULL, nick, "Nick collision");
|
2008-08-17 17:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the server to which the service is connected */
|
|
|
|
intr_c = Client_GetFromToken(Client, token);
|
|
|
|
if (! intr_c) {
|
2013-10-01 12:13:17 +02:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Server %s introduces service \"%s\" on unknown server!?",
|
2008-08-17 17:29:41 +02:00
|
|
|
Client_ID(Client), nick);
|
2013-10-01 12:13:17 +02:00
|
|
|
return IRC_KillClient(Client, NULL, nick, "Unknown server");
|
2008-08-17 17:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get user and host name */
|
|
|
|
ptr = strchr(nick, '@');
|
|
|
|
if (ptr) {
|
|
|
|
*ptr = '\0';
|
|
|
|
host = ++ptr;
|
|
|
|
}
|
|
|
|
if (!host)
|
|
|
|
host = Client_Hostname(intr_c);
|
|
|
|
ptr = strchr(nick, '!');
|
|
|
|
if (ptr) {
|
|
|
|
*ptr = '\0';
|
|
|
|
user = ++ptr;
|
|
|
|
}
|
|
|
|
if (!user)
|
|
|
|
user = nick;
|
|
|
|
|
|
|
|
/* According to RFC 2812/2813 parameter 4 <type> "is currently reserved
|
|
|
|
* for future usage"; but we use it to transfer the modes and check
|
|
|
|
* that the first character is a '+' sign and ignore it otherwise. */
|
|
|
|
modes = (Req->argv[3][0] == '+') ? ++Req->argv[3] : "";
|
|
|
|
|
|
|
|
c = Client_NewRemoteUser(intr_c, nick, hops, user, host,
|
|
|
|
token, modes, info, true);
|
|
|
|
if (! c) {
|
|
|
|
/* Couldn't create client structure, so KILL the service to
|
|
|
|
* keep network status consistent ... */
|
2013-10-01 12:13:17 +02:00
|
|
|
Log(LOG_ALERT,
|
|
|
|
"Can't create client structure! (on connection %d)",
|
2008-08-17 17:29:41 +02:00
|
|
|
Client_Conn(Client));
|
2013-10-01 12:13:17 +02:00
|
|
|
return IRC_KillClient(Client, NULL, nick, "Server error");
|
2008-08-17 17:29:41 +02:00
|
|
|
}
|
|
|
|
|
2012-03-31 15:24:30 +02:00
|
|
|
Client_Introduce(Client, c, CLIENT_SERVICE);
|
2008-08-17 17:29:41 +02:00
|
|
|
return CONNECTED;
|
2008-05-05 18:06:43 +02:00
|
|
|
} /* IRC_SERVICE */
|
|
|
|
|
2010-02-11 00:01:53 +01:00
|
|
|
/**
|
2010-12-29 14:10:18 +01:00
|
|
|
* Handler for the IRC "WEBIRC" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2010-02-11 00:01:53 +01:00
|
|
|
*/
|
|
|
|
GLOBAL bool
|
|
|
|
IRC_WEBIRC(CLIENT *Client, REQUEST *Req)
|
|
|
|
{
|
|
|
|
if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_PASSWDMISMATCH_MSG,
|
2010-02-11 00:01:53 +01:00
|
|
|
Client_ID(Client));
|
|
|
|
|
|
|
|
LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s",
|
|
|
|
Client_Conn(Client), Req->argv[1], Req->argv[2], Req->argv[3]);
|
|
|
|
|
|
|
|
Client_SetUser(Client, Req->argv[1], true);
|
2010-07-11 17:03:43 +02:00
|
|
|
Client_SetOrigUser(Client, Req->argv[1]);
|
2013-12-27 22:34:47 +01:00
|
|
|
if (Conf_DNS)
|
|
|
|
Client_SetHostname(Client, Req->argv[2]);
|
|
|
|
else
|
|
|
|
Client_SetHostname(Client, Req->argv[3]);
|
2013-08-26 22:54:00 +02:00
|
|
|
Client_SetIPAText(Client, Req->argv[3]);
|
|
|
|
|
2010-02-11 00:01:53 +01:00
|
|
|
return CONNECTED;
|
|
|
|
} /* IRC_WEBIRC */
|
|
|
|
|
2010-12-29 14:09:46 +01:00
|
|
|
/**
|
|
|
|
* Handler for the IRC "QUIT" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2010-12-29 14:09:46 +01:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2002-05-27 15:09:26 +02:00
|
|
|
IRC_QUIT( CLIENT *Client, REQUEST *Req )
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
|
|
|
CLIENT *target;
|
2013-10-17 23:10:53 +02:00
|
|
|
char quitmsg[COMMAND_LEN];
|
2008-08-13 01:55:32 +02:00
|
|
|
|
2011-08-02 00:56:49 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Req != NULL);
|
2008-08-13 01:55:32 +02:00
|
|
|
|
2005-06-04 14:32:09 +02:00
|
|
|
if (Req->argc == 1)
|
|
|
|
strlcpy(quitmsg, Req->argv[0], sizeof quitmsg);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2011-08-02 00:56:49 +02:00
|
|
|
if (Client_Type(Client) == CLIENT_SERVER) {
|
2002-02-28 00:26:21 +01:00
|
|
|
/* Server */
|
2011-08-02 00:56:49 +02:00
|
|
|
target = Client_Search(Req->prefix);
|
|
|
|
if (!target) {
|
|
|
|
Log(LOG_WARNING,
|
|
|
|
"Got QUIT from %s for unknown client!?",
|
|
|
|
Client_ID(Client));
|
2002-02-28 00:26:21 +01:00
|
|
|
return CONNECTED;
|
|
|
|
}
|
|
|
|
|
2011-08-02 00:56:49 +02:00
|
|
|
if (target != Client) {
|
2013-01-26 16:52:41 +01:00
|
|
|
Client_Destroy(target, "Got QUIT command",
|
2011-08-02 00:56:49 +02:00
|
|
|
Req->argc == 1 ? quitmsg : NULL, true);
|
|
|
|
return CONNECTED;
|
|
|
|
} else {
|
2013-01-26 16:52:41 +01:00
|
|
|
Conn_Close(Client_Conn(Client), "Got QUIT command",
|
2011-08-02 00:56:49 +02:00
|
|
|
Req->argc == 1 ? quitmsg : NULL, true);
|
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
|
|
|
} else {
|
2005-06-04 14:32:09 +02:00
|
|
|
if (Req->argc == 1 && quitmsg[0] != '\"') {
|
|
|
|
/* " " to avoid confusion */
|
|
|
|
strlcpy(quitmsg, "\"", sizeof quitmsg);
|
|
|
|
strlcat(quitmsg, Req->argv[0], sizeof quitmsg-1);
|
|
|
|
strlcat(quitmsg, "\"", sizeof quitmsg );
|
|
|
|
}
|
2002-04-14 16:02:35 +02:00
|
|
|
|
2009-04-21 08:40:10 +02:00
|
|
|
/* User, Service, or not yet registered */
|
2013-01-26 16:52:41 +01:00
|
|
|
Conn_Close(Client_Conn(Client), "Got QUIT command",
|
2011-08-02 00:56:49 +02:00
|
|
|
Req->argc == 1 ? quitmsg : NULL, true);
|
2008-08-13 01:55:32 +02:00
|
|
|
|
2002-04-14 16:02:35 +02:00
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
2002-02-28 00:26:21 +01:00
|
|
|
} /* IRC_QUIT */
|
|
|
|
|
2011-03-16 23:58:39 +01:00
|
|
|
#ifndef STRICT_RFC
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for HTTP command, e.g. GET and POST
|
|
|
|
*
|
|
|
|
* We handle these commands here to avoid the quite long timeout when
|
|
|
|
* some user tries to access this IRC daemon using an web browser ...
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2011-03-16 23:58:39 +01:00
|
|
|
*/
|
2011-03-16 23:56:27 +01:00
|
|
|
GLOBAL bool
|
|
|
|
IRC_QUIT_HTTP( CLIENT *Client, REQUEST *Req )
|
|
|
|
{
|
2011-03-16 23:58:01 +01:00
|
|
|
Req->argc = 1;
|
|
|
|
Req->argv[0] = "Oops, HTTP request received? This is IRC!";
|
2011-03-16 23:56:27 +01:00
|
|
|
return IRC_QUIT(Client, Req);
|
|
|
|
} /* IRC_QUIT_HTTP */
|
|
|
|
|
2011-03-16 23:58:39 +01:00
|
|
|
#endif
|
|
|
|
|
2010-12-29 14:09:46 +01:00
|
|
|
/**
|
|
|
|
* Handler for the IRC "PING" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2010-12-29 14:09:46 +01:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2005-08-28 13:40:13 +02:00
|
|
|
IRC_PING(CLIENT *Client, REQUEST *Req)
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
|
|
|
CLIENT *target, *from;
|
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Req != NULL);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
if (Req->argc < 1)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG,
|
2005-08-28 13:40:13 +02:00
|
|
|
Client_ID(Client));
|
2002-03-10 23:40:22 +01:00
|
|
|
#ifdef STRICT_RFC
|
2005-08-28 13:40:13 +02:00
|
|
|
/* Don't ignore additional arguments when in "strict" mode */
|
2013-07-30 21:18:42 +02:00
|
|
|
_IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
|
2002-03-10 23:40:22 +01:00
|
|
|
#endif
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
if (Req->argc > 1) {
|
|
|
|
/* A target has been specified ... */
|
|
|
|
target = Client_Search(Req->argv[1]);
|
|
|
|
|
|
|
|
if (!target || Client_Type(target) != CLIENT_SERVER)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
|
2005-08-28 13:40:13 +02:00
|
|
|
Client_ID(Client), Req->argv[1]);
|
|
|
|
|
|
|
|
if (target != Client_ThisServer()) {
|
|
|
|
/* Ok, we have to forward the PING */
|
|
|
|
if (Client_Type(Client) == CLIENT_SERVER)
|
|
|
|
from = Client_Search(Req->prefix);
|
2005-08-27 20:39:56 +02:00
|
|
|
else
|
|
|
|
from = Client;
|
|
|
|
if (!from)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client,
|
2005-08-28 13:40:13 +02:00
|
|
|
ERR_NOSUCHSERVER_MSG,
|
|
|
|
Client_ID(Client), Req->prefix);
|
|
|
|
|
2005-08-27 20:39:56 +02:00
|
|
|
return IRC_WriteStrClientPrefix(target, from,
|
2005-08-28 13:40:13 +02:00
|
|
|
"PING %s :%s", Req->argv[0],
|
|
|
|
Req->argv[1] );
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
if (Client_Type(Client) == CLIENT_SERVER) {
|
|
|
|
if (Req->prefix)
|
|
|
|
from = Client_Search(Req->prefix);
|
|
|
|
else
|
|
|
|
from = Client;
|
|
|
|
} else
|
|
|
|
from = Client_ThisServer();
|
|
|
|
if (!from)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
|
2005-08-28 13:40:13 +02:00
|
|
|
Client_ID(Client), Req->prefix);
|
|
|
|
|
|
|
|
Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...",
|
|
|
|
Client_Conn(Client));
|
|
|
|
|
2005-08-27 20:39:56 +02:00
|
|
|
#ifdef STRICT_RFC
|
2005-08-28 13:40:13 +02:00
|
|
|
return IRC_WriteStrClient(Client, "PONG %s :%s",
|
|
|
|
Client_ID(from), Client_ID(Client));
|
2005-08-27 20:39:56 +02:00
|
|
|
#else
|
2005-08-28 13:40:13 +02:00
|
|
|
/* Some clients depend on the argument being returned in the PONG
|
2008-04-20 23:10:22 +02:00
|
|
|
* reply (not mentioned in any RFC, though) */
|
2005-08-28 13:40:13 +02:00
|
|
|
return IRC_WriteStrClient(Client, "PONG %s :%s",
|
|
|
|
Client_ID(from), Req->argv[0]);
|
|
|
|
#endif
|
2002-02-28 00:26:21 +01:00
|
|
|
} /* IRC_PING */
|
|
|
|
|
2010-12-29 14:09:46 +01:00
|
|
|
/**
|
|
|
|
* Handler for the IRC "PONG" command.
|
|
|
|
*
|
2013-07-30 21:18:42 +02:00
|
|
|
* @param Client The client from which this command has been received.
|
|
|
|
* @param Req Request structure with prefix and all parameters.
|
|
|
|
* @return CONNECTED or DISCONNECTED.
|
2010-12-29 14:09:46 +01:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2005-08-28 13:40:13 +02:00
|
|
|
IRC_PONG(CLIENT *Client, REQUEST *Req)
|
2002-02-28 00:26:21 +01:00
|
|
|
{
|
|
|
|
CLIENT *target, *from;
|
2011-03-27 19:33:48 +02:00
|
|
|
CONN_ID conn;
|
|
|
|
#ifndef STRICT_RFC
|
|
|
|
long auth_ping;
|
|
|
|
#endif
|
2005-08-28 13:40:13 +02:00
|
|
|
char *s;
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Req != NULL);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
/* Wrong number of arguments? */
|
2011-03-27 19:33:48 +02:00
|
|
|
if (Req->argc < 1) {
|
|
|
|
if (Client_Type(Client) == CLIENT_USER)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG,
|
2011-03-27 19:33:48 +02:00
|
|
|
Client_ID(Client));
|
|
|
|
else
|
|
|
|
return CONNECTED;
|
|
|
|
}
|
2013-07-30 21:18:42 +02:00
|
|
|
if (Client_Type(Client) == CLIENT_USER) {
|
|
|
|
_IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
|
2011-03-27 19:33:48 +02:00
|
|
|
}
|
2005-08-28 13:40:13 +02:00
|
|
|
|
|
|
|
/* Forward? */
|
|
|
|
if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) {
|
|
|
|
target = Client_Search(Req->argv[0]);
|
|
|
|
if (!target)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
|
2005-08-28 13:40:13 +02:00
|
|
|
Client_ID(Client), Req->argv[0]);
|
|
|
|
|
2005-09-01 12:51:24 +02:00
|
|
|
from = Client_Search(Req->prefix);
|
|
|
|
|
|
|
|
if (target != Client_ThisServer() && target != from) {
|
2005-08-28 13:40:13 +02:00
|
|
|
/* Ok, we have to forward the message. */
|
|
|
|
if (!from)
|
2013-08-06 23:37:21 +02:00
|
|
|
return IRC_WriteErrClient(Client,
|
2005-08-28 13:40:13 +02:00
|
|
|
ERR_NOSUCHSERVER_MSG,
|
|
|
|
Client_ID(Client), Req->prefix);
|
2002-02-28 00:26:21 +01:00
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
if (Client_Type(Client_NextHop(target)) != CLIENT_SERVER)
|
|
|
|
s = Client_ID(from);
|
|
|
|
else
|
|
|
|
s = Req->argv[0];
|
|
|
|
return IRC_WriteStrClientPrefix(target, from,
|
|
|
|
"PONG %s :%s", s, Req->argv[1]);
|
2002-02-28 00:26:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-28 13:40:13 +02:00
|
|
|
/* The connection timestamp has already been updated when the data has
|
|
|
|
* been read from so socket, so we don't need to update it here. */
|
2011-03-27 19:33:48 +02:00
|
|
|
|
|
|
|
conn = Client_Conn(Client);
|
|
|
|
|
|
|
|
#ifndef STRICT_RFC
|
|
|
|
/* Check authentication PING-PONG ... */
|
|
|
|
auth_ping = Conn_GetAuthPing(conn);
|
|
|
|
if (auth_ping) {
|
|
|
|
LogDebug("AUTH PONG: waiting for token \"%ld\", got \"%s\" ...",
|
|
|
|
auth_ping, Req->argv[0]);
|
2015-01-20 22:49:23 +01:00
|
|
|
if (auth_ping == atol(Req->argv[0])) {
|
2011-03-27 19:33:48 +02:00
|
|
|
Conn_SetAuthPing(conn, 0);
|
|
|
|
if (Client_Type(Client) == CLIENT_WAITAUTHPING)
|
2012-03-31 15:38:46 +02:00
|
|
|
Login_User(Client);
|
2011-03-27 19:33:48 +02:00
|
|
|
} else
|
|
|
|
if (!IRC_WriteStrClient(Client,
|
2015-01-20 22:50:13 +01:00
|
|
|
"NOTICE %s :To connect, type /QUOTE PONG %ld",
|
|
|
|
Client_ID(Client), auth_ping))
|
2011-03-27 19:33:48 +02:00
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-01-24 02:46:12 +01:00
|
|
|
if (Client_Type(Client) == CLIENT_SERVER && Conn_LastPing(conn) == 0) {
|
|
|
|
Log(LOG_INFO,
|
2013-01-26 16:52:41 +01:00
|
|
|
"Synchronization with \"%s\" done (connection %d): %ld second%s [%ld users, %ld channels].",
|
2012-01-24 02:46:12 +01:00
|
|
|
Client_ID(Client), conn, time(NULL) - Conn_GetSignon(conn),
|
2013-01-26 16:52:41 +01:00
|
|
|
time(NULL) - Conn_GetSignon(conn) == 1 ? "" : "s",
|
2012-01-24 02:46:12 +01:00
|
|
|
Client_UserCount(), Channel_CountVisible(NULL));
|
|
|
|
Conn_UpdatePing(conn);
|
|
|
|
} else
|
|
|
|
LogDebug("Connection %d: received PONG. Lag: %ld seconds.",
|
|
|
|
conn, time(NULL) - Conn_LastPing(conn));
|
|
|
|
|
2002-02-28 00:26:21 +01:00
|
|
|
return CONNECTED;
|
|
|
|
} /* IRC_PONG */
|
|
|
|
|
2012-11-02 14:36:29 +01:00
|
|
|
/**
|
|
|
|
* Change the nickname of a client.
|
|
|
|
*
|
|
|
|
* @param Origin The client which caused the nickname change.
|
|
|
|
* @param Target The client of which the nickname should be changed.
|
|
|
|
* @param NewNick The new nickname.
|
|
|
|
*/
|
|
|
|
static void
|
2012-11-02 17:50:31 +01:00
|
|
|
Change_Nick(CLIENT *Origin, CLIENT *Target, char *NewNick, bool InformClient)
|
2012-11-02 14:36:29 +01:00
|
|
|
{
|
|
|
|
if (Client_Conn(Target) > NONE) {
|
|
|
|
/* Local client */
|
|
|
|
Log(LOG_INFO,
|
|
|
|
"%s \"%s\" changed nick (connection %d): \"%s\" -> \"%s\".",
|
|
|
|
Client_TypeText(Target), Client_Mask(Target),
|
|
|
|
Client_Conn(Target), Client_ID(Target), NewNick);
|
|
|
|
Conn_UpdateIdle(Client_Conn(Target));
|
|
|
|
} else {
|
|
|
|
/* Remote client */
|
|
|
|
LogDebug("%s \"%s\" changed nick: \"%s\" -> \"%s\".",
|
|
|
|
Client_TypeText(Target),
|
|
|
|
Client_Mask(Target), Client_ID(Target), NewNick);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Inform all servers and users (which have to know) of the new name */
|
2012-11-02 17:50:31 +01:00
|
|
|
if (InformClient) {
|
2012-11-04 18:01:49 +01:00
|
|
|
IRC_WriteStrClientPrefix(Target, Target, "NICK :%s", NewNick);
|
2012-11-02 17:50:31 +01:00
|
|
|
IRC_WriteStrServersPrefix(NULL, Target, "NICK :%s", NewNick);
|
|
|
|
} else
|
|
|
|
IRC_WriteStrServersPrefix(Origin, Target, "NICK :%s", NewNick);
|
2012-11-02 14:36:29 +01:00
|
|
|
IRC_WriteStrRelatedPrefix(Target, Target, false, "NICK :%s", NewNick);
|
|
|
|
|
2012-11-02 17:50:31 +01:00
|
|
|
/* Register old nickname for WHOWAS queries */
|
|
|
|
Client_RegisterWhowas(Target);
|
2012-11-02 14:36:29 +01:00
|
|
|
|
|
|
|
/* Save new nickname */
|
|
|
|
Client_SetID(Target, NewNick);
|
|
|
|
}
|
|
|
|
|
2002-02-28 00:26:21 +01:00
|
|
|
/* -eof- */
|